Showing posts with label android-espresso. Show all posts
Showing posts with label android-espresso. Show all posts

Wednesday, September 19, 2018

findElement after switching webviews not working

Leave a Comment

I have a simple Espresso test for Android that works okay until the Activity is switched. The test runs through a login, selecting elements from a webview by class and then after a successful login, the activity switches. Once in the new Activity, I am unable to find anything in the new webview, either by class, css selector or by x_path.

I know this is buried in the html, I can see it and search for it in the chrome insepctor:

<div _ngcontent-c9="" class="tile-title" title="Pay">Pay </div> 

Yet I can't find it with this CSS_SELECTOR:

onWebView(allOf<View>(isDisplayed(), isJavascriptEnabled()))                     .withElement(findElement(Locator.CSS_SELECTOR, "div[title=Pay]")) 

Similarly, I have also tried with an X_PATH string and even by class name (which is not unique) but it still fails.

We do have multiple webviews created, but only one is visible.

What can I do to shed more light on this and figure out why I can't select the div in question?

1 Answers

Answers 1

you need to call .reset() at the end of the first interaction;

else you won't be able to access (or match) that reference anymore.

onWebView(allOf<View>(isDisplayed(), isJavascriptEnabled()))     .withElement(findElement(Locator.CSS_SELECTOR, "div[title=Pay]"))     .perform( ... )     .reset(); 

as the documentation for Espresso Web states:

reset() reverts the WebView to its initial state. This is necessary when a prior action, such as a click, introduces a navigation change that makes ElementReference and WindowReference objects inaccessible.

then matching again, will provide a new reference, which can be accessed.

Read More

Monday, September 25, 2017

Could not launch intent within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time?

Leave a Comment

I am writing Espresso Test. Here is the test case

OnClick of Fab, the app launches QuizActivity.

Let me explain to you little about my app.

So the app requirement was -

  1. There is JSON file in assets folder
  2. I have to parse it and store the data in database
  3. On Main Activity load this data from database into recyclerview. There is Fab button, on click of it app pass a random list of data (which I have loaded in recyclerview) to QuizActivity

Here is how I did coding -

  1. In MainActivity's onCreate() used AsyncTask to parse and insert data into database only once.
  2. Once data is available, loaded it in recyclerview via AsyncTaskLoader
  3. set Onclick listener on Fab. and passed required data to QuizActivity.

Below is my test

@RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest {    /* @Rule     public IntentsTestRule<MainActivity> intentsTestRule =             new IntentsTestRule<MainActivity>(MainActivity.class); */      @Rule     public ActivityTestRule<MainActivity> intentsTestRule =             new ActivityTestRule<MainActivity>(MainActivity.class,false,true);      @Test     public void fabTest(){         onView(withId(R.id.fab)).perform(click());         //Check if the text_question textview is displayed         onView(withId(R.id.text_question)).check(matches(isDisplayed()));     }     /* @Test     public void clickFloatingActionButton() {         onView(withId(R.id.fab))                 .perform(click());         intended(hasComponent(new ComponentName(getTargetContext(), QuizActivity.class)));     }*/ } 

My approach is -

  1. Find Fab
  2. Perform click
  3. Check if the text_question textview is displayed. Note this textview is on QuizActivity.

After I run the test I am getting

java.lang.RuntimeException: Could not launch intent Intent { act=android.intent.action.MAIN flg=0x14000000 cmp=my_package_name/.MainActivity } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1505287862579 and now the last time the queue went idle was: 1505287862579. If these numbers are the same your activity might be hogging the event queue.

PS - I have turned off all the animations. I don't have progress bar in code.

Also one more note , if I comment out the AsyncTask, AsyncTaskLoader, RecyclerView part in onCreate() method then the test is passing.

I suspect that it might be causing due to background task.

Anyone faced similar problem? Please let me know if you know the solution. I am struggling from two days. I searched for similar threads on stackoverflow but nothing worked for me.

1 Answers

Answers 1

I finally got the solution!

Actually, the culprit was custom view in my adapter.

Espresso waits until the AsyncTask or AsyncTaskLoader loads the data, but it looks like custom view causing this problem as stated in the exception :

the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen.

Anyways to overcome this problem, what I need to do is -

"If the test is running set the visibility of Custom view to GONE"

How would you do that?

 private AtomicBoolean isTestRunning;      public synchronized boolean isTestRunning () {         if (null == isTestRunning) {             boolean istest;              try {                  Class.forName ("Full path of your TestName"); // for e.g. com.example.MyTest                  istest = true;             } catch (ClassNotFoundException e) {                 istest = false;             }              isTestRunning = new AtomicBoolean (istest);         }          return isRunningTest.get ();     } 

Now here I am using Recyclerview so in ViewHolder,

public InsectHolder(View itemView)         {             super(itemView);                        customView = (DangerLevelView) itemView.findViewById(R.id.danger_level_tv);              if(isRunningTest()) {                 customView.setVisibility(View.GONE);             }         } 

And yay! your test will be passed.

Hope someone finds it helpful!

Please let me know if you have any questions in comment section below!

Read More

Monday, August 28, 2017

Android Espresso IdlingPolicies.setIdlingResourceTimeout not working

Leave a Comment

I have a few classes to test deep links. Each class test 1 deep link.

There are few tests that always terminate correctly at 10+ seconds when I run them individually but always take more than 45 seconds to finish when I run them together. enter image description here
Note that all these tests are supposed to fail all the times now (I haven't done the implementation for them) so the results should not vary.

Am I using IdlingPolicies.setIdlingResourceTimeout wrong?

My test class:

@RunWith(AndroidJUnit4.class) public class DeepLinkActivityBagTest extends MyActivityTest {      @Rule     public MyActivityTestRule<DeepLinkActivity> activityTestRule =             new MyActivityTestRule<DeepLinkActivity>(DeepLinkActivity.class) {                 @Override                 protected Intent getActivityIntent() {                     Intent intent = super.getActivityIntent();                     intent.setAction(Intent.ACTION_VIEW);                     intent.setData(Uri.parse("xxx://bag"));                     return intent;                 }             };      @Test     public void testCorrectScreenOpened() {         setUpWait();          String expectedToolbarTitle = "shopping bag" + mToolbarTitleSuffix;         onView(withTextIgnoreCase(expectedToolbarTitle)).check(matches(isDisplayed()));     } } 

Its parent class:

@RunWith(AndroidJUnit4.class) public class MyActivityTest {     @Rule     public MyActivityTestRule<DeepLinkActivity> activityTestRule;     protected String mToolbarTitleSuffix;      @Before     public void prepare() {         if (!BuildConfig.FLAVOR.equals(ENV_PRODUCTION)) {             mToolbarTitleSuffix = String.format(" (%s)", BuildConfig.FLAVOR);         }     }      @After     public void resetCountry() {         if (activityTestRule != null) {             PrefUtils.clear(InstrumentationRegistry.getTargetContext());             PrefUtils.setCurrentCountryCode(activityTestRule.getmCurCountryCode());             PrefUtils.setCurrentLangCode(activityTestRule.getmCurLangCode());         }     }      protected void setUpWait() {         try {             Thread.sleep(3 * 1000);         } catch (InterruptedException e) {             Logger.e(e, "");         }         IdlingPolicies.setMasterPolicyTimeout(10, TimeUnit.SECONDS);         IdlingPolicies.setIdlingResourceTimeout(5, TimeUnit.SECONDS);     } } 

MyActivityTestRule:

public class MyActivityTestRule<D extends Activity> extends ActivityTestRule {     private String mCurCountryCode;     private String mCurLangCode;      protected MyActivityTestRule(Class activityClass) {         super(activityClass);     }      public MyActivityTestRule(Class activityClass, boolean initialTouchMode) {         super(activityClass, initialTouchMode);     }      public MyActivityTestRule(Class activityClass, boolean initialTouchMode, boolean launchActivity) {         super(activityClass, initialTouchMode, launchActivity);     }      @Override     protected void beforeActivityLaunched() {         super.beforeActivityLaunched();          PrefUtils.setup(InstrumentationRegistry.getTargetContext());         mCurCountryCode = PrefUtils.getCurrentCountryCode();         mCurLangCode = PrefUtils.getCurrentLangCode();         PrefUtils.clear(InstrumentationRegistry.getTargetContext());         PrefUtils.setCurrentCountryCode("SG");         PrefUtils.setCurrentLangCode("en");     }      String getmCurCountryCode() {         return mCurCountryCode;     }      String getmCurLangCode() {         return mCurLangCode;     } } 

0 Answers

Read More

Monday, June 12, 2017

java.lang.Exception: Custom runner class AndroidJUnit4 should have a public constructor with signature AndroidJUnit4(Class testClass)

Leave a Comment

gradle looks like:

apply plugin: 'com.android.application'  android {     compileSdkVersion 25     buildToolsVersion "25.0.2"      defaultConfig {         applicationId "com.google.developer.taskmaker"         minSdkVersion 19         targetSdkVersion 25         versionCode 1         versionName "1.0"          testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"     }     buildTypes {         release {             minifyEnabled false             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'         }     } }  configurations.all {     resolutionStrategy {         force 'com.android.support:support-annotations:25.2.0'     } }   dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     testCompile 'junit:junit:4.12'     compile 'com.android.support:appcompat-v7:25.2.0'     compile 'com.android.support:recyclerview-v7:25.2.0'     compile 'com.android.support:design:25.2.0'     compile 'com.android.support:preference-v7:25.2.0'     debugCompile 'im.dino:dbinspector:3.4.1@aar'     // Android JUnit Runner     compile 'com.google.android.gms:play-services-appindexing:8.4.0'     // Android runner and rules support      // add this for intent mocking support     androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'      // add this for webview testing support     androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'     compile 'com.android.support.test:runner:0.5'     compile 'com.android.support.test:rules:0.5'     compile 'com.android.support.test.espresso:espresso-core:2.2.2' } 

Unit test case looks like

@RunWith(AndroidJUnit4.class) public class TestClass {      @Rule     public ActivityTestRule<MainActivity> mActivityRule =             new ActivityTestRule<>(MainActivity.class);      @Test     public void buttonClick(){         onView(withId(R.id.fab)).perform(click()).check(matches(isDisplayed()));     }  } 

Error message looks like:

java.lang.Exception: Custom runner class AndroidJUnit4 should have a public constructor with signature AndroidJUnit4(Class testClass)      at org.junit.runners.model.InitializationError.<init>(InitializationError.java:38)     at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:111)     at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)     at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)     at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)     at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)     at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:101)     at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:87)     at com.intellij.junit4.JUnit46ClassesRequestBuilder.collectWrappedRunners(JUnit46ClassesRequestBuilder.java:90)     at com.intellij.junit4.JUnit46ClassesRequestBuilder.getClassesRequest(JUnit46ClassesRequestBuilder.java:51)     at com.intellij.junit4.JUnit4TestRunnerUtil.buildRequest(JUnit4TestRunnerUtil.java:91)     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:95)     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at java.lang.reflect.Method.invoke(Method.java:497)     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)   Process finished with exit code -1 

