Coder Social home page Coder Social logo

rxidler's Introduction

RxIdler

An IdlingResource for Espresso which wraps an RxJava Scheduler.

Usage

Set the wrapping functions as the delegate for handling scheduler initialization to RxJava:

  • RxJava 3.x:

    RxJavaPlugins.setInitComputationSchedulerHandler(
        Rx3Idler.create("RxJava 3.x Computation Scheduler"));
    RxJavaPlugins.setInitIoSchedulerHandler(
        Rx3Idler.create("RxJava 3.x IO Scheduler"));
    // etc...
  • RxJava 2.x:

    RxJavaPlugins.setInitComputationSchedulerHandler(
        Rx2Idler.create("RxJava 2.x Computation Scheduler"));
    RxJavaPlugins.setInitIoSchedulerHandler(
        Rx2Idler.create("RxJava 2.x IO Scheduler"));
    // etc...
  • RxJava 1.x:

    RxJavaPlugins.getInstance().registerSchedulersHook(RxIdler.hooks());

When that Scheduler is first accessed via Schedulers, the RxIdler function will wrap it with an Espresso IdlingResource and side-effect by registering it to the Espresso class.

This code is most frequently put in a custom test runner's onStart() method:

public final class MyTestRunner extends AndroidJUnitRunner {
  @Override public void onStart() {
    RxJavaPlugins.setInitComputationSchedulerHandler(
        Rx3Idler.create("RxJava 3.x Computation Scheduler"));
    // etc...
    
    super.onStart();
  }
}

If you have custom Scheduler implementations you can wrap them directly and then register them with Espresso:

  • RxJava 3.x:

    IdlingResourceScheduler wrapped = Rx3Idler.wrap(myScheduler, "My Scheduler");
    IdlingRegistry.getInstance().register(wrapped);
    // Use 'wrapped' now instead of 'myScheduler'...
  • RxJava 2.x:

    IdlingResourceScheduler wrapped = Rx2Idler.wrap(myScheduler, "My Scheduler");
    IdlingRegistry.getInstance().register(wrapped);
    // Use 'wrapped' now instead of 'myScheduler'...
  • RxJava 1.x:

    IdlingResourceScheduler wrapped = RxIdler.wrap(myScheduler, "My Scheduler");
    IdlingRegistry.getInstance().register(wrapped);
    // Use 'wrapped' now instead of 'myScheduler'...

Ensure that you provide unique name for your wrapped schedulers as Espresso will ignore multiple idling resources registered with the same name.

Download

  • RxJava 3.x:

    dependencies {
      androidTestImplementation 'com.squareup.rx.idler:rx3-idler:0.11.0'
    }
  • RxJava 2.x:

    dependencies {
      androidTestImplementation 'com.squareup.rx.idler:rx2-idler:0.11.0'
    }
  • RxJava 1.x:

    dependencies {
      androidTestImplementation 'com.squareup.rx.idler:rx1-idler:0.11.0'
    }

Snapshots of the development version are available in Sonatype's snapshots repository.

ProGuard

If you use ProGuard on Espresso test builds, you may need to add the following rules into your ProGuard configuration.

RxJava 3.x:

-keep class io.reactivex.rxjava3.plugins.RxJavaPlugins { *; }
-keep class io.reactivex.rxjava3.disposables.CompositeDisposable { *; }

RxJava 2.x:

-keep class io.reactivex.plugins.RxJavaPlugins { *; }
-keep class io.reactivex.disposables.CompositeDisposable { *; }

RxJava 1.x:

-keep class rx.plugins.RxJavaPlugins { *; }
-keep class rx.subscriptions.CompositeSubscription { *; }

License

Copyright 2017 Square, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

rxidler's People

Contributors

fabiendevos avatar jakewharton avatar jrodbx avatar larryng avatar tasomaniac avatar technoir42 avatar vanniktech avatar xserxses avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxidler's Issues

Latest code changes not released yet

