Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #242 - Add support to write Kaspresso-like tests that run on the JVM with Robolectric #243

Closed
wants to merge 6 commits into from

Conversation

sergio-sastre
Copy link
Contributor

No description provided.

@CLAassistant
Copy link

CLAassistant commented May 19, 2021

CLA assistant check
All committers have signed the CLA.

@sergio-sastre sergio-sastre marked this pull request as draft May 22, 2021 14:31
@sergio-sastre sergio-sastre marked this pull request as ready for review May 22, 2021 14:32
@sergio-sastre sergio-sastre marked this pull request as draft May 22, 2021 14:32
@sergio-sastre
Copy link
Contributor Author

@matzuk

@sergio-sastre sergio-sastre marked this pull request as ready for review May 22, 2021 14:45
@RuslanMingaliev
Copy link
Collaborator

Wow, great job! Thank you for contribution.
We'll take a closer look in the coming days

@matzuk
Copy link
Member

matzuk commented May 24, 2021

Hi @sergio-sastre!
Thanks a lot for your job! We really appreciate such kind of help!
We got the main idea and concerns about using Robolectric in Kaspresso. Also, your code has highlighted all necessary changes.

So, my thoughts:

  1. I think we have to be able to configure such things using the only Kaspresso.Builder. Yep, it's a little bit challenge to create a suitable and not confusing config =)
  2. Classes duplication is not a very good solution. We try to avoid such an approach.
  3. We have two almost ready PR that will affect the project seriously. That's why I suggest 1. to wait these PR 2. after, apply concepts from your PR to support Robolectric in the separate third PR
  4. If you have some time limits to support Robolectric then let us know. We are ready to introduce Robolectric support as soon as possible for you.

@sergio-sastre
Copy link
Contributor Author

@matzuk
I completely agree with all the points.
Just let me know whether you want me to help add Robolectric compatibility through the Kaspresso.Builder (and what to consider while doing it) once those PRs are merged.

Regarding point 4, no real time limits on my side.

@sergio-sastre
Copy link
Contributor Author

sergio-sastre commented Jul 14, 2021

Hi @sergio-sastre!
Thanks a lot for your job! We really appreciate such kind of help!
We got the main idea and concerns about using Robolectric in Kaspresso. Also, your code has highlighted all necessary changes.

So, my thoughts:

  1. I think we have to be able to configure such things using the only Kaspresso.Builder. Yep, it's a little bit challenge to create a suitable and not confusing config =)
  2. Classes duplication is not a very good solution. We try to avoid such an approach.
  3. We have two almost ready PR that will affect the project seriously. That's why I suggest 1. to wait these PR 2. after, apply concepts from your PR to support Robolectric in the separate third PR
  4. If you have some time limits to support Robolectric then let us know. We are ready to introduce Robolectric support as soon as possible for you.

Hi there!
I have good news!
I found an approach to get it working without the code duplication and making it configurable on the Kaspresso.Builder.
Before I proceed to a complete solution and some code cleaning, I just want to ask for your opinion on my approach. Any suggestions are very welcome.

First of all, enabling tests to also run on the JVM would look like this:

class SharedTest : TestCase(Kaspresso.Builder.simple(sharedTest = true)){}

Coming back to the solution, the main problem was the hard dependency to Automator in Kaspresso, namely

private val uiDevice = UiDevice.getInstance(instrumentation)

as well the one in the Kaspresso constructor:

data class Kaspresso(
...
internal val device: Device,
...
)

I solved it by first removing UiDevice from Kaspresso.Builder, and making Device optional in the constructor (and the corresponding changes it implies). Then I apply a factory pattern to return the proper config, so UiDevice is only used by KautomatorOnDeviceConfig, like this

object KautomatorConfigResolver {

    fun build(sharedTest: Boolean): KautomatorConfig =
        when (sharedTest) {
            true -> KautomatorOnJVMConfig()
            false -> KautomatorOnDeviceConfig()
        }
}
class KautomatorOnDeviceConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer =
        AdbServerImpl(LogLevel.WARN, libLogger)

    override fun getPermissions(libLogger: UiTestLogger): Permissions =
        PermissionsImpl(libLogger, getUiDevice())

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network =
        NetworkImpl(getInstrumentation().targetContext, adbServer, libLogger)
   ...
    private fun getUiDevice() : UiDevice = UiDevice.getInstance(getInstrumentation())
}