I have already check other answers but not getting solution.Please tell where thing goes wrong. When running this code I am getting error

3 Answers

Answers 1

I had the same problem. I'm working in Android studio 2.3.1. I checked my run configurations. Under Run->Edit Configurations and discovered the test I was trying to run as an instrumented test was under the Android JUnit tests category, even though I had it in the androidTest directory in my project. I added an Android Instrumented Test (hit the plus button in the corner) and set it to point to the test I was trying to run. That fixed it for me.

Answers 2

This error can be replicated by making a new Application with the default template in Android Studio and copying the auto-generated ExampleInstrumentedTest from the androidTest folder to the test folder:

incorrectly copying an instrumented test into the test folder

Here's what the error looks like:

the OPs error java.lang.Exception: Custom runner class AndroidJUnit4 should have a public constructor with signature AndroidJUnit4(Class testClass)

Note that in order to replicate the problem you would also have to incorrectly add dependencies to the module-level build.gradle:

dependencies in the wrong place

Explanation:

There are two types of unit tests in Android:

  1. Instrumented tests
  2. Local unit tests

Instrumented tests

Instrumented tests are tests that are designed to run on a handset or emulator. These are tests where you need access to a fully-functional part of the Android library (like a real Context for example). These need to go in the androidTest folder and dependencies for these tests (e.g., Espresso, com.android.support.test.rules:0.5) will be prefixed with androidTestCompile in your build.gradle.

