14

Problem

We have a quite complex application and we don't want in each test case to go through the whole process to get to specific screen to test it, alternatively we just want to jump to specific one with some state stored in redux store.


What I've tried

I made multiple initial states which loads specific screen so I can test it directly and for each run of detox test I load different mocha.opts to select this portion of test cases and used 'react-native-config' so I can load different state in each run so for example for loading a screen I will do the following:

  1. Create initialState for redux store that has all the details of the screen I'm currently testing.
  2. Create mocha.opts to run only this test case by specifying the -f flag in it.
  3. Create .env.test.screenX file which will tell the store which initial state to load according to which ENVFILE I select.
  4. Create different configuration to each screen in detox so it can load the correct mocha opts through the detox CLI.
  5. each time I run the command ENVFILE=env.test.screenX react-native run-ios so the project would be built using this configuration and I can then run the detox test -c .

Question

My method is so complex and require alot of setup and overhead to run test for each screen so I was wondering if any one had the same issue and how could I solve it? In general how can I deal with the react native thread in detox?

AFGhazy
  • 151
  • 7
  • Don't really have experience with react-native and detox. But in normal react/redux apps you just mock the redux store in each test case with the state you need. Any reason this can't be solved on a test case level only in your setup? – timotgl Mar 17 '18 at 12:51
  • You can mock your state using Detox as well. Read our documentation on mocking. – Leo Natan Mar 21 '18 at 13:31
  • @LeoNatan could you please provide me with specific link for my case, thanks in advance. – AFGhazy Mar 21 '18 at 13:33
  • 3
    It's right there, in the documentation: https://github.com/wix/detox/blob/master/docs/Guide.Mocking.md I have no specific info for your case. Use the recommended APIs to achieve what you want. – Leo Natan Mar 21 '18 at 13:36
  • ok but what if I want multiple e2e files for each testing scenario is that doable @LeoNatan – AFGhazy Mar 23 '18 at 13:38

2 Answers2

7

I think there is no way detox can communicate with react native thread in runtime and change state, so I thought of a little hack that uses mocking technique as Leo Natan mentioned, it could be useful in your case

you could mock your App.js file with a screen (App.e2e.js) that has some buttons with known testIDs each button dispatch all the actions needed to load a specific state to store, you can start each test suite by pressing one of the buttons in the beforeEach method then you can start your normal test flow after that

for example:

if you want to test a screen that is far away (requires too many clicks to reach when the user actually use the app) and requires authentication you could have the following structure:

App.e2e.js has 2 buttons:

  • one for authentication that dispatch an action like onAuthenticationSuccess(user, authToken)
  • another one for navigation to that screen this.navigation.navigate("screenName")

test.js

describe("Screen work as intended", () => {
  beforeEach(async () => {
    await device.reloadReactNative();
    await element(by.id("authButtonID")).tap();
    await element(by.id("navigateButtonID")).tap();
  });

  it("should do something", async () => {
    //user is loaded in store
    //current screen is the screen you want to test
  });
});
mina sameh
  • 1,019
  • 7
  • 18
0

If you are using Expo and it's release-channels for specifying the environment, here is what you could do:

  1. Create a method resetStorage like suggested here: How to reset the state of a Redux store? (which you could have already implemented in logout)
  2. In App.js import resetStorage method
  3. In App.js add: import { Constants } from 'expo'
  4. Then add a button with testID="resetStorageBtn" to your render method which you can use for testing purposes and which won't be visible in production release-channel. So render might look similar to this:

    return (
      <Root>
        {Constants.manifest.releaseChannel !== 'production' &&
            (<View>
              <Button onPress={() => resetStorage()} testID="resetStorageBtn">
                <Text>Reset storage</Text>
              </Button>
            </View>
          )}
        <View>
          <AppNavigator />
        </View>
      </Root>
    );
    
Ilarion Halushka
  • 1,274
  • 12
  • 9