Repository: wix/Detox
Pull request #2548 (2020-12-22 17:16:59)

Fix timeline scale: us to ms
## Description

Fix time-line artifact's scale of timestamps - `x1000` (i.e. so as to have events taking 100ms show as 100ms rather than 100us).


Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug-report---android.md b/.github/ISSUE_TEMPLATE/bug-report---android.md
index 2ae0dcd31..602b7c9c1 100644
--- a/.github/ISSUE_TEMPLATE/bug-report---android.md
+++ b/.github/ISSUE_TEMPLATE/bug-report---android.md
@@ -35,10 +35,9 @@ If possible, please provide a small demo project that reproduces the issue, or a
 
 **Device and Verbose Detox Logs**
 <!--
-IMPORTANT: We will not be able to help out or provide proper analysis without these!
 Provide the device and verbose Detox logs so we can understand what happened.
-*Detox* logs can be obtained by passing the `loglevel` param: `detox test --loglevel trace`.
-*Device* logs can be retrieved from the device manually using `adb logcat`, or if recorded using the `--record-logs all` - the artifacts under the `<project>/artifacts/` folder.
+Detox logs can be obtained by passing the loglevel param: `detox test --loglevel trace`.
+Device logs can be retrieved from the device using `adb logcat`, or if recorded, Detox' artifacts.
 -->
 
 **Environment (please complete the following information):**
diff --git a/README.md b/README.md
index 51d404fa8..f7abad677 100644
--- a/README.md
+++ b/README.md
@@ -62,19 +62,17 @@ The most difficult part of automated testing on mobile is the tip of the testing
 
 ### React Native
 
-Detox is built from the ground up to support React Native projects as well as pure native<sup>*</sup> ones.
+Detox is built from the ground up to support React Native projects as well as pure native ones.
 
 The following React Native versions have been tested:
 
 | iOS    | Android                                                      |
 | ------ | ------------------------------------------------------------ |
 | <=0.63 | <=0.56 - Full support                                        |