Here is an example instrumented test:

import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4;  import org.junit.Test; import org.junit.runner.RunWith;  import static org.junit.Assert.assertEquals;  /**  * Instrumentation test, which will execute on an Android device.  *  * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>  */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest {     @Test     public void useAppContext() throws Exception {         // Context of the app under test.         Context appContext = InstrumentationRegistry.getTargetContext();          assertEquals("com.gyaltsab.myapplication", appContext.getPackageName());     } } 

Local unit tests

Local unit tests are tests that you can run in your IDE. They normally don't depend on any part of the Android library not available on a standard JVM (e.g., they won't depend on Context). The dependencies for these go in the testCompile part of your build.gradle.

Here is an example unit test:

import org.junit.Test;  import static org.junit.Assert.*;  /**  * Example local unit test, which will execute on the development machine (host).  *  * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>  */ public class ExampleUnitTest {     @Test     public void addition_isCorrect() throws Exception {         assertEquals(4, 2 + 2);     } } 

Please see the official docs for a more complete explanation.

Answers 3

Try moving your test file to the androidTest folder.

Read More

Wednesday, May 24, 2017

IllegalAccessError with CountingIdlingResource

Leave a Comment

The app contains a splash screen that displays briefly, and that activity is being tested with an instrumented test, using an IdlingResource so the test knows when the splash screen closes. The problem is that SplashActivity throws what looks like a dependency-related exception during test on devices running API 19:

import android.support.test.espresso.idling.CountingIdlingResource; ... private CountingIdlingResource espressoTestIdlingResource = new CountingIdlingResource("Splash_Delay"); // <-- Exception here line 22 ... 

app/build.gradle:

dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {         exclude group: 'com.android.support', module: 'support-annotations'         exclude group: 'com.google.code.findbugs'         exclude module: 'espresso-idling-resource'         exclude group: "javax.inject"     })     compile 'com.android.support.test.espresso:espresso-idling-resource:2.2.2'      compile 'com.google.dagger:dagger:2.10'     annotationProcessor 'com.google.dagger:dagger-compiler:2.10'     compile 'com.google.dagger:dagger-android:2.10'     compile 'com.google.dagger:dagger-android-support:2.10'     annotationProcessor 'com.google.dagger:dagger-android-processor:2.10'      compile "com.android.support:appcompat-v7:$supportLibraryVersion"     compile "com.android.support:design:$supportLibraryVersion"     compile "com.android.support.constraint:constraint-layout:1.0.2"      compile "com.jakewharton.timber:timber:4.5.1"     compile "com.squareup.phrase:phrase:1.1.0"     compile "com.squareup.retrofit2:retrofit:2.2.0"     compile "com.squareup.retrofit2:converter-gson:2.2.0"     compile "com.squareup.okhttp3:logging-interceptor:3.7.0"     compile 'net.danlew:android.joda:2.9.9'      testCompile 'junit:junit:4.12'     compile 'com.google.firebase:firebase-crash:10.2.4'     androidTestCompile 'junit:junit:4.12' } 

