12

I'm using Detox to run end to end tests in my React Native project. I'm also using pretender.js to mock my API requests and I'm struggling to find a way to know if the app is currently in "testing" mode.

I was passing an env variable down (and using babel-transform-inline-environment-variables) to tell if I should mock the requests but that breaks shim.js in our release builds.

Is there any way to tell Detox launched the app & is running tests from within the JS? Ideally I'm looking for some sort of variable set at test time or something passed down from the command line (TESTING=true react-native start or __TESTING__)

robdel12
  • 194
  • 1
  • 8

3 Answers3

11

Try using react-native-config. Here is also a good article on Managing Configuration in React Native with react-native-config.

I also gave an answer here animated-button-block-the-detox with working example of how react-native-config can be used to disable looping animations during testing.

The basic idea is that you create .env config files for all your different build environments (development, production, test, etc). These hold your configuration variables that you can access from either Javascript, Objective-C/Swift, or Java.

You then specify which .env config file to use when building your app:

$ ENVFILE=.env.staging react-native run-ios # bash

And this is an example of package.json file where detox uses .env config files for building the app.

"detox": {
  "specs": "e2e",
  "configurations": {
    "ios.sim.release": {
      "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/example.app",
      "build": "ENVFILE=.env.production export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -project ios/example.xcodeproj -scheme example -configuration Release -sdk iphonesimulator -derivedDataPath ios/build",
      "type": "ios.simulator",
      "name": "iPhone 5s, iOS 10.3"
    },
    "ios.sim.test": {
      "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app",
      "build": "ENVFILE=.env.testing xcodebuild -project ios/example.xcodeproj -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build -arch x86_64",
      "type": "ios.simulator",
      "name": "iPhone 5s, iOS 10.3"
    }
  }
}
Antoni4
  • 2,115
  • 20
  • 34
  • santomegonzalo's deleted answer below added an extra step I needed to do: even though I modifiied the build command for the default `ios.sim.debug` configuration, I still had to pass the configuration to detox manually: `detox build --configuration ios.sim.debug` – Josh Justice Jul 06 '18 at 13:48
4

We are taking advantage of the fact detox invokes your binary with --args -detoxServer ... -detoxSessionId ... on the iOS command line and { detoxServer: ..., detoxSessionId: ... } set in InstrumentationRegistry in android.

The way we are currently exposing this to JS is a bit much for a StackOverflow answer, but here's some sample code that along with react native's docs should get you there - for Android:

// This will throw ClassNotFoundException if not running under any test,
// but it still might not be running under Detox
Class<?> instrumentationRegistry = Class.forName("android.support.test.InstrumentationRegistry");
Method getArguments = instrumentationRegistry.getMethod("getArguments");
Bundle argumentsBundle = (Bundle) getArguments.invoke(null);

// Say you're in your BaseJavaModule.getConstants() implementation:
return Collections.<String, Object>singletonMap("isDetox", null != argumentsBundle.getString("detoxServer"));

And on iOS, something like (don't have an Objective-C compiler ATM):

return @{@"isDetox": [[[NSProcessInfo processInfo] arguments] containsObject: @"-detoxServer"]}

Note it's also possible to get detox to add your own arguments with:

detox.init(config, { launchApp: false });
device.launchApp({ newInstance: true, launchArgs: {
  myCustomArg: value,
  ...,
} });

It would be great to get this polished up to a module at some point.

Simon Buchan
  • 11,503
  • 2
  • 42
  • 51
1

Tests/production code that has knowledge of the environment is messy IMO.
The way I recommend doing it is by creating different app flavour for testing.

If you use React Native, check out react-native-repackager's instructions. Alternatively, Detox docs have that section as well. If you write Java code for Android, use gradle build flavours to create a flavours for testing.

You can find more on how we mock in our E2E suites here.

Rotemmiz
  • 7,625
  • 3
  • 32
  • 36