and in Robolectric those methods return empty implementations of the objects (they are not supported by Robolectric anyway, since are UIAutomator-dependent)

class KautomatorOnJVMConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer = object: AdbServer{}

    override fun getPermissions(libLogger: UiTestLogger): Permissions = object: Permissions{}

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network = object: Network{}
     ...
}

and in the Kaspresso.Builder variable initialisation...

@Suppress("detekt.ComplexMethod")
private fun postInitVariables(sharedTest: Boolean) {
       val kautomatorConfig = KautomatorConfigResolver.build(sharedTest)
       if (!::libLogger.isInitialized) libLogger = UiTestLoggerImpl(DEFAULT_LIB_LOGGER_TAG)
       ...
       
       if (!::adbServer.isInitialized) adbServer = kautomatorConfig.getAdbServer(libLogger)
       if (!::network.isInitialized) network = kautomatorConfig.getNetwork(adbServer, libLogger)
       ...
}

Let me know your thoughts on this ;)

@matzuk
Copy link
Member

matzuk commented Jul 19, 2021

Hi @sergio-sastre!
Thank you for your fixed version!
Please, give us time to check and observe your code.
With best regards!

@matzuk
Copy link
Member

matzuk commented Jul 27, 2021

@sergio-sastre Hi!
Sorry, there's a lot of work this week. Promise to review and answer all questions on the closest weekend =)

@matzuk
Copy link
Member

matzuk commented Aug 1, 2021

Hi @sergio-sastre!
Thanks a lot for your job! We really appreciate such kind of help!
We got the main idea and concerns about using Robolectric in Kaspresso. Also, your code has highlighted all necessary changes.
So, my thoughts:

  1. I think we have to be able to configure such things using the only Kaspresso.Builder. Yep, it's a little bit challenge to create a suitable and not confusing config =)
  2. Classes duplication is not a very good solution. We try to avoid such an approach.
  3. We have two almost ready PR that will affect the project seriously. That's why I suggest 1. to wait these PR 2. after, apply concepts from your PR to support Robolectric in the separate third PR
  4. If you have some time limits to support Robolectric then let us know. We are ready to introduce Robolectric support as soon as possible for you.

Hi there!
I have good news!
I found an approach to get it working without the code duplication and making it configurable on the Kaspresso.Builder.
Before I proceed to a complete solution and some code cleaning, I just want to ask for your opinion on my approach. Any suggestions are very welcome.

First of all, enabling tests to also run on the JVM would look like this:

class SharedTest : TestCase(Kaspresso.Builder.simple(sharedTest = true)){}

Coming back to the solution, the main problem was the hard dependency to Automator in Kaspresso, namely

private val uiDevice = UiDevice.getInstance(instrumentation)

as well the one in the Kaspresso constructor:

data class Kaspresso(
...
internal val device: Device,
...
)

I solved it by first removing UiDevice from Kaspresso.Builder, and making Device optional in the constructor (and the corresponding changes it implies). Then I apply a factory pattern to return the proper config, so UiDevice is only used by KautomatorOnDeviceConfig, like this

object KautomatorConfigResolver {

    fun build(sharedTest: Boolean): KautomatorConfig =
        when (sharedTest) {
            true -> KautomatorOnJVMConfig()
            false -> KautomatorOnDeviceConfig()
        }
}
class KautomatorOnDeviceConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer =
        AdbServerImpl(LogLevel.WARN, libLogger)

    override fun getPermissions(libLogger: UiTestLogger): Permissions =
        PermissionsImpl(libLogger, getUiDevice())

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network =
        NetworkImpl(getInstrumentation().targetContext, adbServer, libLogger)
   ...
    private fun getUiDevice() : UiDevice = UiDevice.getInstance(getInstrumentation())
}

and in Robolectric those methods return empty implementations of the objects (they are not supported by Robolectric anyway, since are UIAutomator-dependent)

class KautomatorOnJVMConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer = object: AdbServer{}

    override fun getPermissions(libLogger: UiTestLogger): Permissions = object: Permissions{}

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network = object: Network{}
     ...
}

and in the Kaspresso.Builder variable initialisation...

