Search code examples
javaandroidandroid-edittextandroid-espresso

EditText with inputType: textEmailAddress not able to type text using Espresso


My xml has an EditText:

<EditText
android:id="@+id/et_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/margin_padding_size_small"
android:layout_marginLeft="@dimen/margin_padding_size_small"
android:background="@android:color/transparent"
android:drawableStart="@drawable/ic_envelope"
android:drawableLeft="@drawable/ic_envelope"
android:drawablePadding="4dp"
android:gravity="center_vertical"
android:hint="@string/email_hint"
android:maxLines="1"
android:textColorHint="@color/colorHintText"
android:inputType="textEmailAddress"/>

Now I was writing UI tests using the Espresso library and it cannot type text into this EditText using typeText() or typeTextIntoFocusedView() and my test method is:

 @Test
    public void onSubmitClickedWithAnInvalidEmail(){
        onView(withId(R.id.et_email)).perform(scrollTo(), click(), typeText("test")); //invalid email
        onView(withId(R.id.btn_submit)).perform(click());
        onView(withId(R.id.et_email)).check(matches(hasErrorText(mActivityTestRule.getActivity().getString(R.string.invalid_email_prompt))));
    }

The test runs but cannot type into the email edittext. It gets stuck after scrolling to and clicking on the EditText. One thing that I noticed is that my email addresses are suggested on the email EditText by google in a Spinner looking thing. I strongly think that is the reason why espresso is not able to type into the EditText.

The message that I get in the Run is:


java.lang.RuntimeException: Waited for the root of the view hierarchy to have window focus and not request layout for 10 seconds. If you specified a non default root matcher, it may be picking a root that never takes focus. Root:
Root{application-window-token=android.view.ViewRootImpl$W@d881111, window-token=android.view.ViewRootImpl$W@d881111, has-window-focus=false, layout-params-type=1, layout-params-string={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=true, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}}
at androidx.test.espresso.base.RootViewPicker.waitForRootToBeReady(RootViewPicker.java:111)
at androidx.test.espresso.base.RootViewPicker.pickRootView(RootViewPicker.java:149)
at androidx.test.espresso.base.RootViewPicker.get(RootViewPicker.java:91)
at androidx.test.espresso.ViewInteractionModule.provideRootView(ViewInteractionModule.java:77)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.provideRootView(ViewInteractionModule_ProvideRootViewFactory.java:37)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:27)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:10)
at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:63)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:223)
at androidx.test.espresso.ViewInteraction.access$100(ViewInteraction.java:65)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:158)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:155)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

EDIT:

Test method

@Test
    public void onSubmitClickedWithAnInvalidEmail() {
        onView(withId(R.id.et_email)).perform(scrollTo(), typeText("test")); //invalid email
        onView(withId(R.id.btn_submit)).perform(click());
        onView(withId(R.id.et_email)).check(matches(hasErrorText(mActivityTestRule.getActivity().getString(R.string.invalid_email_prompt))));
    }

Error Log:

androidx.test.espresso.PerformException: Error performing 'type text(test)' on view 'with id: com.example.myapp:id/et_email'.
at androidx.test.espresso.PerformException$Builder.build(PerformException.java:86)
at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:87)
at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:59)
at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:322)
at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:178)
at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:119)
at com.exmple.myapp.activities.ForgotPasswordActivityTest.onSubmitClickedWithAnInvalidEmail(ForgotPasswordActivityTest.java:45)
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:392)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2337)
Caused by: androidx.test.espresso.InjectEventSecurityException: java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
at androidx.test.espresso.base.InputManagerEventInjectionStrategy.injectKeyEvent(InputManagerEventInjectionStrategy.java:119)
at androidx.test.espresso.base.EventInjector.injectKeyEvent(EventInjector.java:88)
at androidx.test.espresso.base.UiControllerImpl$2.call(UiControllerImpl.java:192)
at androidx.test.espresso.base.UiControllerImpl$2.call(UiControllerImpl.java:189)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
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:764)
Caused by: java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission
at android.os.Parcel.createException(Parcel.java:1950)
at android.os.Parcel.readException(Parcel.java:1918)
at android.os.Parcel.readException(Parcel.java:1868)
at android.hardware.input.IInputManager$Stub$Proxy.injectInputEvent(IInputManager.java:575)
at android.hardware.input.InputManager.injectInputEvent(InputManager.java:880)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.test.espresso.base.InputManagerEventInjectionStrategy.injectKeyEvent(InputManagerEventInjectionStrategy.java:113)
... 9 more
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.input.InputManagerService.injectInputEventInternal(InputManagerService.java:627)
at com.android.server.input.InputManagerService.injectInputEvent(InputManagerService.java:601)
at android.hardware.input.IInputManager$Stub.onTransact(IInputManager.java:143)
at android.os.Binder.execTransact(Binder.java:752)

Please suggest some workaround or point if I am doing something wrong. thanks.


Solution

  • Seems like the typeText() is blocked by the Google Autofill Service. And removing typeText() and using replaceText() actually works here. But the thing you would want to do is to disable Google Autofill Service from the Settings of your device.