Detox: toHaveValue() for Switch does not match the view on Android

Created on 25 Mar 2020  路  7Comments  路  Source: wix/Detox

Describe the bug
await expect(element(by.id('passcode-switch'))).toHaveValue('0');

causes the following error

androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: '(with content description text: is "0" and view has effective visibility=VISIBLE)' doesn't match the selected view.
    Expected: (with content description text: is "0" and view has effective visibility=VISIBLE)
         Got: "ReactSwitch{id=3503, visibility=VISIBLE, width=122, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.view.ViewGroup$LayoutParams@36b9888, tag=passcode-switch, root-is-layout-requested=false, has-input-connection=false, x=874.0, y=21.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false}"

        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1536)
        at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:96)
        at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:59)
        at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:324)
        at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:306)
        at com.wix.detox.espresso.DetoxAssertion.assertMatcher(DetoxAssertion.java:32)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:443)
        at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:405)
        at com.wix.invoke.types.ClassTarget.execute(ClassTarget.java:23)
        at com.wix.invoke.types.Target.invoke(Target.java:59)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:35)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:26)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:20)
        at com.wix.detox.InvokeActionHandler.handle(DetoxActionHandlers.kt:52)
        at com.wix.detox.DetoxManager$4.run(DetoxManager.java:121)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at com.wix.detox.Detox$1.run(Detox.java:135)
        at java.lang.Thread.run(Thread.java:764)
    Caused by: junit.framework.AssertionFailedError: '(with content description text: is "0" and view has effective visibility=VISIBLE)' doesn't match the selected view.
    Expected: (with content description text: is "0" and view has effective visibility=VISIBLE)
         Got: "ReactSwitch{id=3503, visibility=VISIBLE, width=122, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.view.ViewGroup$LayoutParams@36b9888, tag=passcode-switch, root-is-layout-requested=false, has-input-connection=false, x=874.0, y=21.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false}"

        at androidx.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:540)
        at com.wix.detox.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:52)
        at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:425)
        at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:288)
        at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:272)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

To Reproduce

  • [x] I have tested this issue on the latest Detox release and it still reproduces

Steps to reproduce:

  1. Create simple component
import React from 'react';
import { Switch as ReactSwitch } from 'react-native';
class PasscodeSwitch extends React.Component {
  render() {
    return (
       <ReactSwitch
         testID="passcode-switch"
         value={false}
       />
    )
  }
}
  1. Create a test switch.spec.js
describe('Switch', () => {
  it('should check if the Switch is OFF', async () => {
    await expect(element(by.id('passcode-switch'))).toHaveValue('0');
  })
})
  1. Run the test
    npx detox test -l verbose --configuration android.emu.debug --findRelatedTests 'e2e/switch.spec.js'

Expected behavior
The test should pass

Screenshots
N/A

Device and Verbose Detox Logs

logcat log

03-25 16:41:14.579 19875 19952 I DetoxManager: onAction: type: invoke params: {"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxAssertion"},"method":"assertMatcher","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"androidx.test.espresso.Espresso"},"method":"onView","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForTestId","args":["passcode-switch"]}}]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForContentDescription","args":["0"]}}]}
03-25 16:41:14.579 19875 19930 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForTestId, [passcode-switch]
03-25 16:41:14.579 19875 19930 D Detox   : class androidx.test.espresso.Espresso, onView, [(with tag value: is "passcode-switch" and view has effective visibility=VISIBLE)]
03-25 16:41:14.580 19875 19930 D Detox   : class com.wix.detox.espresso.DetoxMatcher, matcherForContentDescription, [0]
03-25 16:41:14.580 19875 19930 D Detox   : class com.wix.detox.espresso.DetoxAssertion, assertMatcher, [androidx.test.espresso.ViewInteraction@537ac2b, (with content description text: is "0" and view has effective visibility=VISIBLE)]
03-25 16:41:14.582 19875 19875 I ViewInteraction: Checking 'MatchesViewAssertion(Detox){viewMatcher=(with content description text: is "0" and view has effective visibility=VISIBLE)}' assertion on view (with tag value: is "passcode-switch" and view has effective visibility=VISIBLE)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: Exception
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: java.lang.reflect.InvocationTargetException
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at java.lang.reflect.Method.invoke(Native Method)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:443)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:405)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.invoke.types.ClassTarget.execute(ClassTarget.java:23)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.invoke.types.Target.invoke(Target.java:59)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:35)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:26)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:20)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.detox.InvokeActionHandler.handle(DetoxActionHandlers.kt:52)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.detox.DetoxManager$4.run(DetoxManager.java:121)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.os.Handler.handleCallback(Handler.java:789)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.os.Handler.dispatchMessage(Handler.java:98)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.os.Looper.loop(Looper.java:164)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.detox.Detox$1.run(Detox.java:135)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at java.lang.Thread.run(Thread.java:764)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: Caused by: androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: '(with content description text: is "0" and view has effective visibility=VISIBLE)' doesn't match the selected view.
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: Expected: (with content description text: is "0" and view has effective visibility=VISIBLE)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:      Got: "ReactSwitch{id=3503, visibility=VISIBLE, width=122, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.view.ViewGroup$LayoutParams@36b9888, tag=passcode-switch, root-is-layout-requested=false, has-input-connection=false, x=874.0, y=21.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false}"
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: 
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at dalvik.system.VMStack.getThreadStackTrace(Native Method)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at java.lang.Thread.getStackTrace(Thread.java:1536)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:96)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:59)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:324)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:306)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.detox.espresso.DetoxAssertion.assertMatcher(DetoxAssertion.java:32)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   ... 15 more
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: Caused by: junit.framework.AssertionFailedError: '(with content description text: is "0" and view has effective visibility=VISIBLE)' doesn't match the selected view.
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: Expected: (with content description text: is "0" and view has effective visibility=VISIBLE)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:      Got: "ReactSwitch{id=3503, visibility=VISIBLE, width=122, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.view.ViewGroup$LayoutParams@36b9888, tag=passcode-switch, root-is-layout-requested=false, has-input-connection=false, x=874.0, y=21.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=false}"
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers: 
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:540)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.wix.detox.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:52)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:425)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:288)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:272)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at java.util.concurrent.FutureTask.run(FutureTask.java:266)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.os.Handler.handleCallback(Handler.java:789)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.os.Handler.dispatchMessage(Handler.java:98)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.os.Looper.loop(Looper.java:164)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at android.app.ActivityThread.main(ActivityThread.java:6541)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at java.lang.reflect.Method.invoke(Native Method)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
03-25 16:41:14.584 19875 19930 E DetoxActionHandlers:   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