@Suppress("detekt.ComplexMethod")
private fun postInitVariables(sharedTest: Boolean) {
       val kautomatorConfig = KautomatorConfigResolver.build(sharedTest)
       if (!::libLogger.isInitialized) libLogger = UiTestLoggerImpl(DEFAULT_LIB_LOGGER_TAG)
       ...
       
       if (!::adbServer.isInitialized) adbServer = kautomatorConfig.getAdbServer(libLogger)
       if (!::network.isInitialized) network = kautomatorConfig.getNetwork(adbServer, libLogger)
       ...
}

Let me know your thoughts on this ;)

Hi @sergio-sastre!
I've reviewed your solution. So, now it looks better =) But, the big number of !! and ? really confuses me. Also, I see some kind of duplication code in KautomatorConfig, anyway.
If we have problems with UI Automator classes then maybe there is a sense to wrap only these classes? It will interfaces with two implementations: first - call UI Automator, second - throw Exceptions (with all needed additional information, sure). Yep, throwing exceptions in different places is not a very appropriate way. On the other hand, Kaspresso declares using UI Automator as a tool helping in a lot of cases, and UI tests are not associated with JVM. That's why if you want to run your tests on JVM only then be ready to change your tests. Wrapping of UI Automator classes simplifies an introduction of Robolectric support into Kaspresso. But, the common disadvantage of our attempts is how to warm a user and how to highlight code where UI Automator is using. Or do we make a user responsible for such experiments with Robolectric?
@RuslanMingaliev @eakurnikov your opinion?

@sergio-sastre
Copy link
Contributor Author

sergio-sastre commented Aug 4, 2021

Hi @sergio-sastre!
Thanks a lot for your job! We really appreciate such kind of help!
We got the main idea and concerns about using Robolectric in Kaspresso. Also, your code has highlighted all necessary changes.
So, my thoughts:

  1. I think we have to be able to configure such things using the only Kaspresso.Builder. Yep, it's a little bit challenge to create a suitable and not confusing config =)
  2. Classes duplication is not a very good solution. We try to avoid such an approach.
  3. We have two almost ready PR that will affect the project seriously. That's why I suggest 1. to wait these PR 2. after, apply concepts from your PR to support Robolectric in the separate third PR
  4. If you have some time limits to support Robolectric then let us know. We are ready to introduce Robolectric support as soon as possible for you.

Hi there!
I have good news!
I found an approach to get it working without the code duplication and making it configurable on the Kaspresso.Builder.
Before I proceed to a complete solution and some code cleaning, I just want to ask for your opinion on my approach. Any suggestions are very welcome.
First of all, enabling tests to also run on the JVM would look like this:

class SharedTest : TestCase(Kaspresso.Builder.simple(sharedTest = true)){}

Coming back to the solution, the main problem was the hard dependency to Automator in Kaspresso, namely

private val uiDevice = UiDevice.getInstance(instrumentation)

as well the one in the Kaspresso constructor:

data class Kaspresso(
...
internal val device: Device,
...
)

I solved it by first removing UiDevice from Kaspresso.Builder, and making Device optional in the constructor (and the corresponding changes it implies). Then I apply a factory pattern to return the proper config, so UiDevice is only used by KautomatorOnDeviceConfig, like this

object KautomatorConfigResolver {

    fun build(sharedTest: Boolean): KautomatorConfig =
        when (sharedTest) {
            true -> KautomatorOnJVMConfig()
            false -> KautomatorOnDeviceConfig()
        }
}
class KautomatorOnDeviceConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer =
        AdbServerImpl(LogLevel.WARN, libLogger)

    override fun getPermissions(libLogger: UiTestLogger): Permissions =
        PermissionsImpl(libLogger, getUiDevice())

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network =
        NetworkImpl(getInstrumentation().targetContext, adbServer, libLogger)
   ...
    private fun getUiDevice() : UiDevice = UiDevice.getInstance(getInstrumentation())
}

and in Robolectric those methods return empty implementations of the objects (they are not supported by Robolectric anyway, since are UIAutomator-dependent)

class KautomatorOnJVMConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer = object: AdbServer{}

    override fun getPermissions(libLogger: UiTestLogger): Permissions = object: Permissions{}

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network = object: Network{}
     ...
}

