Detox: thrown: "Exceeded timeout of 120000 ms for a hook.

Description

When running the tests locally on my machine, the test work as expected. However on CircleCI I receive the described errors. It seems like the app is being installed and uninstalled in a loop, very strange.

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

Reproduction

I’m not 100% sure how to reproduce this since this is only happening on CircleCI and Travis too. I’ve tried to set the environment running on CircleCI to be as identical to my machine as possible. Both have the same Node, Xcode and Homebrew versions. The only difference is I’m running on M1 12.1 and CircleCI uses macOS 11.6.2

Expected behavior

The tests should initiate and run on both environments.

Environment

  • Detox: ^19.4.5
  • React Native: 0.67.2
  • Node: 14.19
  • Device: iPhone 12
  • Xcode: 12.5.1
  • iOS: Probably 12
  • macOS: 11.6.2
  • Test-runner (select one): jest-circus

Logs

If you are experiencing a timeout in your test

If you are seeing a Detox build problem (e.g. during npm install, not detox build)

  • I am providing the npm install log below:
Npm logs (paste logs here)

Device and verbose Detox logs

  • I have run my tests using the --loglevel trace argument and am providing the verbose log below:
Detox logs

GitHub doesn’t allow me to upload such a large file (maximum body exceeded, 65536 chars). Full logs can be found here: https://drive.google.com/file/d/1ZSdd-nIGv1dWgua2lsu4tqhLcZvfNos6/view?usp=sharing

Device logs I'm not sure how to get these from CircleCI. Can someone help me with that?

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 16 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Thanks @gunnartorfis, I will go over the logs and the configurations you provided.

Also, regarding:

It also might be worth mentioning that when running the tests locally, Detox spins up a new simulator. For example, if I declare “iPhone 12” in my `.detoxrc.json’, that one will fire up but tests will run on “iPhone 12-Detox”. Not sure if that’s normal but wanted to mention that.

Try echo "[]" > ~/Library/Detox/device.registry.state.lock. That’s probably because the desired simulators are locked in this file. See: https://wix.github.io/Detox/docs/guide/parallel-test-execution/#lock-file

Each worker is responsible for removing the device ID from the list in device.registry.state.lock. Exiting a test runner abruptly (using Ctrl+C / ⌘+C) will not give the worker a chance to unregister the device from the lock file, resulting in an inconsistent state, which can result in creation of unnecessary new simulators.

It’s still behaving a bit weird, like it’s constantly restarting the simulator or something, eventually reaching an error thrown: "Exceeded timeout of 120000 ms for a hook. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.".

It also might be worth mentioning that when running the tests locally, Detox spins up a new simulator. For example, if I declare “iPhone 12” in my `.detoxrc.json’, that one will fire up but tests will run on “iPhone 12-Detox”. Not sure if that’s normal but wanted to mention that.

Here’s a link to the output logs: https://drive.google.com/file/d/1Fcfyy_wGZfsrAF5vHBCqRFOOhQSwec7s/view?usp=sharing

Here’s my Detox config.json:

{
    "maxWorkers": 1,
    "testEnvironment": "./environment",
    "testRunner": "jest-circus/runner",
    "testTimeout": 120000,
    "testRegex": "\\.e2e\\.js$",
    "reporters": [
        "detox/runners/jest/streamlineReporter"
    ],
    "verbose": true,
    "setupFilesAfterEnv": [
        "<rootDir>/init.js"
    ]
}

environment.js:

const {
  DetoxCircusEnvironment,
  SpecReporter,
  WorkerAssignReporter,
} = require('detox/runners/jest-circus');

class CustomDetoxEnvironment extends DetoxCircusEnvironment {
  constructor(config, context) {
    super(config, context);

    // Can be safely removed, if you are content with the default value (=300000ms)
    this.initTimeout = 300000;

    // This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
    // This is strictly optional.
    this.registerListeners({
      SpecReporter,
      WorkerAssignReporter,
    });
  }
}

module.exports = CustomDetoxEnvironment;

init.js:

const detox = require('detox');
const config = './config.json';

beforeAll(async () => {
  await detox.init(config);
  await device.launchApp();
});

afterAll(async () => {
  await detox.cleanup();
});

.detoxrc.json

{
  "testRunner": "jest",
  "runnerConfig": "e2e/config.json",
  "skipLegacyWorkersInjection": true,
  "apps": {
    "ios.debug": {
      "type": "ios.app",
      "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/NoonaDEV.app",
      "build": "xcodebuild -workspace ios/timatorgmobile.xcworkspace -scheme 'Noona Develop' -sdk iphonesimulator -derivedDataPath ios/build"
    },
    "ios.release": {
      "name": "Noona",
      "type": "ios.app",
      "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/Noona.app",
      "build": "xcodebuild -workspace ios/timatorgmobile.xcworkspace -scheme 'Noona Release' -sdk iphonesimulator -derivedDataPath ios/build"
    },
    "android.DEV": {
      "type": "android.apk",
      "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
      "build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=DEV && cd .."
    },
    "android.release": {
      "type": "android.apk",
      "binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
      "build": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd .."
    }
  },
  "devices": {
    "simulator": {
      "type": "ios.simulator",
      "device": {
        "type": "iPhone 12"
      }
    },
    "emulator": {
      "type": "android.emulator",
      "device": {
        "avdName": "Pixel_3a_API_30_x86"
      }
    }
  },
  "configurations": {
    "ios.sim.debug": {
      "device": "simulator",
      "app": "ios.debug"
    },
    "ios.sim.release": {
      "device": "simulator",
      "app": "ios.release"
    },
    "android.emu.DEV": {
      "device": "emulator",
      "app": "android.DEV"
    },
    "android.emu.release": {
      "device": "emulator",
      "app": "android.release"
    }
  }
}

Actually this shouldn’t be related to the error… changing direction 😅

Please check what happens when you don’t set permissions when calling launchApp

@gunnartorfis I’m not sure why your init.js is required. Detox init and cleanup is done automatically in a jest-circus environment, such as yourself. That alone might be a source of some of the issues 🤔