The PR to support AndroidX was merged last month (#19) but this never got released, would it be possible to get a new release so that RxIdler can be used with the AndroidX version of Espresso?

Thanks!

Question: How could I test case with an infinite Observable?

Details:
While we wait for a response from the backend we show a progress bar.
We simulate waiting by return a fake response with Observable.never() and it leads the test to IdlingTimeoutException because we wait infinitely.

A possible solution I see: unregister IdleResources for such rare test scenarios

Maybe you solve somehow similar tasks at Squre

DelegatingIdlingResourceScheduler does not work with .delay()

Using this library on my project I see that when using delay() rx operator, the idlingResource returns that it is idle.
Looking at the unit tests I saw this was designed that way. These tests guarantee it:
scheduleWithNonZeroDelayReportsIdle and schedulePeriodicallyWithNonZeroDelayReportsIdle

It is supposed to not work with delay() operator?

Scheduler handlers do not take effect in rxjava-2.1.3

Hi, I am using RxJava 2.1.3 with the latest Espresso 3.0.0 and ATSL 1.0.0.
I noticed that the handlers were not taking effect. I debugged and notice that the call to Schedulers#initXXScheduler() happens inside a static block (see io.reactivex.schedulers.Schedulers:73).
To get it working, I had to move the calls to RxJavaPlugins.setInitXXXSchedulerHandler also inside a static block (in the runner) and then add a null check to DelegatingIdlingResourceScheduler#stopWork method to make sure callback is not null.

I am not submitting a PR because I think this fix is somehow a bit dodgy :/ although works for me

Any thoughts?

Debounce doesn't taken into account.

If app have something like .debounce(100, TimeUnit.MILLISECONDS) before updating UI espresso does not wait for it.

This happens because RxIdler is busy only when executing work and during the time between schedule call and executing it is idle.

Does library unregisters IdlingResource?

Hello,

so in RxIdler I see Espresso.registerIdlingResources call.
But I didn't see Espresso.unregisterIdlingResources or IdlingRegistry.getInstance().unregister.

Should it be that way or I should unregister Rx idling resource manually?

Is there any idler library used for rxjava3?

Hi,

Currently I'm working on migration to rxjava3. In our project we are using this idler to testing with Espresso, but after migrated to rxjava3, how can we using Idler? Thanks for help.

IdlingRegistry doesn't set registerIdleTransitionCallback until a IdlingResourceRegistry sync

io.reactivex.rxjava2:rxandroid:2.1.0
io.reactivex.rxjava2:rxjava:2.2.2
com.squareup.rx.idler:rx2-idler:0.9.1
androidx.test.espresso:espresso-core:3.2.0
androidx.test.espresso:espresso-idling-resource:3.2.0

I have an application that injects our ScheduleProviders, so in our test app component I was having to use the RxIdler.wrap() functionality and I am registering them as IdlingResources in a custom ActivityTestRule before the base?.evaluate().

Since Espresso.registerIdlingResources() is now a deprecated function, I was using the IdlingRegistry.getInstance().register(). However I have a couple of tests that have no UI interactions that were crashing for null pointer exceptions on the DelegatingIdlingResourceSchedulers.stopWork() for a null ResourceCallback. Even though I could debug through and see the Schedulers in the list of registered resources in the IdlingRegistry. This didn't happen if I changed the call to use the deprecated Espresso.registerIdlingResources().
After much debugging I discovered that this is because:
Espresso.registerIdlingResources() immediately causes a sync on the IdlingResourceRegistry which is where the registerIdleTransitionCallback() happens. Whereas the IdlingRegistry does not sync with the IdlingResourceRegistry until an IdleNotifier is necessary.
I am able to force this by calling an Espresso interaction immediately after registering.

All of my tests now work the same by exchanging

@Suppress("DEPRECATION")
Espresso.registerIdlingResources(scheduler)

with

IdlingRegistry.getInstance().register(scheduler)
Espresso.onIdle()

I thought this information might help a few other people, or could be an addition to the README for how to fully register these IdlingResources with the newer IdlingRegistry.

RxJava 3 and RxJava 3 Retrofit adapter

Hello,

This is more of a question that an actual issue. We've recently migrated our project to RxJava 3 and our UI tests were all randomly failing. The culprit turned out to be com.squareup.retrofit2:adapter-rxjava3 because during the migration we left the RxJava3CallAdapterFactory.create() call instead of RxJava3CallAdapterFactory.createSynchronous() (which according to https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-290-2020-05-20 would have a similar functionality as RxJava2). The failing tests were in situations where multiple API requests were combined when using flatMap (as an example). RxIdler would determine that the IdlingResource was idle after the first API call and that would make espresso to start asserting the UI before the 2nd API call was finished.
Are there any plans to change RxIdler to support asynchronous HTTP requests?

Thank you

Not idling?

Correct if I am wrong but I made idler setup as described and test with body below fails.

 val value = AtomicBoolean(false)
 Observable.timer(1, TimeUnit.SECONDS)
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .switchMap {
          value.set(true)
          Observable.just(Unit)
       }
      .subscribe()
Espresso.onIdle {
     assertTrue(value.get())
}

stopWork() crashes when attempting to call onTransitionToIdle()

This started happening in 0.10.0 but works fine in 0.9.1:

E/AndroidRuntime: FATAL EXCEPTION: RxIoScheduler-2
    Process: com.example.test, PID: 7030
    java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
        at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:59)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
     Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void androidx.test.espresso.IdlingResource$ResourceCallback.onTransitionToIdle()' on a null object reference
        at com.squareup.rx.idler.DelegatingIdlingResourceScheduler.stopWork(DelegatingIdlingResourceScheduler.java:100)
        at com.squareup.rx.idler.DelegatingIdlingResourceScheduler$ScheduledWork.call(DelegatingIdlingResourceScheduler.java:148)
        at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230)
        at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) 
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:919) 