and in the Kaspresso.Builder variable initialisation...

@Suppress("detekt.ComplexMethod")
private fun postInitVariables(sharedTest: Boolean) {
       val kautomatorConfig = KautomatorConfigResolver.build(sharedTest)
       if (!::libLogger.isInitialized) libLogger = UiTestLoggerImpl(DEFAULT_LIB_LOGGER_TAG)
       ...
       
       if (!::adbServer.isInitialized) adbServer = kautomatorConfig.getAdbServer(libLogger)
       if (!::network.isInitialized) network = kautomatorConfig.getNetwork(adbServer, libLogger)
       ...
}

Let me know your thoughts on this ;)

Hi @sergio-sastre!
I've reviewed your solution. So, now it looks better =) But, the big number of !! and ? really confuses me. Also, I see some kind of duplication code in KautomatorConfig, anyway.
If we have problems with UI Automator classes then maybe there is a sense to wrap only these classes? It will interfaces with two implementations: first - call UI Automator, second - throw Exceptions (with all needed additional information, sure). Yep, throwing exceptions in different places is not a very appropriate way. On the other hand, Kaspresso declares using UI Automator as a tool helping in a lot of cases, and UI tests are not associated with JVM. That's why if you want to run your tests on JVM only then be ready to change your tests. Wrapping of UI Automator classes simplifies an introduction of Robolectric support into Kaspresso. But, the common disadvantage of our attempts is how to warm a user and how to highlight code where UI Automator is using. Or do we make a user responsible for such experiments with Robolectric?
@RuslanMingaliev @eakurnikov your opinion?

Hi @matzuk!
Thanks for your feedback, it is very valuable!
I personally believe the user should be responsible for such experiments with Robolectric, but we warned about the reason of the failing test when running on the JVM because of UiAutomator.

Wrapping UiDevice (the direct UiAutomator class that causes the problem) in an interface would solve the problem and help catch and throw the desired exceptions to warn the user about the incompatibility of the running test with Robolectric. I believe that would be a pretty nice solution, and seems feasible.
I have to assess how much work it is indeed, but hope to adjust the PR in the following week.

Regarding the code duplication in KautomatorConfig, what do you mean exactly? I am open to any suggestion to improve it :)

@matzuk
Copy link
Member

matzuk commented Aug 9, 2021

Hi @sergio-sastre!
Thanks a lot for your job! We really appreciate such kind of help!
We got the main idea and concerns about using Robolectric in Kaspresso. Also, your code has highlighted all necessary changes.
So, my thoughts:

  1. I think we have to be able to configure such things using the only Kaspresso.Builder. Yep, it's a little bit challenge to create a suitable and not confusing config =)
  2. Classes duplication is not a very good solution. We try to avoid such an approach.
  3. We have two almost ready PR that will affect the project seriously. That's why I suggest 1. to wait these PR 2. after, apply concepts from your PR to support Robolectric in the separate third PR
  4. If you have some time limits to support Robolectric then let us know. We are ready to introduce Robolectric support as soon as possible for you.

Hi there!
I have good news!
I found an approach to get it working without the code duplication and making it configurable on the Kaspresso.Builder.
Before I proceed to a complete solution and some code cleaning, I just want to ask for your opinion on my approach. Any suggestions are very welcome.
First of all, enabling tests to also run on the JVM would look like this:

class SharedTest : TestCase(Kaspresso.Builder.simple(sharedTest = true)){}

Coming back to the solution, the main problem was the hard dependency to Automator in Kaspresso, namely

private val uiDevice = UiDevice.getInstance(instrumentation)

as well the one in the Kaspresso constructor:

data class Kaspresso(
...
internal val device: Device,
...
)

I solved it by first removing UiDevice from Kaspresso.Builder, and making Device optional in the constructor (and the corresponding changes it implies). Then I apply a factory pattern to return the proper config, so UiDevice is only used by KautomatorOnDeviceConfig, like this

object KautomatorConfigResolver {