Environment (please complete the following information):

  • Detox: 16.0.1
  • React Native: 0.61.5
  • Node: 12.8.0
  • Device: Pixel_2_API_28 emulator
  • OS: Android
  • Test-runner jest
acceptebug android 馃搶 pinned

Most helpful comment

I can confirm though that the test below works on iOS, or at least doesn't throw an error

describe('Switch', () => {
  it('should check if the Switch is OFF', async () => {
    await expect(element(by.id('passcode-switch'))).toHaveValue('0');
  })
})

All 7 comments

@rotemmiz I see the test was disabled even for iOS: https://github.com/wix/detox/blob/63e5310752ecf099bb19c4fb35b3eea1d5128cf7/detox/test/e2e/04.assertions.test.js#L39

Are you familiar with the history here? Is this indeed a bug?

I think we should direct the question at @LeoNatan , seems like he was the one to skip this.
Although this is not related to Android, not sure why it is disabled for Android.

The test was killed on iOS due to a bug in react native.

https://github.com/facebook/react-native/issues/28032

On Android, toHaveValue() is wired to a matcher over the View's content-description. Does that make sense?

I can confirm though that the test below works on iOS, or at least doesn't throw an error

describe('Switch', () => {
  it('should check if the Switch is OFF', async () => {
    await expect(element(by.id('passcode-switch'))).toHaveValue('0');
  })
})

Same issue. The assertion works on IOS but I get the following error on Android on a Switch that has value set to true.

androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: '(with content description text: is "1" and view has effective visibility=VISIBLE)' doesn't match the selected view.
    Expected: (with content description text: is "1" and view has effective visibility=VISIBLE)
         Got: "ReactSwitch{id=4357, visibility=VISIBLE, width=122, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.view.ViewGroup$LayoutParams@70963a9, tag=toggle-notifications-switch, root-is-layout-requested=false, has-input-connection=false, x=904.0, y=771.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=true}"

        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1720)
        at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:96)
        at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:59)
        at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:324)
        at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:306)
        at com.wix.detox.espresso.DetoxAssertion.assertMatcher(DetoxAssertion.java:32)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:443)
        at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:405)
        at com.wix.invoke.types.ClassTarget.execute(ClassTarget.java:23)
        at com.wix.invoke.types.Target.invoke(Target.java:59)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:35)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:26)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:20)
        at com.wix.detox.InvokeActionHandler.handle(DetoxActionHandlers.kt:52)
        at com.wix.detox.DetoxManager$4.run(DetoxManager.java:121)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at com.wix.detox.Detox$1.run(Detox.java:135)
        at java.lang.Thread.run(Thread.java:919)
    Caused by: junit.framework.AssertionFailedError: '(with content description text: is "1" and view has effective visibility=VISIBLE)' doesn't match the selected view.
    Expected: (with content description text: is "1" and view has effective visibility=VISIBLE)
         Got: "ReactSwitch{id=4357, visibility=VISIBLE, width=122, height=71, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.view.ViewGroup$LayoutParams@70963a9, tag=toggle-notifications-switch, root-is-layout-requested=false, has-input-connection=false, x=904.0, y=771.0, text=, input-type=0, ime-target=false, has-links=false, is-checked=true}"

        at androidx.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:540)
        at com.wix.detox.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:52)
        at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:425)
        at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:288)
        at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:272)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

    Check device logs for full details!

      114 |     );
      115 | 
    > 116 |     await expect(notificationsSwitch).toHaveValue('1');
          |                                       ^
      117 |     await notificationsSwitch.tap();
      118 |     await expect(notificationsSwitch).toHaveValue('0');
      119 | 

      at Client.execute (../node_modules/detox/src/client/Client.js:92:28)
      at InvocationManager.execute (../node_modules/detox/src/invoke.js:11:39)
      at MatcherAssertionInteraction.execute (../node_modules/detox/src/android/expect.js:128:35)
      at ExpectElement.toHaveValue (../node_modules/detox/src/android/expect.js:296:115)
      at _callee3$ (user-preferences.test.js:116:39)
      at tryCatch (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:45:40)
      at Generator.invoke [as _invoke] (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:274:22)
      at Generator.prototype.<computed> [as next] (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:97:21)
      at tryCatch (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:45:40)
      at invoke (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:135:20)
      at ../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:170:11
      at callInvokeWithMethodAndArg (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:169:16)
      at AsyncIterator.enqueue (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:192:13)
      at AsyncIterator.prototype.<computed> [as next] (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:97:21)
      at Object.exports.async (../node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:219:14)

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you believe the issue is still relevant, please test on the latest Detox and report back.

Thank you for your contributions!

For more information on bots in this reporsitory, read this discussion.

Was this page helpful?
0 / 5 - 0 ratings