-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
[WiP] feat: add device.backdoor() API #4208
base: master
Are you sure you want to change the base?
Conversation
Fixes running tests on MacOS due to this bug: raphw/byte-buddy#732
This makes it possible for tests to send arbitrary messages to the app being tested for the purpose of configuring state or running any other special actions. Usage inside a test looks like: await device.backdoor({ action: "do-something" }); Then receive the event in a React Native app: const emitter = Platform.OS === "ios" ? NativeAppEventEmitter : DeviceEventEmitter; emitter.addListener("detoxBackdoor", ({ action }) => { // do something based on action }); Inspired by a similar feature in the Xamarin test framework: https://docs.microsoft.com/en-us/appcenter/test-cloud/frameworks/uitest/features/backdoors
Okay, so far, I have studied the existing concerns from the team about the previous attempt to introduce Backdoor API. The following points have been raised:
On the contrary, this is a very accurate name because it reminds the user about the danger of leaving any detoxBackdoor listeners in the production code. See the danger admonition from the updated Mocking guide:
Let's go to another point.
This makes sense to me – such functionality would be valuable. On the other hand, I don't view this as a critical flaw but as a minor shortcoming acceptable for Phase 1. Since any consequent activity like re-rendering, network requests, timers, etc., falls under the general synchronization handling in Detox, I doubt that we'll see any new idling timeouts due to the backdoor mechanism. What I did is that I limited the action handlers to "single per action". This limitation is enough to be forward-compatible with Phase 2. For users who need broadcasts (one-to-many), there are action listeners to add and remove. |
This is a really good idea, and will simplify certain flows. We are using a similar flow, but we also expect data from the application and use it throughout the test. Application I'm working on is white label, and tests are running on multiple prod environments that have different config. While some parts can use mock files, I'm wondering if this backdoor action could also help us get data back into Detox. I see this PR sends data to the RN app, but could it be modified to receive data as well? |
This comment was marked as outdated.
This comment was marked as outdated.
I'll take it for the next sprint – hopefully I'll be able to set up https://github.com/wix-incubator/wml with our e2e project. |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
It seems there is a simpler solution nowadays to this: https://metrobundler.dev/docs/configuration/#unstable_enablesymlinks-experimental |
I managed to revive the Metro bundler, but @d4vidi @asafkorem it looks like this call is outdated and won't work with the new React Native: + (void)emitBackdoorEvent:(id)data
{
if([DTXReactNativeSupport hasReactNative] == NO)
{
return;
}
id<RN_RCTBridge> bridge = [NSClassFromString(@"RCTBridge") valueForKey:@"currentBridge"];
[bridge enqueueJSCall:@"RCTNativeAppEventEmitter" method:@"emit" args:@[@"detoxBackdoor", data] completion:nil];
} Maybe we need to find direct way to call emit in the emitter, without the bridge. 🤔 I have to stop again here. |
Hello @noomorph, this solution is very cool, do you know if this works in RN 0.71? I'm desperate for something like this, to be able to control my testing without a bunch of flags inside my app. |
@renatop7 , just as we are speaking, my colleague @andrey-wix is working on this pull request right now. I hope you will see it soon. P. S. As for RN71, yes, it worked, but I don't recommend to recompile/patch unless you are very proficient in these things. |
@noomorph that's awesome! I'll wait then, hope to see it soon as well :) |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
🚨 Blockers🚨 (why it is WiP)
The underlying mechanisms seem to have changed, and this PR does not work already with RN73. 😢
Description
This is a revived pull request by @codebutler (#3245). All props go to him. 🏆
Inspired by functionality in the Xamarin test framework, this PR proposes a new API within Detox to allow tests to send messages or commands directly to the app, modifying its state during runtime without UI interactions.
The "Detox as a platform" vision discussed in issue #207 underlines the potential benefits and use cases of enabling dynamic behaviours and state manipulations during test executions. The Backdoor API is a step in this direction, providing a mechanism for tests to instruct internal changes within the app from E2E tests dynamically.
Implementation:
A simple API call within a test sends a specific action to the app.
The message should be an object with
action
property and any other custom data:On the application side, you have to implement a handler for the backdoor message, e.g.:
Use Case Example
Using the Backdoor API, we can mock time from a Detox test, assuming the app takes the current time indirectly from a time service which has a mocked counterpart (see the guide), e.g.:
src/services/TimeService.ts
src/services/TimeService.e2e.ts
From a Detox test, this may look like:
Assuming the
TimeService
provides the current time vianow()
method, the mockedTimeService.e2e.ts
will be listening toset-mock-time
actions and return the received time value in itsnow()
implementation:This allows any test to dynamically set the time to a desired value, thereby controlling the app behaviour for precise testing scenarios without multiple compiled app variants or complex mock server setups.
If you still would like to have multiple listeners for the same action, you can use the
detoxBackdoor.addActionListener
method instead:The weaker side of action listeners is that they will never be able to return a value to the caller by design.
Further development
While this PR introduces the ability to send instructions from tests to the app, it lacks bi-directional communication, enabling the app to report state or responses back to the executing test. This can be a future development vector for this feature.
Here's a draft version of the future BackdoorEmitter (omitting listeners and non-relevant code):
As you can see, the missing part to finish it on the native side is to tap on the
detoxBackdoorResult
events and wait for them before returning the result to the Detox tester (client).Summary
This PR facilitates dynamic mocking and state configuration during Detox test runs, enhancing testing capability and flexibility. Feedback, especially regarding practical use cases and potential improvements, is welcomed.
It can give a simple enough solution for many support requests like in #4088, #4207, #3986 and others.