    fun build(sharedTest: Boolean): KautomatorConfig =
        when (sharedTest) {
            true -> KautomatorOnJVMConfig()
            false -> KautomatorOnDeviceConfig()
        }
}
class KautomatorOnDeviceConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer =
        AdbServerImpl(LogLevel.WARN, libLogger)

    override fun getPermissions(libLogger: UiTestLogger): Permissions =
        PermissionsImpl(libLogger, getUiDevice())

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network =
        NetworkImpl(getInstrumentation().targetContext, adbServer, libLogger)
   ...
    private fun getUiDevice() : UiDevice = UiDevice.getInstance(getInstrumentation())
}

and in Robolectric those methods return empty implementations of the objects (they are not supported by Robolectric anyway, since are UIAutomator-dependent)

class KautomatorOnJVMConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer = object: AdbServer{}

    override fun getPermissions(libLogger: UiTestLogger): Permissions = object: Permissions{}

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network = object: Network{}
     ...
}

and in the Kaspresso.Builder variable initialisation...

@Suppress("detekt.ComplexMethod")
private fun postInitVariables(sharedTest: Boolean) {
       val kautomatorConfig = KautomatorConfigResolver.build(sharedTest)
       if (!::libLogger.isInitialized) libLogger = UiTestLoggerImpl(DEFAULT_LIB_LOGGER_TAG)
       ...
       
       if (!::adbServer.isInitialized) adbServer = kautomatorConfig.getAdbServer(libLogger)
       if (!::network.isInitialized) network = kautomatorConfig.getNetwork(adbServer, libLogger)
       ...
}

Let me know your thoughts on this ;)

Hi @sergio-sastre!
I've reviewed your solution. So, now it looks better =) But, the big number of !! and ? really confuses me. Also, I see some kind of duplication code in KautomatorConfig, anyway.
If we have problems with UI Automator classes then maybe there is a sense to wrap only these classes? It will interfaces with two implementations: first - call UI Automator, second - throw Exceptions (with all needed additional information, sure). Yep, throwing exceptions in different places is not a very appropriate way. On the other hand, Kaspresso declares using UI Automator as a tool helping in a lot of cases, and UI tests are not associated with JVM. That's why if you want to run your tests on JVM only then be ready to change your tests. Wrapping of UI Automator classes simplifies an introduction of Robolectric support into Kaspresso. But, the common disadvantage of our attempts is how to warm a user and how to highlight code where UI Automator is using. Or do we make a user responsible for such experiments with Robolectric?
@RuslanMingaliev @eakurnikov your opinion?

Hi @matzuk!
Thanks for your feedback, it is very valuable!
I personally believe the user should be responsible for such experiments with Robolectric, but we warned about the reason of the failing test when running on the JVM because of UiAutomator.

Wrapping UiDevice (the direct UiAutomator class that causes the problem) in an interface would solve the problem and help catch and throw the desired exceptions to warn the user about the incompatibility of the running test with Robolectric. I believe that would be a pretty nice solution, and seems feasible.
I have to assess how much work it is indeed, but hope to adjust the PR in the following week.

Regarding the code duplication in KautomatorConfig, what do you mean exactly? I am open to any suggestion to improve it :)

@sergi

Hi @sergio-sastre!
Thanks a lot for your job! We really appreciate such kind of help!
We got the main idea and concerns about using Robolectric in Kaspresso. Also, your code has highlighted all necessary changes.
So, my thoughts:

  1. I think we have to be able to configure such things using the only Kaspresso.Builder. Yep, it's a little bit challenge to create a suitable and not confusing config =)
  2. Classes duplication is not a very good solution. We try to avoid such an approach.
  3. We have two almost ready PR that will affect the project seriously. That's why I suggest 1. to wait these PR 2. after, apply concepts from your PR to support Robolectric in the separate third PR
  4. If you have some time limits to support Robolectric then let us know. We are ready to introduce Robolectric support as soon as possible for you.

Hi there!
I have good news!
I found an approach to get it working without the code duplication and making it configurable on the Kaspresso.Builder.
Before I proceed to a complete solution and some code cleaning, I just want to ask for your opinion on my approach. Any suggestions are very welcome.
First of all, enabling tests to also run on the JVM would look like this:

class SharedTest : TestCase(Kaspresso.Builder.simple(sharedTest = true)){}

Coming back to the solution, the main problem was the hard dependency to Automator in Kaspresso, namely

private val uiDevice = UiDevice.getInstance(instrumentation)

as well the one in the Kaspresso constructor:

data class Kaspresso(
...
internal val device: Device,
...
)

I solved it by first removing UiDevice from Kaspresso.Builder, and making Device optional in the constructor (and the corresponding changes it implies). Then I apply a factory pattern to return the proper config, so UiDevice is only used by KautomatorOnDeviceConfig, like this

object KautomatorConfigResolver {

    fun build(sharedTest: Boolean): KautomatorConfig =
        when (sharedTest) {
            true -> KautomatorOnJVMConfig()
            false -> KautomatorOnDeviceConfig()
        }
}
class KautomatorOnDeviceConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer =
        AdbServerImpl(LogLevel.WARN, libLogger)

    override fun getPermissions(libLogger: UiTestLogger): Permissions =
        PermissionsImpl(libLogger, getUiDevice())

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network =
        NetworkImpl(getInstrumentation().targetContext, adbServer, libLogger)
   ...
    private fun getUiDevice() : UiDevice = UiDevice.getInstance(getInstrumentation())
}

and in Robolectric those methods return empty implementations of the objects (they are not supported by Robolectric anyway, since are UIAutomator-dependent)

class KautomatorOnJVMConfig : KautomatorConfig {

    override fun getAdbServer(libLogger: UiTestLogger): AdbServer = object: AdbServer{}

    override fun getPermissions(libLogger: UiTestLogger): Permissions = object: Permissions{}

    override fun getNetwork(adbServer: AdbServer, libLogger: UiTestLogger): Network = object: Network{}
     ...
}

and in the Kaspresso.Builder variable initialisation...

@Suppress("detekt.ComplexMethod")
private fun postInitVariables(sharedTest: Boolean) {
       val kautomatorConfig = KautomatorConfigResolver.build(sharedTest)
       if (!::libLogger.isInitialized) libLogger = UiTestLoggerImpl(DEFAULT_LIB_LOGGER_TAG)
       ...
       
       if (!::adbServer.isInitialized) adbServer = kautomatorConfig.getAdbServer(libLogger)
       if (!::network.isInitialized) network = kautomatorConfig.getNetwork(adbServer, libLogger)
       ...
}

Let me know your thoughts on this ;)

Hi @sergio-sastre!
I've reviewed your solution. So, now it looks better =) But, the big number of !! and ? really confuses me. Also, I see some kind of duplication code in KautomatorConfig, anyway.
If we have problems with UI Automator classes then maybe there is a sense to wrap only these classes? It will interfaces with two implementations: first - call UI Automator, second - throw Exceptions (with all needed additional information, sure). Yep, throwing exceptions in different places is not a very appropriate way. On the other hand, Kaspresso declares using UI Automator as a tool helping in a lot of cases, and UI tests are not associated with JVM. That's why if you want to run your tests on JVM only then be ready to change your tests. Wrapping of UI Automator classes simplifies an introduction of Robolectric support into Kaspresso. But, the common disadvantage of our attempts is how to warm a user and how to highlight code where UI Automator is using. Or do we make a user responsible for such experiments with Robolectric?
@RuslanMingaliev @eakurnikov your opinion?

Hi @matzuk!
Thanks for your feedback, it is very valuable!
I personally believe the user should be responsible for such experiments with Robolectric, but we warned about the reason of the failing test when running on the JVM because of UiAutomator.

Wrapping UiDevice (the direct UiAutomator class that causes the problem) in an interface would solve the problem and help catch and throw the desired exceptions to warn the user about the incompatibility of the running test with Robolectric. I believe that would be a pretty nice solution, and seems feasible.
I have to assess how much work it is indeed, but hope to adjust the PR in the following week.

Regarding the code duplication in KautomatorConfig, what do you mean exactly? I am open to any suggestion to improve it :)

Hi @sergio-sastre!

About KautomatorConfig. After wrapping of UI Automator classes, KautomatorConfig will be unnecessary, I think.

@sergio-sastre
Copy link
Contributor Author

Hi @matzuk!
Sorry for not updating this yet, I got other stuff that has priority first. I promise to try to include the proposed changes before the end of the month!

@matzuk
Copy link
Member

matzuk commented Oct 12, 2021

merged in #286

@matzuk matzuk closed this Oct 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request: Make Kaspresso robolectric-compatible (Project Nitrogen)
5 participants