-|        | >=0.57 <=0.63 - Visibility edge-case: see this [RN issue](https://github.com/facebook/react-native/issues/23870) |
+|        | >=0.57 <=0.63 - Visibility edge-case: see this [RN issue](https://github.com/facebook/react-native/issues/23870)* |
 
 Future versions are most likely supported, but have not been tested yet. Please open issues if you find specific issues with newer React Native versions.
 
-> \* *Currently, support for **pure-native** Android projects is broken - see issue [#2543](https://github.com/wix/Detox/issues/2543). Note we would appreciate contributions in that area.*
-
 ## Get Started With Detox!
 
 Read the [Getting Started Guide](/docs/Introduction.GettingStarted.md) to get Detox running on your app in less than 10 minutes.
diff --git a/detox/ios/Detox/Invocation/Predicate.swift b/detox/ios/Detox/Invocation/Predicate.swift
index 91fbac034..303984c0a 100644
--- a/detox/ios/Detox/Invocation/Predicate.swift
+++ b/detox/ios/Detox/Invocation/Predicate.swift
@@ -204,7 +204,7 @@ class ValuePredicate : Predicate {
 	]
 	
 	static let translator : [String: String] = [
-		"accessibilityIdentifier": "identifier",
+		"accessibilityIdentifier": "identifier:",
 		"accessibilityLabel": "label",
 		"dtx_text": "text",
 		"accessibilityValue": "value"
diff --git a/detox/package.json b/detox/package.json
index d8e47ea0a..bf4f335e3 100644
--- a/detox/package.json
+++ b/detox/package.json
@@ -1,7 +1,7 @@
 {
   "name": "detox",
   "description": "E2E tests and automation for mobile",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "bin": {
     "detox": "local-cli/cli.js"
   },
diff --git a/detox/src/devices/DeviceRegistry.js b/detox/src/devices/DeviceRegistry.js
index e11a41509..1aeec9f63 100644
--- a/detox/src/devices/DeviceRegistry.js
+++ b/detox/src/devices/DeviceRegistry.js
@@ -3,9 +3,6 @@ const environment = require('../utils/environment');
 const ExclusiveLockfile = require('../utils/ExclusiveLockfile');
 const safeAsync = require('../utils/safeAsync');
 
-const getDeviceEqualsFn = (deviceHandle) => (otherDeviceHandle) => _.isEqual(otherDeviceHandle, deviceHandle);
-const getDeviceDifferFn = (deviceHandle) => (otherDeviceHandle) => !_.isEqual(otherDeviceHandle, deviceHandle);
-
 class DeviceRegistry {
   constructor({ lockfilePath }) {
     /***
@@ -25,31 +22,30 @@ class DeviceRegistry {
   }
 
   /***
-   * @param {string|Function} getDeviceHandle
+   * @param {string|Function} getDeviceId
    * @returns {Promise<string>}
    */
-  async allocateDevice(getDeviceHandle) {
+  async allocateDevice(getDeviceId) {
     return this._lockfile.exclusively(async () => {
-      const deviceHandle = await safeAsync(getDeviceHandle);
-      this._toggleDeviceStatus(deviceHandle, true);
-      return deviceHandle;
+      const deviceId = await safeAsync(getDeviceId);
+      this._toggleDeviceStatus(deviceId, true);
+      return deviceId;
     });
   }
 
   /***
-   * @param {string|Function} getDeviceHandle
+   * @param {string|Function} getDeviceId
    * @returns {void}
    */
-  async disposeDevice(getDeviceHandle) {
+  async disposeDevice(getDeviceId) {
     await this._lockfile.exclusively(async () => {
-      const deviceId = await safeAsync(getDeviceHandle);
+      const deviceId = await safeAsync(getDeviceId);
       this._toggleDeviceStatus(deviceId, false);
     });
   }
 
-  includes(deviceHandle) {
-    const deviceEqualsFn = getDeviceEqualsFn(deviceHandle);
-    return !!_.find(this._lockfile.read(), deviceEqualsFn);
+  includes(deviceId) {
+    return this._lockfile.read().includes(deviceId);
   }
 
   getRegisteredDevices() {
@@ -74,12 +70,11 @@ class DeviceRegistry {
   /***
    * @private
    */
-  _toggleDeviceStatus(deviceHandle, busy) {
-    const deviceDifferFn = getDeviceDifferFn(deviceHandle);
+  _toggleDeviceStatus(deviceId, busy) {
     const state = this._lockfile.read();
     const newState = busy
-      ? _.concat(state, deviceHandle)
-      : _.filter(state, deviceDifferFn);
+      ? _.concat(state, deviceId)
+      : _.without(state, deviceId);
     this._lockfile.write(newState);
   }
 
diff --git a/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.js b/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.js
index 84713181a..4bd081982 100644
--- a/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.js
+++ b/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.js
@@ -1,5 +1,4 @@
 const AndroidDeviceAllocator = require('../AndroidDeviceAllocator');
-const GenyCloudInstanceHandle = require('./GenyCloudInstanceHandle');
 const retry = require('../../../../utils/retry');
 const logger = require('../../../../utils/logger').child({ __filename });
 
@@ -14,10 +13,8 @@ class GenyCloudDeviceAllocator extends AndroidDeviceAllocator {
 
   async _doAllocateDevice(recipe) {
     let { instance, isNew } = await this._doSynchronizedAllocation(recipe);
-    const instanceHandle = new GenyCloudInstanceHandle(instance);
-
     if (isNew) {
-      await this.deviceCleanupRegistry.allocateDevice(instanceHandle);
+      await this.deviceCleanupRegistry.allocateDevice(instance.uuid);
     }
 
     instance = await this._waitForInstanceBoot(instance);
@@ -25,7 +22,7 @@ class GenyCloudDeviceAllocator extends AndroidDeviceAllocator {
     return {
       instance,
       isNew,
-      toString: () => instanceHandle.toString(),
+      toString: () => `GenyCloud:${instance.name} (${instance.uuid})`,
     }
   }
 
diff --git a/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.js b/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.js
index 58b59bed0..abc686067 100644
--- a/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.js
+++ b/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.js
@@ -1,4 +1,3 @@
-const semver = require('semver'); // eslint-disable-line node/no-extraneous-require
 const AndroidDriver = require('../AndroidDriver');
 const GenyCloudDeviceAllocator = require('./GenyCloudDeviceAllocator');
 const GenyDeviceRegistryFactory = require('./GenyDeviceRegistryFactory');
@@ -13,25 +12,23 @@ const DetoxRuntimeError = require('../../../../errors/DetoxRuntimeError');
 const logger = require('../../../../utils/logger').child({ __filename });
 const environment = require('../../../../utils/environment');
 
-const MIN_GMSAAS_VERSION = '1.6.0';
-
 class GenyCloudDriver extends AndroidDriver {
   constructor(config) {
     super(config);
     this._name = 'Unspecified Genymotion Cloud Emulator';
 
-    this._exec = new GenyCloudExec(environment.getGmsaasPath());
+    const exec = new GenyCloudExec(environment.getGmsaasPath());
     const instanceNaming = new InstanceNaming(); // TODO should consider a permissive impl for debug/dev mode. Maybe even a custom arg in package.json (Detox > ... > genycloud > sharedAccount: false)
     this._deviceRegistry = GenyDeviceRegistryFactory.forRuntime();
     this._deviceCleanupRegistry = GenyDeviceRegistryFactory.forGlobalShutdown();
 
-    const recipeService = new RecipesService(this._exec, logger);
-    const instanceLookupService = new InstanceLookupService(this._exec, instanceNaming, this._deviceRegistry);
-    this._instanceLifecycleService = new InstanceLifecycleService(this._exec, instanceNaming);
+    const recipeService = new RecipesService(exec, logger);
+    const instanceLookupService = new InstanceLookupService(exec, instanceNaming, this._deviceRegistry);
+    this._instanceLifecycleService = new InstanceLifecycleService(exec, instanceNaming);
     this._deviceQueryHelper = new DeviceQueryHelper(recipeService);
     this._deviceAllocator = new GenyCloudDeviceAllocator(this._deviceRegistry, this._deviceCleanupRegistry, instanceLookupService, this._instanceLifecycleService);
 
-    this._authService = new AuthService(this._exec);
+    this._authService = new AuthService(exec);
   }
 
   get name() {
@@ -39,8 +36,7 @@ class GenyCloudDriver extends AndroidDriver {
   }
 
   async prepare() {
-    await this._validateGmsaasVersion();
-    await this._validateGmsaasAuth();
+    return this._validateGmsaasAuth();
   }
 
   async acquireFreeDevice(deviceQuery) {
@@ -87,20 +83,10 @@ class GenyCloudDriver extends AndroidDriver {
     }
   }
 
-  async _validateGmsaasVersion() {
-    const { version } = await this._exec.getVersion();
-    if (semver.lt(version, MIN_GMSAAS_VERSION)) {
-      throw new DetoxRuntimeError({
-        message: `Your Genymotion-Cloud executable (found in ${environment.getGmsaasPath()}) is too old! (version ${version})`,
-        hint: `Detox requires version 1.6.0, or newer. To use 'android.genycloud' type devices, you must upgrade it, first.`,
-      });
-    }
-  }
-
   async _validateGmsaasAuth() {
     if (!await this._authService.getLoginEmail()) {
       throw new DetoxRuntimeError({
-        message: `Cannot run tests using 'android.genycloud' type devices, because Genymotion was not logged-in to!`,
+        message: 'Cannot run tests using a Genymotion-cloud emulator, because Genymotion was not logged-in to!',
         hint: `Log-in to Genymotion-cloud by running this command (and following instructions):\n${environment.getGmsaasPath()} auth login --help`,
       });
     }
@@ -108,11 +94,11 @@ class GenyCloudDriver extends AndroidDriver {
 
   static async globalCleanup() {
     const deviceCleanupRegistry = GenyDeviceRegistryFactory.forGlobalShutdown();
-    const instanceHandles = await deviceCleanupRegistry.readRegisteredDevices();
-    if (instanceHandles.length) {
+    const deviceUUIDs = await deviceCleanupRegistry.readRegisteredDevices();
+    if (deviceUUIDs.length) {
       const exec = new GenyCloudExec(environment.getGmsaasPath());
       const instanceLifecycleService = new InstanceLifecycleService(exec, null);
-      await doCleanup(instanceLifecycleService, instanceHandles);
+      await doCleanup(instanceLifecycleService, deviceUUIDs);
     }
   }
 }
@@ -121,13 +107,13 @@ const cleanupLogData = {
   event: 'GENYCLOUD_TEARDOWN',
 };
 
-async function doCleanup(instanceLifecycleService, instanceHandles) {
+async function doCleanup(instanceLifecycleService, deviceUUIDs) {
   logger.info(cleanupLogData, 'Initiating Genymotion cloud instances teardown...');
 
   const deletionLeaks = [];
-  const killPromises = instanceHandles.map(({ uuid, name }) =>
+  const killPromises = deviceUUIDs.map((uuid) =>
     instanceLifecycleService.deleteInstance(uuid)
-      .catch((error) => deletionLeaks.push({ uuid, name, error })));
+      .catch((error) => deletionLeaks.push({ uuid, error })));
 
   await Promise.all(killPromises);
   reportGlobalCleanupSummary(deletionLeaks);
@@ -137,8 +123,8 @@ function reportGlobalCleanupSummary(deletionLeaks) {
   if (deletionLeaks.length) {
     logger.warn(cleanupLogData, 'WARNING! Detected a Genymotion cloud instance leakage, for the following instances:');
 
-    deletionLeaks.forEach(({ uuid, name, error }) =>
-      logger.warn(cleanupLogData, `Instance ${name} (${uuid}): ${error}`));
+    deletionLeaks.forEach(({ uuid, error }) =>
+      logger.warn(cleanupLogData, `Instance UUID ${uuid}: ${error}`));
 
     logger.info(cleanupLogData, 'Instances teardown completed with warnings');
   } else {
diff --git a/detox/src/devices/drivers/android/genycloud/GenyCloudInstanceHandle.js b/detox/src/devices/drivers/android/genycloud/GenyCloudInstanceHandle.js
deleted file mode 100644
index 2e58c6278..000000000
--- a/detox/src/devices/drivers/android/genycloud/GenyCloudInstanceHandle.js
+++ /dev/null
@@ -1,12 +0,0 @@
-class GenyCloudInstanceHandle {
-  constructor(instance) {
-    this.uuid = instance.uuid;
-    this.name = instance.name;
-  }
-
-  toString() {
-    return `GenyCloud:${this.name} (${this.uuid})`;
-  }
-}
-
-module.exports = GenyCloudInstanceHandle;
diff --git a/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.js b/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.js
index 4a164f0aa..84a8cd2e0 100644
--- a/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.js
+++ b/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.js
@@ -5,24 +5,16 @@ class GenyCloudExec {
     this.binaryExec = `"${binaryPath}" --format compactjson`;
   }
 
-  getVersion() {
-    return this._exec('--version');
-  }
-
   whoAmI() {
-    return this._exec('auth whoami');
+    return this._exec(`auth whoami`);
   }
 
   getRecipe(name) {
     return this._exec(`recipes list --name "${name}"`);
   }
 
-  getInstance(instanceUUID) {
-    return this._exec(`instances get ${instanceUUID}`);
-  }
-
   getInstances() {
-    return this._exec('instances list -q');
+    return this._exec(`instances list -q`);
   }
 
   startInstance(recipeUUID, instanceName) {
diff --git a/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.js b/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.js
index e4158b0b1..4d2816035 100644
--- a/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.js
+++ b/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.js
@@ -1,3 +1,4 @@
+const _ = require('lodash');
 const Instance = require('./dto/GenyInstance');
 
 class GenyInstanceLookupService {
@@ -13,8 +14,8 @@ class GenyInstanceLookupService {
   }
 
   async getInstance(instanceUUID) {
-    const { instance } = await this.genyCloudExec.getInstance(instanceUUID);
-    return new Instance(instance);
+    const instances = await this._getAllInstances();
+    return _.find(instances, (instance) => instance.uuid === instanceUUID);
   }
 
   async _getRelevantInstances() {
diff --git a/detox/src/devices/drivers/android/genycloud/services/dto/GenyInstance.js b/detox/src/devices/drivers/android/genycloud/services/dto/GenyInstance.js
index a84e741b9..307c03b3a 100644
--- a/detox/src/devices/drivers/android/genycloud/services/dto/GenyInstance.js
+++ b/detox/src/devices/drivers/android/genycloud/services/dto/GenyInstance.js
@@ -1,3 +1,4 @@
+const _ = require('lodash');
 const Recipe = require('./GenyRecipe');
 
 const STATE_ONLINE = 'ONLINE';
@@ -12,9 +13,7 @@ const initStates = [
 
 class GenyInstance {
   constructor(rawInstance) {
-    this.uuid = rawInstance.uuid;
-    this.name = rawInstance.name;
-    this.state = rawInstance.state;
+    Object.assign(this, _.pick(rawInstance, 'uuid', 'name', 'state'));
     this.adb = {
       name: rawInstance.adb_serial,
       port: rawInstance.adb_serial_port,
diff --git a/detox/src/devices/drivers/android/genycloud/services/dto/GenyRecipe.js b/detox/src/devices/drivers/android/genycloud/services/dto/GenyRecipe.js
index 792d692e2..19d196b75 100644
--- a/detox/src/devices/drivers/android/genycloud/services/dto/GenyRecipe.js
+++ b/detox/src/devices/drivers/android/genycloud/services/dto/GenyRecipe.js
@@ -1,7 +1,8 @@
-class GenyRecipe {
+const _ = require('lodash');
+
+class Recipe {
   constructor(rawRecipe) {
-    this.uuid = rawRecipe.uuid;
-    this.name = rawRecipe.name;
+    Object.assign(this, _.pick(rawRecipe, 'uuid', 'name'));
   }
 
   toString() {
@@ -9,4 +10,4 @@ class GenyRecipe {
   }
 }
 
-module.exports = GenyRecipe;
+module.exports = Recipe;
diff --git a/detox/src/utils/ChromeTracingExporter.js b/detox/src/utils/ChromeTracingExporter.js
index c570ec5ce..84e36fccf 100644
--- a/detox/src/utils/ChromeTracingExporter.js
+++ b/detox/src/utils/ChromeTracingExporter.js
@@ -25,8 +25,8 @@ class ChromeTracingExporter {
   _parseEvent(event) {
     const { name, ts, args, type } = event;
     switch (type) {
-      case 'start': return this._event(name, 'B', ts, args);
-      case 'end': return this._event(name, 'E', ts, args);
+      case 'start': return this._event(name, 'B', ts * 1000, args);
+      case 'end': return this._event(name, 'E', ts * 1000, args);
       case 'init': return [
           this._event('process_name', 'M', ts, { name: this._process.name }),
           this._event('thread_name', 'M', ts, { name: this._thread.name }),
diff --git a/examples/demo-native-android/README.md b/examples/demo-native-android/README.md
index 02f479a3e..2d91d4b66 100644
--- a/examples/demo-native-android/README.md
+++ b/examples/demo-native-android/README.md
@@ -1,6 +1,7 @@
-# Pure Native Android Demo Project
-Currently, support for **pure-native** Android projects is broken - see issue [#2543](https://github.com/wix/Detox/issues/2543).
+> detox
 
-Note we would appreciate contributions in that area.
+# Pure Native Android Demo Project
+Android is not supported in detox yet. 
+This project is here for development purposes and is not working at the moment.
 
 
diff --git a/examples/demo-native-android/package.json b/examples/demo-native-android/package.json
index 6aa17b406..b20db1cc4 100644
--- a/examples/demo-native-android/package.json
+++ b/examples/demo-native-android/package.json
@@ -1,6 +1,6 @@
 {
   "name": "detox-demo-native-android",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "scripts": {
     "packager": "react-native start",
@@ -8,7 +8,7 @@
     "e2e": "mocha e2e --opts ./e2e/mocha.opts"
   },
   "devDependencies": {
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "mocha": "^6.1.3"
   },
   "detox": {}
diff --git a/examples/demo-native-ios/package.json b/examples/demo-native-ios/package.json
index 0e8f00e46..8bb92f978 100644
--- a/examples/demo-native-ios/package.json
+++ b/examples/demo-native-ios/package.json
@@ -1,9 +1,9 @@
 {
   "name": "detox-demo-native-ios",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "devDependencies": {
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "mocha": "^6.1.3"
   },
   "detox": {
diff --git a/examples/demo-plugin/package.json b/examples/demo-plugin/package.json
index e8925399f..c73d13f86 100644
--- a/examples/demo-plugin/package.json
+++ b/examples/demo-plugin/package.json
@@ -1,12 +1,12 @@
 {
   "name": "demo-plugin",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "scripts": {
     "test:plugin": "detox test --configuration plugin -l verbose"
   },
   "devDependencies": {
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "jest": "^26.5.0"
   },
   "detox": {
diff --git a/examples/demo-react-native-detox-instruments/package.json b/examples/demo-react-native-detox-instruments/package.json
index 40172bdc8..9c6318cb3 100644
--- a/examples/demo-react-native-detox-instruments/package.json
+++ b/examples/demo-react-native-detox-instruments/package.json
@@ -1,10 +1,10 @@
 {
   "name": "demo-react-native-detox-instruments",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "scripts": {},
   "devDependencies": {
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "mocha": "6.x.x"
   },
   "detox": {
diff --git a/examples/demo-react-native-jest/package.json b/examples/demo-react-native-jest/package.json
index e9492f7b5..60b5464ee 100644
--- a/examples/demo-react-native-jest/package.json
+++ b/examples/demo-react-native-jest/package.json
@@ -1,6 +1,6 @@
 {
   "name": "demo-react-native-jest",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "scripts": {
     "test:ios-release": "detox test --configuration ios.sim.release -l verbose",
@@ -9,7 +9,7 @@
     "test:android-release-ci": "detox test --configuration android.emu.release -l verbose --workers 2 --headless --record-logs all --take-screenshots all"
   },
   "devDependencies": {
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "jest": "^26.5.0",
     "jest-circus": "^26.5.2",
     "sanitize-filename": "^1.6.1"
diff --git a/examples/demo-react-native/package.json b/examples/demo-react-native/package.json
index ce8b1af29..501c4bf1d 100644
--- a/examples/demo-react-native/package.json
+++ b/examples/demo-react-native/package.json
@@ -1,6 +1,6 @@
 {
   "name": "example",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "scripts": {
     "start": "react-native start",
@@ -23,7 +23,7 @@
     "react-native": "0.62.x"
   },
   "devDependencies": {
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "mocha": "^6.1.3"
   }
 }
diff --git a/lerna.json b/lerna.json
index 4fdb75cc0..48a8aaba9 100644
--- a/lerna.json
+++ b/lerna.json
@@ -13,7 +13,7 @@
     "generation",
     "."
   ],
-  "version": "17.14.6",
+  "version": "17.14.5",
   "npmClient": "npm",
   "command": {
     "publish": {
diff --git a/package.json b/package.json
index 7f7c7e1e1..0e4712306 100644
--- a/package.json
+++ b/package.json
@@ -19,5 +19,5 @@
     "semver": "5.x.x",
     "shell-utils": "1.x.x"
   },
-  "version": "17.14.6"
+  "version": "17.14.5"
 }


Test patch:
diff --git a/detox/src/devices/DeviceRegistry.test.js b/detox/src/devices/DeviceRegistry.test.js
index 06d2fc6d0..e2857ed90 100644
--- a/detox/src/devices/DeviceRegistry.test.js
+++ b/detox/src/devices/DeviceRegistry.test.js
@@ -19,37 +19,37 @@ describe('DeviceRegistry', () => {
       await fs.remove(lockfilePath);
     });
 
-    async function allocateDevice(deviceHandle) {
-      return registry.allocateDevice(() => deviceHandle);
+    async function allocateDevice(deviceId) {
+      return registry.allocateDevice(() => deviceId);
     }
 
-    function expectRegisteredDevices(...deviceHandles) {
+    function expectRegisteredDevices(...deviceIds) {
       return registry.allocateDevice(() => {
-        expect(registry.getRegisteredDevices()).toEqual([ ...deviceHandles ]);
+        expect(registry.getRegisteredDevices()).toEqual([ ...deviceIds ]);
         throw new Error('ignored'); // So it wouldn't really allocate anything
       }).catch((e) => { if (e.message !== 'ignored') throw e });
     }
 
-    async function checkDeviceRegisteredAndDispose(deviceHandle) {
+    async function checkDeviceRegisteredAndDispose(deviceId) {
       return registry.disposeDevice(async () => {
-        expect(registry.includes(deviceHandle)).toBe(true);
-        return deviceHandle;
+        expect(registry.includes(deviceId)).toBe(true);
+        return deviceId;
       });
     }
 
-    async function disposeDevice(deviceHandle) {
-      return registry.disposeDevice(() => deviceHandle);
+    async function disposeDevice(deviceId) {
+      return registry.disposeDevice(() => deviceId);
     }
 
-    async function checkDeviceIsNotRegistered(deviceHandle) {
+    async function checkDeviceNotRegistered(deviceId) {
       return registry.allocateDevice(async () => {
-        expect(registry.includes(deviceHandle)).toBe(false);
+        expect(registry.includes(deviceId)).toBe(false);
         throw new Error('ignored'); // So it wouldn't really allocate anything
       }).catch((e) => { if (e.message !== 'ignored') throw e });
     }
 
-    async function checkRegisteredDevicesEqual(...deviceHandles) {
-      expect(await registry.readRegisteredDevices()).toEqual([ ...deviceHandles ]);
+    async function checkRegisteredDevicesEqual(...deviceIds) {
+      expect(await registry.readRegisteredDevices()).toEqual([ ...deviceIds ]);
     }
 
     const assertForbiddenOutOfContextRegistryQuery = () =>
@@ -59,78 +59,51 @@ describe('DeviceRegistry', () => {
       expect(() => registry.getRegisteredDevices()).toThrowError();
 
     it('should be able to tell whether a device is registered', async () => {
-      const deviceHandle = 'emulator-5554';
-      await allocateDevice(deviceHandle);
-      await checkDeviceRegisteredAndDispose(deviceHandle);
-      await checkDeviceIsNotRegistered(deviceHandle);
-    });
-
-    it('should be able to tell whether a device is registered, given objects for handles', async () => {
-      const rawDeviceHandle = {
-        type: 'mocked-device-type',
-        adbName: 'localhost:11111',
-      };
-      const deviceHandle = {
-        ...rawDeviceHandle,
-        mockFunc: () => 'mocked-func-result',
-      };
-
-      await allocateDevice(deviceHandle);
-      await checkDeviceRegisteredAndDispose(rawDeviceHandle);
-      await checkDeviceIsNotRegistered(deviceHandle);
+      const deviceId = 'emulator-5554';
+      await allocateDevice(deviceId);
+      await checkDeviceRegisteredAndDispose(deviceId);
+      await checkDeviceNotRegistered(deviceId);
     });
 
     it('should throw on attempt of checking whether a device is registered outside of allocation/disposal context', async () => {
-      const deviceHandle = 'emulator-5554';
+      const deviceId = 'emulator-5554';
 
       assertForbiddenOutOfContextRegistryQuery();
 
-      await allocateDevice(deviceHandle);
+      await allocateDevice(deviceId);
       assertForbiddenOutOfContextRegistryQuery();
     });
 
     it('should be able to fast-get a valid list of registered devices', async () => {
-      const deviceHandle = 'emulator-5554';
-      const anotherDeviceHandle = {
+      const deviceId = 'emulator-5554';
+      const anotherDeviceId = {
         type: 'mocked-device-type',
         adbName: 'emulator-5556',
       };
 
-      await allocateDevice(deviceHandle);
-      await allocateDevice(anotherDeviceHandle);
-      await expectRegisteredDevices(deviceHandle, anotherDeviceHandle);
+      await allocateDevice(deviceId);
+      await allocateDevice(anotherDeviceId);
+      await expectRegisteredDevices(deviceId, anotherDeviceId);
     });
 
     it('should throw on attempt of fast-getting registered devices list outside of allocation/disposal context', async () => {
-      const deviceHandle = 'emulator-5554';
+      const deviceId = 'emulator-5554';
 
       assertForbiddenOutOfContextDeviceListQuery();
 
-      await allocateDevice(deviceHandle);
+      await allocateDevice(deviceId);
       assertForbiddenOutOfContextDeviceListQuery();
     });
 
     it('should be able to read a valid list of registered devices', async () => {
-      const deviceHandle = 'emulator-5554';
-      const anotherDeviceHandle = 'emulator-5556';
-
-      await allocateDevice(deviceHandle);
-      await allocateDevice(anotherDeviceHandle);
-      await checkRegisteredDevicesEqual(deviceHandle, anotherDeviceHandle);
-      await disposeDevice(deviceHandle);
-      await checkRegisteredDevicesEqual(anotherDeviceHandle);
-    });
-
-    it('should be able to dispose devices with object-like handles', async () => {
-      const deviceId = {
-        type: 'mocked-device-type',
-        adbName: 'emulator-5554',
-      };
+      const deviceId = 'emulator-5554';
+      const anotherDeviceId = 'emulator-5556';
 
       await allocateDevice(deviceId);
-      await checkRegisteredDevicesEqual(deviceId);
+      await allocateDevice(anotherDeviceId);
+      await checkRegisteredDevicesEqual(deviceId, anotherDeviceId);
       await disposeDevice(deviceId);
-      await checkRegisteredDevicesEqual();
+      await checkRegisteredDevicesEqual(anotherDeviceId);
     });
 
     describe('.reset() method', () => {
diff --git a/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.test.js b/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.test.js
index 61c386760..5ba399705 100644
--- a/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.test.js
+++ b/detox/src/devices/drivers/android/genycloud/GenyCloudDeviceAllocator.test.js
@@ -220,26 +220,6 @@ describe('Genymotion-Cloud device allocator', () => {
     expect(deviceRegistry.allocateDevice).toHaveBeenCalled();
   });
 
-  it('should register a new device for cleanup', async () => {
-    const instance = aFullyConnectedInstance();
-    givenNoFreeInstances();
-    givenCreatedInstance(instance);
-
-    await uut.allocateDevice(aRecipe());
-    expect(deviceCleanupRegistry.allocateDevice).toHaveBeenCalledWith({
-      uuid: instance.uuid,
-      name: instance.name,
-    });
-  });
-
-  it('should not register an existing device for cleanup', async () => {
-    const instance = aFullyConnectedInstance();
-    givenFreeInstance(instance);
-
-    await uut.allocateDevice(aRecipe());
-    expect(deviceCleanupRegistry.allocateDevice).not.toHaveBeenCalled();
-  });
-
   it('should log pre-allocate event', async () => {
     givenFreeInstance(aFullyConnectedInstance());
     await uut.allocateDevice(aRecipe());
diff --git a/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.test.js b/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.test.js
index 983d5b594..d5c69a491 100644
--- a/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.test.js
+++ b/detox/src/devices/drivers/android/genycloud/GenyCloudDriver.test.js
@@ -2,24 +2,6 @@ const _ = require('lodash');
 
 const latestInstanceOf = (clazz) => _.last(clazz.mock.instances);
 
-const MOCK_GMSAAS_PATH = '/path/to/gmsaas';
-
-const aRecipe = () => ({
-  uuid: 'mock-recipe-uuid',
-  name: 'mock-recipe-name',
-  toString: () => 'mock-recipe-toString()-result',
-});
-
-const anInstance = () => ({
-  uuid: 'mock-instance-uuid',
-  name: 'mock-instance-name',
-  adbName: 'mock-instance-adb-name',
-});
-
-const aDeviceQuery = () => ({
-  query: 'mock',
-});
-
 describe('Genymotion-cloud driver', () => {
   class MockInstanceLifecycleService {
     constructor(...args) {
@@ -28,6 +10,23 @@ describe('Genymotion-cloud driver', () => {
     }
   }
 
+  const MOCK_GMSAAS_PATH = '/path/to/gmsaas';
+
+  const aRecipe = () => ({
+    uuid: 'mock-recipe-uuid',
+    name: 'mock-recipe-name',
+    toString: () => 'mock-recipe-toString()-result',
+  });
+
+  const anInstance = () => ({
+    uuid: 'mock-instance-uuid',
+    adbName: 'mock-instance-adb-name',
+  });
+
+  const aDeviceQuery = () => ({
+    query: 'mock',
+  });
+
   beforeEach(mockBaseClassesDependencies);
   beforeEach(mockDirectDependencies);
 
@@ -37,7 +36,6 @@ describe('Genymotion-cloud driver', () => {
   let environment;
   let adbObj;
   let Exec;
-  let execObj;
   let deviceQueryHelper;
   let deviceRegistry;
   let deviceCleanupRegistry;
@@ -59,7 +57,6 @@ describe('Genymotion-cloud driver', () => {
     adbObj = () => latestInstanceOf(ADB);
 
     Exec = require('./exec/GenyCloudExec');
-    execObj = () => latestInstanceOf(Exec);
 
     const GenyDeviceRegistryFactory = require('./GenyDeviceRegistryFactory');
     const DeviceRegistry = jest.genMockFromModule('../../../DeviceRegistry');
@@ -111,67 +108,21 @@ describe('Genymotion-cloud driver', () => {
     });
 
     describe('preparation', () => {
-      const givenProperGmsaasLogin = () => authServiceObj().getLoginEmail.mockResolvedValue('detox@wix.com');
-      const givenGmsaasLoggedOut = () => authServiceObj().getLoginEmail.mockResolvedValue(null);
-      const givenGmsaasExecVersion = (version) => execObj().getVersion.mockResolvedValue({ version });
-      const givenProperGmsaasExecVersion = () => givenGmsaasExecVersion('1.6.0');
-
-      it('should throw an error if gmsaas exec is too old (minor version < 6)', async () => {
-        givenProperGmsaasLogin();
-        givenGmsaasExecVersion('1.5.9');
-
-        try {
-          await uut.prepare();
-          fail('Expected an error');
-        } catch (e) {
-          expect(e.constructor.name).toEqual('DetoxRuntimeError');
-          expect(e.toString()).toContain(`Your Genymotion-Cloud executable (found in ${MOCK_GMSAAS_PATH}) is too old! (version 1.5.9)`);
-          expect(e.toString()).toContain(`HINT: Detox requires version 1.6.0, or newer. To use 'android.genycloud' type devices, you must upgrade it, first.`);
-        }
-      });
-
-      it('should accept the gmsaas exec if version is sufficiently new', async () => {
-        givenProperGmsaasLogin();
-        givenGmsaasExecVersion('1.6.0');
-        await uut.prepare();
-      });
-
-      it('should accept the gmsaas exec if version is more than sufficiently new', async () => {
-        givenProperGmsaasLogin();
-        givenGmsaasExecVersion('1.7.2');
-        await uut.prepare();
-      });
-
-      it('should throw an error if gmsaas exec is too old (major version < 1)', async () => {
-        givenProperGmsaasLogin();
-        givenGmsaasExecVersion('0.6.0');
-
-        try {
-          await uut.prepare();
-          fail('Expected an error');
-        } catch (e) {
-          expect(e.toString()).toContain(`Your Genymotion-Cloud executable (found in ${MOCK_GMSAAS_PATH}) is too old! (version 0.6.0)`);
-        }
-      });
-
-      it('should throw an error if not logged-in to gmsaas', async () => {
-        givenProperGmsaasExecVersion();
-        givenGmsaasLoggedOut();
+      it('should throw error if not logged-in to gmsaas', async () => {
+        authServiceObj().getLoginEmail.mockResolvedValue(null);
 
         try {
           await uut.prepare();
           fail('Expected an error');
         } catch (e) {
           expect(e.constructor.name).toEqual('DetoxRuntimeError');
-          expect(e.toString()).toContain(`Cannot run tests using 'android.genycloud' type devices, because Genymotion was not logged-in to!`);
+          expect(e.toString()).toContain('Cannot run tests using a Genymotion-cloud emulator, because Genymotion was not logged-in to!');
           expect(e.toString()).toContain(`HINT: Log-in to Genymotion-cloud by running this command (and following instructions):\n${MOCK_GMSAAS_PATH} auth login --help`);
         }
       });
 
       it('should not throw an error if properly logged in to gmsaas', async () => {
-        givenProperGmsaasExecVersion();
-        givenProperGmsaasLogin();
-
+        authServiceObj().getLoginEmail.mockResolvedValue('detox@wix.com');
         await uut.prepare();
       });
     });
@@ -190,10 +141,10 @@ describe('Genymotion-cloud driver', () => {
         const deviceQuery = aDeviceQuery();
         const result = await uut.acquireFreeDevice(deviceQuery);
 
-        expect(result).toEqual(expect.objectContaining({
+        expect(result).toEqual({
           adbName: instance.adbName,
           uuid: instance.uuid,
-        }));
+        });
         expect(deviceQueryHelper().getRecipeFromQuery).toHaveBeenCalledWith(deviceQuery);
         expect(deviceAllocator().allocateDevice).toHaveBeenCalledWith(recipe);
       });
@@ -375,39 +326,34 @@ describe('Genymotion-cloud driver', () => {
     });
 
     describe('global clean-up', () => {
-      const givenDeletionPendingDevices = (devicesHandles) => deviceCleanupRegistry.readRegisteredDevices.mockResolvedValue(devicesHandles);
+      const givenDeletionPendingDevices = (deviceUUIDs) => deviceCleanupRegistry.readRegisteredDevices.mockResolvedValue(deviceUUIDs);
       const givenNoDeletionPendingDevices = () => givenDeletionPendingDevices([]);
-      const givenDeletionPendingInstances = (instances) => givenDeletionPendingDevices( _.map(instances, ({ uuid, name }) => ({ uuid, name }) ));
+      const givenDeletionPendingInstances = (instances) => givenDeletionPendingDevices(_.map(instances, 'uuid'));
       const givenDeletionResult = (deletedInstance) => instanceLifecycleService.deleteInstance.mockResolvedValue(deletedInstance);
 
-      const anAssertablePendingPromise = () => {
+      const assertablePendingPromise = () => {
         let promiseAck = jest.fn();
         const promise = new Promise(resolve => setTimeout(resolve, 1)).then(promiseAck);
         promise.assertResolved = () => expect(promiseAck).toHaveBeenCalled();
         return promise;
       };
 
-      const aPendingDevice = (name, uuid) => ({ name, uuid });
-
       it('should kill all deletion-pending device', async () => {
-        const killPromise1 = anAssertablePendingPromise();
-        const killPromise2 = anAssertablePendingPromise();
+        const killPromise1 = assertablePendingPromise();
+        const killPromise2 = assertablePendingPromise();
         instanceLifecycleService.deleteInstance
           .mockReturnValueOnce(killPromise1)
           .mockReturnValueOnce(killPromise2);
 
-        const deviceHandles = [
-          aPendingDevice('device1', 'uuid1'),
-          aPendingDevice('device2', 'uuid2'),
-        ];
-        givenDeletionPendingDevices(deviceHandles);
+        const deviceUUIDs = ['device1-uuid', 'device2-uuid'];
+        givenDeletionPendingDevices(deviceUUIDs);
 
         await GenyCloudDriver.globalCleanup();
 
         killPromise1.assertResolved();
         killPromise2.assertResolved();
-        expect(instanceLifecycleService.deleteInstance).toHaveBeenCalledWith('uuid1');
-        expect(instanceLifecycleService.deleteInstance).toHaveBeenCalledWith('uuid2');
+        expect(instanceLifecycleService.deleteInstance).toHaveBeenCalledWith(deviceUUIDs[0]);
+        expect(instanceLifecycleService.deleteInstance).toHaveBeenCalledWith(deviceUUIDs[1]);
       });
 
       it('should warn of instances deletion rejects', async () => {
@@ -416,17 +362,13 @@ describe('Genymotion-cloud driver', () => {
           .mockResolvedValueOnce(anInstance())
           .mockRejectedValueOnce(new Error('mock-error2'));
 
-        givenDeletionPendingDevices([
-          aPendingDevice('failing1', 'uuid1'),
-          aPendingDevice('nonfailing', 'uuid'),
-          aPendingDevice('failing2', 'uuid2'),
-        ]);
+        givenDeletionPendingDevices(['failing-uuid1', 'nonfailing-uuid', 'failing-uuid2']);
 
         await GenyCloudDriver.globalCleanup();
 
         expect(logger.warn).toHaveBeenCalledWith({ event: 'GENYCLOUD_TEARDOWN' }, 'WARNING! Detected a Genymotion cloud instance leakage, for the following instances:');
-        expect(logger.warn).toHaveBeenCalledWith({ event: 'GENYCLOUD_TEARDOWN' }, expect.stringMatching(/failing1 \(uuid1\): .*mock-error1/));
-        expect(logger.warn).toHaveBeenCalledWith({ event: 'GENYCLOUD_TEARDOWN' }, expect.stringMatching(/failing2 \(uuid2\): .*mock-error2/));
+        expect(logger.warn).toHaveBeenCalledWith({ event: 'GENYCLOUD_TEARDOWN' }, expect.stringMatching(/failing-uuid1:.*mock-error1/));
+        expect(logger.warn).toHaveBeenCalledWith({ event: 'GENYCLOUD_TEARDOWN' }, expect.stringMatching(/failing-uuid2:.*mock-error2/));
         expect(logger.warn).toHaveBeenCalledTimes(3);
       });
 
diff --git a/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.test.js b/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.test.js
index ddb1f5c7d..41d5419f4 100644
--- a/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.test.js
+++ b/detox/src/devices/drivers/android/genycloud/exec/GenyCloudExec.test.js
@@ -1,23 +1,18 @@
-
-const aResponse = (exit_code = 0, exit_code_desc = 'NO_ERROR') => ({
-  exit_code,
-  exit_code_desc,
-});
-const anErrorResponse = (exit_code, exit_code_desc, error_desc) => ({
-  ...aResponse(exit_code, exit_code_desc),
-  error: {
-    message: `API return unexpected code: ${exit_code}. Error: {"code":"${error_desc}","message":"Oh no, mocked error has occurred!"}`,
-    details: '',
-  }
-});
-
 describe('Genymotion-cloud executable', () => {
+  const aResponse = (exit_code = 0, exit_code_desc = 'NO_ERROR') => ({
+    exit_code,
+    exit_code_desc,
+  });
+  const anErrorResponse = (exit_code, exit_code_desc, error_desc) => ({
+    ...aResponse(exit_code, exit_code_desc),
+    error: {
+      message: `API return unexpected code: ${exit_code}. Error: {"code":"${error_desc}","message":"Oh no, mocked error has occurred!"}`,
+      details: '',
+    }
+  });
+
   const successResponse = aResponse();
   const failResponse = anErrorResponse(4, 'API_ERROR', 'TOO_MANY_RUNNING_VDS');
-  const recipeName = 'mock-recipe-name';
-  const recipeUUID = 'mock-recipe-uuid';
-  const instanceUUID = 'mock-uuid';
-  const instanceName = 'detox-instance1';
 
   const givenSuccessResult = () => exec.mockResolvedValue({
     stdout: JSON.stringify(successResponse),
@@ -38,12 +33,12 @@ describe('Genymotion-cloud executable', () => {
     uut = new GenyCloudExec('mock/path/to/gmsaas');
   });
 
+  const recipeName = 'mock-recipe-name';
+  const recipeUUID = 'mock-recipe-uuid';
+  const instanceUUID = 'mock-uuid';
+  const instanceName = 'detox-instance1';
+
   [
-    {
-      commandName: 'version',
-      commandExecFn: () => uut.getVersion(),
-      expectedExec: `"mock/path/to/gmsaas" --format compactjson --version`,
-    },
     {
       commandName: 'whoami',
       commandExecFn: () => uut.whoAmI(),
@@ -54,11 +49,6 @@ describe('Genymotion-cloud executable', () => {
       commandExecFn: () => uut.getRecipe(recipeName),
       expectedExec: `"mock/path/to/gmsaas" --format compactjson recipes list --name "${recipeName}"`,
     },
-    {
-      commandName: 'Get Instance',
-      commandExecFn: () => uut.getInstance(instanceUUID),
-      expectedExec: `"mock/path/to/gmsaas" --format compactjson instances get ${instanceUUID}`,
-    },
     {
       commandName: 'Get Instances',
       commandExecFn: () => uut.getInstances(),
diff --git a/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.test.js b/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.test.js
index d6e053e0a..ef14904ac 100644
--- a/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.test.js
+++ b/detox/src/devices/drivers/android/genycloud/services/GenyInstanceLookupService.test.js
@@ -43,7 +43,6 @@ describe('Genymotion-Cloud instances lookup service', () => {
   const givenNoRegisteredInstances = () => deviceRegistry.getRegisteredDevices.mockReturnValue([]);
   const givenInstances = (...instances) => exec.getInstances.mockResolvedValue({ instances });
   const givenNoInstances = () => exec.getInstances.mockResolvedValue({ instances: [] });
-  const givenAnInstance = (instance) => exec.getInstance.mockResolvedValue({ instance });
   const givenAllDevicesFamilial = () => instanceNaming.isFamilial.mockReturnValue(true);
   const givenNoDevicesFamilial = () => instanceNaming.isFamilial.mockReturnValue(false);
 
@@ -124,13 +123,12 @@ describe('Genymotion-Cloud instances lookup service', () => {
 
   describe('finding a specific instance', () => {
     it('should return an instance matching a UUID', async () => {
-      const instance = anInstance();
-      givenAnInstance(instance);
+      const instance1 = anInstance();
+      const instance2 = anotherInstance();
+      givenInstances(instance1, instance2);
 
-      const result = await uut.getInstance(instance.uuid);
-      expect(result.uuid).toEqual(instance.uuid);
-      expect(result.constructor.name).toContain('Instance');
-      expect(exec.getInstance).toHaveBeenCalledWith(instance.uuid);
+      const result = await uut.getInstance(instance2.uuid);
+      expect(result.uuid).toEqual(instance2.uuid);
     });
   });
 });
diff --git a/detox/src/utils/ChromeTracingExporter.test.js b/detox/src/utils/ChromeTracingExporter.test.js
index 964a43b00..121311990 100644
--- a/detox/src/utils/ChromeTracingExporter.test.js
+++ b/detox/src/utils/ChromeTracingExporter.test.js
@@ -30,11 +30,12 @@ describe('Chrome-Tracing exporter', () => {
 
   it('should export a start-event with args', () => {
     const startEvent = anEvent({ type: 'start' });
+    const expectedTs = startEvent.ts * 1000;
     const expectedObject = {
       name: startEvent.name,
       pid: processId,
       tid: threadId,
-      ts: startEvent.ts,
+      ts: expectedTs,
       ph: 'B',
       args: startEvent.args,
     };
@@ -44,11 +45,12 @@ describe('Chrome-Tracing exporter', () => {
 
   it('should export an end-event with args', () => {
     const endEvent = anEvent({ type: 'end' });
+    const expectedTs = endEvent.ts * 1000;
     const expectedObject = {
       name: endEvent.name,
       pid: processId,
       tid: threadId,
-      ts: endEvent.ts,
+      ts: expectedTs,
       ph: 'E',
       args: endEvent.args,
     };
@@ -61,18 +63,19 @@ describe('Chrome-Tracing exporter', () => {
       type: 'init',
       ts: 1234,
     };
+    const expectedTs = initEvent.ts;
     const expectedObjects = [{
       name: 'process_name',
       pid: processId,
       tid: threadId,
-      ts: initEvent.ts,
+      ts: expectedTs,
       ph: 'M',
       args: { name: processName }
     }, {
       name: 'thread_name',
       pid: processId,
       tid: threadId,
-      ts: initEvent.ts,
+      ts: expectedTs,
       ph: 'M',
       args: { name: threadName }
     }];
diff --git a/detox/test/integration/__snapshots__/timeline-artifact.test.js.snap b/detox/test/integration/__snapshots__/timeline-artifact.test.js.snap
index fdb9a2a2a..ddb4ab8ec 100644
--- a/detox/test/integration/__snapshots__/timeline-artifact.test.js.snap
+++ b/detox/test/integration/__snapshots__/timeline-artifact.test.js.snap
@@ -1,3 +1,3 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`Timeline integration test should deterministically produce a timeline artifact 1`] = `"[{\\"name\\":\\"process_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"detox\\"}},{\\"name\\":\\"thread_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"Worker #2\\"}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1200,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1300,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1400,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1500,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1600,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1700,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1800,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1900,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Stub1\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2200,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2300,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2400,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2500,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"Navigate to sanity\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2600,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Navigate to sanity\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2700,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"Asserting various texts\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2800,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Asserting various texts\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2900,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"failed\\"}},{\\"name\\":\\"Stub1\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3100,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3200,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"process_name\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"detox\\"}},{\\"name\\":\\"thread_name\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"Worker #1\\"}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1200,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1300,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1400,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1500,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1600,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1700,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1800,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1900,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"StubDevice#1\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Stub3\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2200,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2300,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2400,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2500,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2600,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2700,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2800,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2900,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"should show world screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3200,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3300,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should show world screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3400,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"Stub3\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3500,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"StubDevice#1\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3600,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"process_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3300,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"detox\\"}},{\\"name\\":\\"thread_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3300,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"Worker #2\\"}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3400,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3500,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3600,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3700,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3800,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3900,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4200,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4300,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4400,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Stub2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4500,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4600,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4700,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4800,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4900,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5100,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5200,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5300,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"Stub2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5400,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5500,\\"ph\\":\\"E\\",\\"args\\":{}}"`;
+exports[`Timeline integration test should deterministically produce a timeline artifact 1`] = `"[{\\"name\\":\\"process_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"detox\\"}},{\\"name\\":\\"thread_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"Worker #2\\"}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1200000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1300000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1400000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1500000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1600000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1700000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1800000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":1900000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2000000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Stub1\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2200000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2300000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2400000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2500000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"Navigate to sanity\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2600000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Navigate to sanity\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2700000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"Asserting various texts\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2800000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Asserting various texts\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":2900000,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3000000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"failed\\"}},{\\"name\\":\\"Stub1\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3100000,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3200000,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"process_name\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"detox\\"}},{\\"name\\":\\"thread_name\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1000,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"Worker #1\\"}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1200000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1300000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1400000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1500000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1600000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1700000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1800000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":1900000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2000000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"StubDevice#1\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Stub3\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2200000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2300000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2400000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2500000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2600000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2700000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2800000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":2900000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3000000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"should show world screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3200000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3300000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should show world screen after tap\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3400000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"Stub3\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3500000,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"StubDevice#1\\",\\"pid\\":0,\\"tid\\":\\"1\\",\\"ts\\":3600000,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"process_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3300,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"detox\\"}},{\\"name\\":\\"thread_name\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3300,\\"ph\\":\\"M\\",\\"args\\":{\\"name\\":\\"Worker #2\\"}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3400000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3500000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"acquireDevice\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3600000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3700000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appUninstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3800000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":3900000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"appInstall\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4000000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"launchApp\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4200000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"detoxInit\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4300000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4400000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"Stub2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4500000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4600000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4700000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4800000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should have welcome screen\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":4900000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5000000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5100000,\\"ph\\":\\"B\\",\\"args\\":{}},{\\"name\\":\\"reloadRN\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5200000,\\"ph\\":\\"E\\",\\"args\\":{\\"success\\":true}},{\\"name\\":\\"should show hello screen after tap\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5300000,\\"ph\\":\\"E\\",\\"args\\":{\\"status\\":\\"passed\\"}},{\\"name\\":\\"Stub2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5400000,\\"ph\\":\\"E\\",\\"args\\":{}},{\\"name\\":\\"StubDevice#2\\",\\"pid\\":0,\\"tid\\":\\"2\\",\\"ts\\":5500000,\\"ph\\":\\"E\\",\\"args\\":{}}"`;
diff --git a/detox/test/package.json b/detox/test/package.json
index f9efcc350..aed50f701 100644
--- a/detox/test/package.json
+++ b/detox/test/package.json
@@ -1,6 +1,6 @@
 {
   "name": "detox-test",
-  "version": "17.14.6",
+  "version": "17.14.5",
   "private": true,
   "engines": {
     "node": ">=8.3.0"
@@ -33,7 +33,7 @@
   },
   "devDependencies": {
     "@babel/core": "^7.8.7",
-    "detox": "^17.14.6",
+    "detox": "^17.14.5",
     "express": "^4.15.3",
     "jest": "^26.5.0",
     "jest-circus": "^26.5.2",