Exception:

java.lang.IllegalAccessError java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation     at com.myapp.android.ui.splash.SplashActivity.<init>(SplashActivity.java:22)     at java.lang.Class.newInstanceImpl(Native Method)     at java.lang.Class.newInstance(Class.java:1208)     at android.app.Instrumentation.newActivity(Instrumentation.java:1061)     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2101)     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)     at android.app.ActivityThread.accessX800(ActivityThread.java:135)     at android.app.ActivityThreadXH.handleMessage(ActivityThread.java:1196)     at android.os.Handler.dispatchMessage(Handler.java:102)     at android.os.Looper.loop(Looper.java:136)     at android.app.ActivityThread.main(ActivityThread.java:5001)     at java.lang.reflect.Method.invokeNative(Native Method)     at java.lang.reflect.Method.invoke(Method.java:515)     at com.android.internal.os.ZygoteInitXMethodAndArgsCaller.run(ZygoteInit.java:785)     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)     at dalvik.system.NativeStart.main(Native Method) 

The exception occurs on an API level 19 Nexus 4 physical device in Firebase Test Lab. It does not occur on any other platforms we are testing on, including a local API 19 emulated Nexus S.

I understood the exception to mean there are ambiguous/duplicate (transitive) dependencies, but I cannot see any in gradlew dependencies, only Espresso Idling Resources v2.2.2. The dependency is "compile" not "androidTestCompile" as CountingIdlingResource is referenced in the Activity.

How do I identify the cause and resolve it?

UPDATE: The exception also occurs with API 19 on a Nexus 5 and Nexus 7. Here are the parts of the output of "./gradlew dependencies" relating to the idling resource library:

_debugApk - ## Internal use, do not manually configure ## +--- com.android.support.test.espresso:espresso-idling-resource:2.2.2 +--- com.google.dagger:dagger:2.10 ... _debugCompile - ## Internal use, do not manually configure ## +--- com.android.support.test.espresso:espresso-idling-resource:2.2.2 +--- com.google.dagger:dagger:2.10 ... _releaseApk - ## Internal use, do not manually configure ## +--- com.android.support.test.espresso:espresso-idling-resource:2.2.2 +--- com.google.dagger:dagger:2.10 ... _releaseCompile - ## Internal use, do not manually configure ## +--- com.android.support.test.espresso:espresso-idling-resource:2.2.2 +--- com.google.dagger:dagger:2.10 ... compile - Classpath for compiling the main sources. +--- com.android.support.test.espresso:espresso-idling-resource:2.2.2 +--- com.google.dagger:dagger:2.10 

1 Answers

Answers 1

As I understand Google Samples the dependency:

com.android.support.test.espresso:espresso-idling-resource:2.2.2 

is only needed when you are implementing custom IdlingResource. Even in IdlingResourceSample README there is a sentence:

Consider using the CountingIdlingResource class from the espresso-contrib package

And as I understand your code you are trying to use CountingIdlingResource from espresso-contrib package, so try to organise your test dependencies as written in other Google sample.

Read More

Thursday, March 24, 2016

Jacoco coverage report in spite of connected device test failures?

Leave a Comment

I'm cleaning up an Android project that has several hundred Espresso tests of which several are flaky. Getting 100% instrumented test success on a regular basis isn't realistic in this context.

My Gradle task for Jacoco code coverage works perfectly (!) when all the Espresso tests do pass (achievable by skipping the flaky ones). When there are test failures, however, the Jacoco report shows 0% coverage even though the Gradle test report has the correct data. Looks like the coverage.ec file generated is 0 bytes.

The connected<flavor>DebugAndroidTest task has been configured with ignoreFailures = true, so the build no longer halts when there were failing tests.

Is there any way to get the test task to correctly generate the coverage.ec file in spite of failures?

0 Answers

Read More