Not yet sure whether this is my fault. Here's how we registering the idler:

class ExampleAndroidJUnitRunner : AndroidJUnitRunner() {
    override fun onStart() {
        RxJavaPlugins.getInstance().registerSchedulersHook(RxIdler.hooks())
        IdlingRegistry.getInstance().register(
            RxIdler.wrap(AndroidSchedulers.mainThread(), "Android Main Thread Scheduler")
        )
        super.onStart()
    }
}

RxIdler throws IllegalStateException when buffer is used

When RxJava2 operator buffer is used like this:

RxJavaPlugins.setInitIoSchedulerHandler(Rx2Idler.create("Test scheduler"));
PublishSubject subject = PublishSubject.create();

subject
        .buffer(1, TimeUnit.SECONDS, Schedulers.io())
        .subscribe();

RxIdler throws IllegalStateException:

java.lang.IllegalStateException: Already completed
  at com.squareup.rx2.idler.DelegatingIdlingResourceScheduler$ScheduledWork.run(DelegatingIdlingResourceScheduler.java:152)
  at io.reactivex.Scheduler$Worker$PeriodicTask.run(Scheduler.java:371)
  at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
  at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
  at java.lang.Thread.run(Thread.java:764)

If this actual RxIdler issue I can provide project to reproduce this.

RxIdler does not wait until network request get finished

Here is my method which I want to test :

@Test
    fun shouldBeAbleToScrollViewAndDisplayRuleDetails() {
        onView(withId(R.id.recyclerView)).perform(RecyclerViewActions
            .actionOnItemAtPosition<MainAdapter.SavingsGoalViewHolder>(5, click()))
        onView(withText(R.string.your_rules)).check(matches(isDisplayed()))
    }

I receive following exception :

at dalvik.system.VMStack.getThreadStackTrace(Native Method)
	at java.lang.Thread.getStackTrace(Thread.java:1736)
	at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:88)
	at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:51)
	at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:314)
	at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:297)
	at com.sample.android.qapital.TestMainActivity.shouldBeAbleToScrollViewAndDisplayRuleDetails(TestMainActivity.kt:38)
	at java.lang.reflect.Method.invoke(Native Method)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at androidx.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:531)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
	at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:388)
	at com.sample.android.qapital.AppTestRunner.onStart(AppTestRunner.kt:18)
	at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2205)
Caused by: junit.framework.AssertionFailedError: 'is displayed on the screen to the user' doesn't match the selected view.
Expected: is displayed on the screen to the user
     Got: "AppCompatTextView{id=-1, visibility=VISIBLE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@52b82ea, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Your\nRules, input-type=0, ime-target=false, has-links=false}"

	at androidx.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:539)
	at androidx.test.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:103)
	at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:415)
	at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:279)
	at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:265)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at android.os.Handler.handleCallback(Handler.java:938)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loop(Looper.java:223)
	at android.app.ActivityThread.main(ActivityThread.java:7656)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

It seems RxIdler does not wait as expected. I have used RxIdler in similar projects and it seems to work.

Here is source code of my project : https://github.com/Ali-Rezaei/SavingGoals-Cache

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.