From b0d1f2e4098cc047ba023e51b87d9d9335418e6c Mon Sep 17 00:00:00 2001 From: Yaroslav Serhieiev Date: Fri, 12 Aug 2022 12:24:28 +0300 Subject: [PATCH] fix: make Detox runtime config key names identical to Detox static config --- detox/internals.d.ts | 21 +++++++----- detox/local-cli/build.js | 2 +- detox/local-cli/build.test.js | 28 ++++++++-------- detox/local-cli/test.js | 6 ++-- detox/local-cli/test.test.js | 2 +- detox/runners/jest/testEnvironment/index.js | 2 +- .../listeners/DetoxCoreListener.js | 4 +-- .../testEnvironment/listeners/SpecReporter.js | 2 +- .../listeners/WorkerAssignReporter.js | 2 +- detox/src/DetoxWorker.js | 8 ++++- detox/src/DetoxWorker.test.js | 32 +++++++++---------- .../composeRunnerConfig.test.js.snap | 4 +-- .../configuration/composeRunnerConfig.test.js | 2 +- detox/src/configuration/index.js | 17 +++++----- detox/src/configuration/index.test.js | 14 ++++---- detox/src/realms/DetoxContext.js | 2 +- detox/src/realms/DetoxPrimaryContext.js | 11 +++++-- detox/test/e2e/jest.config.js | 2 +- detox/test/types/detox-internals-tests.ts | 18 ++++++----- .../e2e/global-setup.js | 2 +- 20 files changed, 100 insertions(+), 81 deletions(-) diff --git a/detox/internals.d.ts b/detox/internals.d.ts index 2c94befd7b..7b70694d59 100644 --- a/detox/internals.d.ts +++ b/detox/internals.d.ts @@ -87,14 +87,19 @@ declare global { type RuntimeConfig = Readonly<{ configurationName: string; - appsConfig: Record>; - artifactsConfig: Detox.DetoxArtifactsConfig; - behaviorConfig: Detox.DetoxBehaviorConfig; - cliConfig: DetoxCLIConfig; - deviceConfig: Detox.DetoxDeviceConfig; - loggerConfig: Detox.DetoxLoggerConfig; - runnerConfig: Detox.DetoxTestRunnerConfig; - sessionConfig: Detox.DetoxSessionConfig; + /** + * Dictionary of app configurations, + * where the keys are defined by {@link Detox.DetoxAppConfig#name} + * or equal to "default" if the name is not configured. + */ + apps: Record>; + artifacts: Readonly; + behavior: Readonly; + cli: Readonly; + device: Readonly; + logger: Readonly; + testRunner: Readonly; + session: Readonly; }>; type DetoxCLIConfig = Readonly { const DetoxConfigErrorComposer = require('../src/errors/DetoxConfigErrorComposer'); const config = { - appsConfig: {}, - artifactsConfig: {}, - behaviorConfig: {}, + apps: {}, + artifacts: {}, + behavior: {}, errorComposer: new DetoxConfigErrorComposer(), - deviceConfig: {}, - sessionConfig: {} + device: {}, + session: {} }; return ({ @@ -44,14 +44,14 @@ describe('build', () => { }); it('runs the build script from the composed device config', async () => { - detox.config.appsConfig.default = { build: 'yet another command' }; + detox.config.apps.default = { build: 'yet another command' }; await callCli('./build', 'build'); expect(execSync).toHaveBeenCalledWith('yet another command', expect.anything()); }); it('skips building the app if the binary exists and --if-missing flag is set', async () => { - detox.config.appsConfig.default = { build: 'yet another command', binaryPath: __filename }; + detox.config.apps.default = { build: 'yet another command', binaryPath: __filename }; await callCli('./build', 'build -i'); expect(execSync).not.toHaveBeenCalled(); @@ -63,32 +63,32 @@ describe('build', () => { }); it('fails with an error if a build script has not been found', async () => { - detox.config.appsConfig.default = {}; + detox.config.apps.default = {}; await expect(callCli('./build', 'build')).rejects.toThrowError(/Failed to build/); }); it('should ignore missing build command with -s, --silent flag', async () => { - detox.config.appsConfig.default = {}; + detox.config.apps.default = {}; await expect(callCli('./build', 'build -s')).resolves.not.toThrowError(); expect(detox.log.warn).not.toHaveBeenCalled(); }); it('should print a warning upon user build script failure', async () => { - detox.config.appsConfig.default = { build: 'a command' }; + detox.config.apps.default = { build: 'a command' }; execSync.mockImplementation(() => { throw new Error('Build failure'); }); await expect(callCli('./build', 'build')).rejects.toThrowError(/Build failure/); expect(detox.log.warn).toHaveBeenCalledWith(expect.stringContaining('You are responsible')); }); it('should print a warning if app is not found at binary path', async () => { - detox.config.appsConfig.default = { binaryPath: tempfile() }; + detox.config.apps.default = { binaryPath: tempfile() }; await expect(callCli('./build', 'build -s')).resolves.not.toThrowError(); expect(detox.log.warn).toHaveBeenCalledWith(expect.stringContaining('could not find your app at the given binary path')); }); it('should print extra message with the app name before building (in a multi-app configuration)', async () => { - detox.config.appsConfig.app1 = { binaryPath: tempfile(), build: ':' }; - detox.config.appsConfig.app2 = { binaryPath: tempfile(), build: ':' }; + detox.config.apps.app1 = { binaryPath: tempfile(), build: ':' }; + detox.config.apps.app2 = { binaryPath: tempfile(), build: ':' }; await expect(callCli('./build', 'build -s')).resolves.not.toThrowError(); expect(detox.log.info).toHaveBeenCalledWith(expect.stringContaining('app1')); @@ -96,7 +96,7 @@ describe('build', () => { }); it('should not print that extra message when the app is single', async () => { - detox.config.appsConfig.default = { binaryPath: tempfile(), build: ':' }; + detox.config.apps.default = { binaryPath: tempfile(), build: ':' }; await expect(callCli('./build', 'build -s')).resolves.not.toThrowError(); expect(detox.log.info).not.toHaveBeenCalledWith(expect.stringContaining('default')); diff --git a/detox/local-cli/test.js b/detox/local-cli/test.js index 518f017311..432efea73a 100644 --- a/detox/local-cli/test.js +++ b/detox/local-cli/test.js @@ -15,9 +15,9 @@ module.exports.handler = async function test({ detoxArgs, runnerArgs }) { }); const runnerCommand = new TestRunnerCommand() - .setRunnerConfig(detox.config.runnerConfig) - .setDeviceConfig(detox.config.deviceConfig) - .replicateCLIConfig(detox.config.cliConfig); + .setRunnerConfig(detox.config.testRunner) + .setDeviceConfig(detox.config.device) + .replicateCLIConfig(detox.config.cli); await runnerCommand.execute(); } finally { diff --git a/detox/local-cli/test.test.js b/detox/local-cli/test.test.js index e1b881c210..45de42c3bd 100644 --- a/detox/local-cli/test.test.js +++ b/detox/local-cli/test.test.js @@ -116,7 +116,7 @@ describe('CLI', () => { }); }); - test('should use runnerConfig.specs as default specs', async () => { + test('should use testRunner.args._ as default specs', async () => { detoxConfig.testRunner.args._ = ['e2e/sanity']; await run(); expect(_.last(cliCall().argv)).toEqual('e2e/sanity'); diff --git a/detox/runners/jest/testEnvironment/index.js b/detox/runners/jest/testEnvironment/index.js index 3306f8e861..b735b8d247 100644 --- a/detox/runners/jest/testEnvironment/index.js +++ b/detox/runners/jest/testEnvironment/index.js @@ -46,7 +46,7 @@ class DetoxCircusEnvironment extends NodeEnvironment { /** @protected */ this.testEventListeners = []; /** @protected */ - this.initTimeout = detox.config.runnerConfig.jest.initTimeout; + this.initTimeout = detox.config.testRunner.jest.initTimeout; } /** @override */ diff --git a/detox/runners/jest/testEnvironment/listeners/DetoxCoreListener.js b/detox/runners/jest/testEnvironment/listeners/DetoxCoreListener.js index 7d7bc6a7cc..17528b4aad 100644 --- a/detox/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +++ b/detox/runners/jest/testEnvironment/listeners/DetoxCoreListener.js @@ -22,7 +22,7 @@ class DetoxCoreListener { async setup() { // Workaround to override Jest's expect - if (detoxInternals.config.behaviorConfig.init.exposeGlobals) { + if (detoxInternals.config.behavior.init.exposeGlobals) { this._env.global.expect = detox.expect; } } @@ -98,7 +98,7 @@ class DetoxCoreListener { async run_finish(_event, state) { if (this._hasFailedTests(state.rootDescribeBlock)) { - const handledByJestCircus = this._testRunTimes > 1 && !detoxInternals.config.runnerConfig.jest.retryAfterCircusRetries; + const handledByJestCircus = this._testRunTimes > 1 && !detoxInternals.config.testRunner.jest.retryAfterCircusRetries; await detoxInternals.reportFailedTests([this._env.testPath], handledByJestCircus); } } diff --git a/detox/runners/jest/testEnvironment/listeners/SpecReporter.js b/detox/runners/jest/testEnvironment/listeners/SpecReporter.js index e898f9ffe8..368e78f2d8 100644 --- a/detox/runners/jest/testEnvironment/listeners/SpecReporter.js +++ b/detox/runners/jest/testEnvironment/listeners/SpecReporter.js @@ -16,7 +16,7 @@ class SpecReporter { } get enabled() { - const jestSection = config.runnerConfig.jest; + const jestSection = config.testRunner.jest; const reportSpecs = jestSection && jestSection.reportSpecs; return reportSpecs !== undefined ? reportSpecs : session.workersCount === 1; diff --git a/detox/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js b/detox/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js index 847d26f71f..1cda09f8ce 100644 --- a/detox/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +++ b/detox/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js @@ -12,7 +12,7 @@ class WorkerAssignReporter { } run_start() { - if (config.runnerConfig.jest.reportWorkerAssign) { + if (config.testRunner.jest.reportWorkerAssign) { log.info({ event: 'WORKER_ASSIGN' }, `${this._formatTestName()} is assigned to ${this._formatDeviceName()}`); } } diff --git a/detox/src/DetoxWorker.js b/detox/src/DetoxWorker.js index 9e9bb2a433..ad702b6bf5 100644 --- a/detox/src/DetoxWorker.js +++ b/detox/src/DetoxWorker.js @@ -56,7 +56,13 @@ class DetoxWorker { async init() { if (this._isCleaningUp) return; - const { appsConfig, artifactsConfig, behaviorConfig, deviceConfig, sessionConfig } = this._config; + const { + apps: appsConfig, + artifacts: artifactsConfig, + behavior: behaviorConfig, + device: deviceConfig, + session: sessionConfig + } = this._config; this._appsConfig = appsConfig; this._artifactsConfig = artifactsConfig; this._behaviorConfig = behaviorConfig; diff --git a/detox/src/DetoxWorker.test.js b/detox/src/DetoxWorker.test.js index 2b93f110f0..6369d39700 100644 --- a/detox/src/DetoxWorker.test.js +++ b/detox/src/DetoxWorker.test.js @@ -127,7 +127,7 @@ describe('DetoxWorker', () => { expect(envValidator.validate).toHaveBeenCalled()); it('should allocate a device', () => { - expect(deviceAllocator.allocate).toHaveBeenCalledWith(detoxConfig.deviceConfig); + expect(deviceAllocator.allocate).toHaveBeenCalledWith(detoxConfig.device); }); it('should create a runtime-device based on the allocation result (cookie)', () => @@ -140,9 +140,9 @@ describe('DetoxWorker', () => { runtimeErrorComposer: expect.any(Object), }, { - appsConfig: detoxConfig.appsConfig, - behaviorConfig: detoxConfig.behaviorConfig, - deviceConfig: detoxConfig.deviceConfig, + appsConfig: detoxConfig.apps, + behaviorConfig: detoxConfig.behavior, + deviceConfig: detoxConfig.device, sessionConfig: expect.any(Object), }, )); @@ -168,7 +168,7 @@ describe('DetoxWorker', () => { expect(global.globalMatcher).toBe(mockGlobalMatcher)); it('should create artifacts manager', () => - expect(artifactsManagerFactory.createArtifactsManager).toHaveBeenCalledWith(detoxConfig.artifactsConfig, expect.objectContaining({ + expect(artifactsManagerFactory.createArtifactsManager).toHaveBeenCalledWith(detoxConfig.artifacts, expect.objectContaining({ client: client(), eventEmitter: eventEmitter(), }))); @@ -189,12 +189,12 @@ describe('DetoxWorker', () => { describe('with multiple apps', () => { beforeEach(() => { - detoxConfig.appsConfig['extraApp'] = { + detoxConfig.apps['extraApp'] = { type: 'ios.app', binaryPath: 'path/to/app', }; - detoxConfig.appsConfig['extraAppWithAnotherArguments'] = { + detoxConfig.apps['extraAppWithAnotherArguments'] = { type: 'ios.app', binaryPath: 'path/to/app', launchArgs: { @@ -218,9 +218,9 @@ describe('DetoxWorker', () => { }); }); - describe('with behaviorConfig.init.exposeGlobals = false', () => { + describe('with behavior.init.exposeGlobals = false', () => { beforeEach(() => { - detoxConfig.behaviorConfig.init.exposeGlobals = false; + detoxConfig.behavior.init.exposeGlobals = false; }); beforeEach(init); @@ -239,9 +239,9 @@ describe('DetoxWorker', () => { expect(global.globalMatcher).toBe(undefined)); }); - describe('with behaviorConfig.init.reinstallApp = false', () => { + describe('with behavior.init.reinstallApp = false', () => { beforeEach(() => { - detoxConfig.behaviorConfig.init.reinstallApp = false; + detoxConfig.behavior.init.reinstallApp = false; }); beforeEach(init); @@ -521,9 +521,9 @@ describe('DetoxWorker', () => { }); }); - describe('when behaviorConfig.cleanup.shutdownDevice = true', () => { + describe('when behavior.cleanup.shutdownDevice = true', () => { beforeEach(async () => { - detoxConfig.behaviorConfig.cleanup.shutdownDevice = true; + detoxConfig.behavior.cleanup.shutdownDevice = true; detox = await new Detox(detoxContext).init(); }); @@ -570,7 +570,7 @@ describe('DetoxWorker', () => { // TODO: move it to the root realm describe.skip('global context', () => { const configs = { - deviceConfig: { + device: { mock: 'config', }, }; @@ -594,7 +594,7 @@ describe('DetoxWorker', () => { await Detox.globalInit(configs); expect(lifecycleHandler.globalInit).toHaveBeenCalled(); - expect(environmentFactory.createGlobalLifecycleHandler).toHaveBeenCalledWith(configs.deviceConfig); + expect(environmentFactory.createGlobalLifecycleHandler).toHaveBeenCalledWith(configs.device); }); it(`should not invoke init if no handler was resolved`, async () => { @@ -607,7 +607,7 @@ describe('DetoxWorker', () => { await Detox.globalCleanup(configs); expect(lifecycleHandler.globalCleanup).toHaveBeenCalled(); - expect(environmentFactory.createGlobalLifecycleHandler).toHaveBeenCalledWith(configs.deviceConfig); + expect(environmentFactory.createGlobalLifecycleHandler).toHaveBeenCalledWith(configs.device); }); it(`should not invoke cleanup if no handler was resolved`, async () => { diff --git a/detox/src/configuration/__snapshots__/composeRunnerConfig.test.js.snap b/detox/src/configuration/__snapshots__/composeRunnerConfig.test.js.snap index 3ca1a9725d..6f7f82797f 100644 --- a/detox/src/configuration/__snapshots__/composeRunnerConfig.test.js.snap +++ b/detox/src/configuration/__snapshots__/composeRunnerConfig.test.js.snap @@ -15,12 +15,12 @@ HINT: Check that in your Detox config. `; exports[`composeRunnerConfig unhappy scenarios non-string and non-object "testRunner" in global config 1`] = ` -"testRunner should be an object, not a function +"testRunner should be an object, not a number HINT: Check that in your Detox config. { - testRunner: [Function (anonymous)], + testRunner: 0, configurations: [Object] }" `; diff --git a/detox/src/configuration/composeRunnerConfig.test.js b/detox/src/configuration/composeRunnerConfig.test.js index 601eeeeb0f..69d1c1e93c 100644 --- a/detox/src/configuration/composeRunnerConfig.test.js +++ b/detox/src/configuration/composeRunnerConfig.test.js @@ -298,7 +298,7 @@ describe('composeRunnerConfig', () => { describe('unhappy scenarios', () => { test('non-string and non-object "testRunner" in global config', () => { - globalConfig['testRunner'] = () => ({ jest: {} }); + globalConfig['testRunner'] = 0; expect(composeRunnerConfig).toThrowErrorMatchingSnapshot(); }); diff --git a/detox/src/configuration/index.js b/detox/src/configuration/index.js index a96130239f..bfba073688 100644 --- a/detox/src/configuration/index.js +++ b/detox/src/configuration/index.js @@ -105,16 +105,17 @@ async function composeDetoxConfig({ }); const result = { - appsConfig, - artifactsConfig, - behaviorConfig, - cliConfig, configurationName, - deviceConfig, errorComposer, - loggerConfig, - runnerConfig, - sessionConfig, + + apps: appsConfig, + artifacts: artifactsConfig, + behavior: behaviorConfig, + cli: cliConfig, + device: deviceConfig, + logger: loggerConfig, + testRunner: runnerConfig, + session: sessionConfig, }; return result; diff --git a/detox/src/configuration/index.test.js b/detox/src/configuration/index.test.js index 1deb38ba7a..5e4162b248 100644 --- a/detox/src/configuration/index.test.js +++ b/detox/src/configuration/index.test.js @@ -96,7 +96,7 @@ describe('composeDetoxConfig', () => { configurationName: 'another', filepath: path.join(__dirname, '__mocks__/configuration/packagejson/package.json'), }, - artifactsConfig: { + artifacts: { pathBuilder: '@some/pathbuilder-implementation', plugins: { log: { @@ -109,7 +109,7 @@ describe('composeDetoxConfig', () => { }, }, }, - behaviorConfig: { + behavior: { init: { exposeGlobals: true, reinstallApp: false, @@ -118,32 +118,32 @@ describe('composeDetoxConfig', () => { shutdownDevice: true, } }, - cliConfig: { + cli: { configuration: 'another', deviceName: 'iPhone XS', cleanup: true, reuse: true, recordLogs: 'all', }, - deviceConfig: expect.objectContaining({ + device: expect.objectContaining({ type: 'ios.simulator', device: { type: 'iPhone XS', }, }), - loggerConfig: { + logger: { level: 'info', overrideConsole: 'sandbox', options: expect.objectContaining({}), }, - runnerConfig: { + testRunner: { args: { $0: 'jest', config: 'e2e/jest.config.js', _: [], }, }, - sessionConfig: expect.objectContaining({ + session: expect.objectContaining({ server: 'ws://localhost:9999', sessionId: 'external file works', }), diff --git a/detox/src/realms/DetoxContext.js b/detox/src/realms/DetoxContext.js index fe1c17980b..10fae710b3 100644 --- a/detox/src/realms/DetoxContext.js +++ b/detox/src/realms/DetoxContext.js @@ -27,7 +27,7 @@ class DetoxContext { this[$sessionState] = this[$restoreSessionState](); const loggerConfig = this[$sessionState].detoxConfig - ? this[$sessionState].detoxConfig.loggerConfig + ? this[$sessionState].detoxConfig.logger : undefined; /** diff --git a/detox/src/realms/DetoxPrimaryContext.js b/detox/src/realms/DetoxPrimaryContext.js index f70ef1c7bf..60088949a9 100644 --- a/detox/src/realms/DetoxPrimaryContext.js +++ b/detox/src/realms/DetoxPrimaryContext.js @@ -65,7 +65,12 @@ class DetoxPrimaryContext extends DetoxContext { this[_dirty] = true; const detoxConfig = await this[symbols.resolveConfig](opts); - const { behaviorConfig, deviceConfig, loggerConfig, sessionConfig } = detoxConfig; + const { + behavior: behaviorConfig, + device: deviceConfig, + logger: loggerConfig, + session: sessionConfig + } = detoxConfig; await this[$logger].setConfig(loggerConfig); this.trace.begin({ @@ -177,7 +182,7 @@ class DetoxPrimaryContext extends DetoxContext { } const streamUtils = require('../utils/streamUtils'); - const { rootDir, plugins } = this[symbols.config].artifactsConfig || {}; + const { rootDir, plugins } = this[symbols.config].artifacts || {}; const logConfig = plugins && plugins.log || 'none'; const enabled = rootDir && (typeof logConfig === 'string' ? logConfig !== 'none' : logConfig.enabled); @@ -204,7 +209,7 @@ class DetoxPrimaryContext extends DetoxContext { async[_resetLockFile]() { const DeviceRegistry = require('../devices/DeviceRegistry'); - const deviceType = this[symbols.config].deviceConfig.type; + const deviceType = this[symbols.config].device.type; switch (deviceType) { case 'ios.none': diff --git a/detox/test/e2e/jest.config.js b/detox/test/e2e/jest.config.js index 5d61300dab..3aeed5ffed 100644 --- a/detox/test/e2e/jest.config.js +++ b/detox/test/e2e/jest.config.js @@ -27,7 +27,7 @@ module.exports = async () => { : ['/runners/jest/reporter', '/test/node_modules/jest-junit'], 'verbose': true, 'bail': false, - 'maxWorkers': process.env.CI ? maxWorkersMap[config.deviceConfig.type] || 1 : 1, + 'maxWorkers': process.env.CI ? maxWorkersMap[config.device.type] || 1 : 1, 'collectCoverageFrom': [ 'src/**/*.js', '!**/__test/**', diff --git a/detox/test/types/detox-internals-tests.ts b/detox/test/types/detox-internals-tests.ts index c5c49c1da8..f79e593cd3 100644 --- a/detox/test/types/detox-internals-tests.ts +++ b/detox/test/types/detox-internals-tests.ts @@ -56,6 +56,8 @@ async function internalsTest() { workerId: 1, }); + assert(worker); + await teardown(); await globalTeardown(); } @@ -125,15 +127,15 @@ async function logTest() { function configTest() { assert(session.workersCount); - assert(config.deviceConfig); - assert(config.runnerConfig); - assert>(config.appsConfig); - assert(config.sessionConfig); - assert(config.artifactsConfig); - assert(config.behaviorConfig); - assert(config.cliConfig); assert(config.configurationName); - assert(config.loggerConfig); + assert>(config.apps); + assert(config.artifacts); + assert(config.behavior); + assert(config.cli); + assert(config.device); + assert(config.logger); + assert(config.session); + assert(config.testRunner); } async function lifecycleTest() { diff --git a/examples/demo-react-native-jest/e2e/global-setup.js b/examples/demo-react-native-jest/e2e/global-setup.js index 4ce482d61d..ac78fc572c 100644 --- a/examples/demo-react-native-jest/e2e/global-setup.js +++ b/examples/demo-react-native-jest/e2e/global-setup.js @@ -6,7 +6,7 @@ const { config } = require('detox/internals'); async function customGlobalSetup() { await globalSetup(); - if (config.deviceConfig.type === 'android.emulator') { + if (config.device.type === 'android.emulator') { downloadTestButlerAPK(); } }