detox 20.0.15-prerelease.0 → 20.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/Detox-android/com/wix/detox/{20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar → 20.1.0/detox-20.1.0-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar → 20.1.0/detox-20.1.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom → 20.1.0/detox-20.1.0.pom} +1 -1
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.sha512 +1 -0
- package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
- package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios.tbz +0 -0
- package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +3 -3
- package/android/detox/src/full/java/com/wix/detox/adapters/server/QueryStatusActionHandler.kt +12 -80
- package/android/detox/src/full/java/com/wix/detox/espresso/common/UiControllerImplReflected.kt +16 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/idlingresources/DescriptiveIdlingResource.kt +8 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/registry/BusyResourcesInquirer.kt +48 -0
- package/android/detox/src/full/java/com/wix/detox/inquiry/DetoxBusyResource.kt +92 -0
- package/android/detox/src/full/java/com/wix/detox/{reactnative/idlingresources/IdlingResourceDescription.kt → inquiry/DetoxBusyResourceDescription.kt} +6 -6
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +18 -7
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResource.kt +2 -4
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +12 -6
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +2 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +14 -8
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +1 -6
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +4 -6
- package/android/detox/src/testFull/java/com/wix/detox/adapters/server/QueryStatusActionHandlerSpec.kt +35 -94
- package/android/detox/src/testFull/java/com/wix/detox/espresso/registry/{IRStatusInquirerTest.kt → BusyResourcesInquirerTest.kt} +46 -7
- package/android/detox/src/testFull/java/com/wix/detox/{reactnative/idlingresources/IdlingResourceDescriptionSpec.kt → inquiry/DetoxBusyResourceDescriptionSpec.kt} +6 -6
- package/android/detox/src/testFull/java/com/wix/detox/inquiry/DetoxBusyResourceSpec.kt +134 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +4 -5
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +5 -5
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +4 -6
- package/index.d.ts +1 -1
- package/internals.d.ts +2 -2
- package/local-cli/cli.js +6 -3
- package/local-cli/testCommand/TestRunnerCommand.js +25 -12
- package/local-cli/testCommand/TestRunnerError.js +17 -0
- package/package.json +3 -6
- package/runners/deprecation.js +2 -2
- package/src/artifacts/utils/temporaryPath.js +32 -2
- package/src/client/actions/SyncStatusSchema.json +21 -0
- package/src/client/actions/formatters/SyncStatusFormatter.js +2 -0
- package/src/client/actions/formatters/sync-resources/BgThreadFormatter.js +5 -0
- package/src/configuration/composeRunnerConfig.js +1 -1
- package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -3
- package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -16
- package/src/devices/common/drivers/android/exec/ADB.js +4 -0
- package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
- package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +2 -0
- package/src/errors/DetoxError.js +5 -1
- package/src/ipc/IPCClient.js +26 -17
- package/src/ipc/IPCServer.js +11 -3
- package/src/ipc/SessionState.js +4 -6
- package/src/logger/DetoxLogger.js +34 -5
- package/src/logger/utils/BunyanLogger.js +39 -0
- package/src/logger/utils/CategoryThreadDispatcher.js +2 -1
- package/src/logger/utils/DetoxLogFinalizer.js +83 -57
- package/src/logger/utils/MessageStack.js +17 -6
- package/src/logger/utils/customConsoleLogger.js +18 -2
- package/src/logger/utils/getMainCategory.js +5 -0
- package/src/logger/utils/streams/BunyanTransformer.js +72 -0
- package/src/logger/utils/streams/ChromeTraceTransformer.js +132 -0
- package/src/logger/utils/streams/DetoxJSONLParser.js +31 -0
- package/src/logger/utils/streams/JSONLStringer.js +55 -0
- package/src/logger/utils/streams/index.js +7 -0
- package/src/logger/utils/streams/transformers.js +39 -0
- package/src/realms/DetoxContext.js +2 -1
- package/src/realms/DetoxPrimaryContext.js +13 -3
- package/src/realms/DetoxSecondaryContext.js +2 -2
- package/src/utils/pathUtils.js +11 -0
- package/src/utils/shellUtils.js +17 -0
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.0.15-prerelease.0/detox-20.0.15-prerelease.0.pom.sha512 +0 -1
- package/android/detox/src/full/java/com/wix/detox/espresso/registry/IRStatusInquirer.kt +0 -24
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DescriptiveIdlingResource.kt +0 -10
- package/local-cli/build.test.js +0 -104
- package/local-cli/run-server.test.js +0 -23
- package/local-cli/test.test.js +0 -602
- package/runners/jest/index.test.js +0 -13
- package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -22
- package/src/logger/utils/streamUtils.js +0 -248
@@ -0,0 +1,17 @@
|
|
1
|
+
const { DetoxError } = require('../../src/errors');
|
2
|
+
|
3
|
+
class TestRunnerError extends DetoxError {
|
4
|
+
constructor({ command, code, signal }) {
|
5
|
+
super(`Command failed with exit code = ${code}:\n${command}`);
|
6
|
+
|
7
|
+
this.code = code;
|
8
|
+
this.signal = signal;
|
9
|
+
this.name = 'TestRunnerError';
|
10
|
+
}
|
11
|
+
|
12
|
+
format() {
|
13
|
+
return '';
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
module.exports = TestRunnerError;
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "detox",
|
3
3
|
"description": "E2E tests and automation for mobile",
|
4
|
-
"version": "20.
|
4
|
+
"version": "20.1.0",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -61,10 +61,9 @@
|
|
61
61
|
"caf": "^15.0.1",
|
62
62
|
"chalk": "^2.4.2",
|
63
63
|
"child-process-promise": "^2.2.0",
|
64
|
-
"duplexify": "^4.1.2",
|
65
64
|
"find-up": "^4.1.0",
|
66
65
|
"fs-extra": "^4.0.2",
|
67
|
-
"funpermaproxy": "^1.0
|
66
|
+
"funpermaproxy": "^1.1.0",
|
68
67
|
"glob": "^8.0.3",
|
69
68
|
"ini": "^1.3.4",
|
70
69
|
"json-cycle": "^1.3.0",
|
@@ -82,7 +81,6 @@
|
|
82
81
|
"signal-exit": "^3.0.3",
|
83
82
|
"stream-json": "^1.7.4",
|
84
83
|
"strip-ansi": "^6.0.1",
|
85
|
-
"tail": "^2.0.0",
|
86
84
|
"telnet-client": "1.2.8",
|
87
85
|
"tempfile": "^2.0.0",
|
88
86
|
"trace-event-lib": "^1.3.1",
|
@@ -164,7 +162,6 @@
|
|
164
162
|
"runners/jest/testEnvironment",
|
165
163
|
"src/DetoxWorker.js",
|
166
164
|
"src/logger/utils/streamUtils.js",
|
167
|
-
"src/ipc",
|
168
165
|
"src/realms"
|
169
166
|
],
|
170
167
|
"resetMocks": true,
|
@@ -190,5 +187,5 @@
|
|
190
187
|
}
|
191
188
|
}
|
192
189
|
},
|
193
|
-
"gitHead": "
|
190
|
+
"gitHead": "57097c7301cae2460bd3b36c1749c4048d84dd39"
|
194
191
|
}
|
package/runners/deprecation.js
CHANGED
@@ -26,7 +26,7 @@ console.error(centerText(`\
|
|
26
26
|
|
27
27
|
${bold(header)}
|
28
28
|
|
29
|
-
https://wix.github.io/Detox/docs/
|
29
|
+
https://wix.github.io/Detox/docs/guide/migration
|
30
30
|
|
31
31
|
Sorry to say that Detox 20 comes without old adapters for Jest.
|
32
32
|
You have to rearrange your init code before you can continue your journey.
|
@@ -40,6 +40,6 @@ ${bold(header)}
|
|
40
40
|
|
41
41
|
`, header.length));
|
42
42
|
|
43
|
-
const error = new Error('\nPlease follow the migration guide:\nhttps://wix.github.io/Detox/docs/
|
43
|
+
const error = new Error('\nPlease follow the migration guide:\nhttps://wix.github.io/Detox/docs/guide/migration\n\n');
|
44
44
|
error.stack = '';
|
45
45
|
throw error;
|
@@ -1,14 +1,42 @@
|
|
1
1
|
const path = require('path');
|
2
|
+
const { promisify } = require('util');
|
2
3
|
|
4
|
+
const glob = require('glob');
|
3
5
|
const tempfile = require('tempfile');
|
4
6
|
|
7
|
+
const { useForwardSlashes } = require('../../utils/shellUtils');
|
8
|
+
|
9
|
+
const globSync = glob.sync;
|
10
|
+
const globAsync = promisify(glob);
|
11
|
+
|
12
|
+
function getRoot() {
|
13
|
+
return path.dirname(tempfile());
|
14
|
+
}
|
15
|
+
|
16
|
+
function createGlobber(ext) {
|
17
|
+
const fullExt = `.detox.${ext}`;
|
18
|
+
|
19
|
+
return {
|
20
|
+
sync: (pattern) => {
|
21
|
+
const cwd = getRoot();
|
22
|
+
const files = globSync(useForwardSlashes(pattern + fullExt), { cwd });
|
23
|
+
return files.map(f => path.join(cwd, f));
|
24
|
+
},
|
25
|
+
async: async (pattern) => {
|
26
|
+
const cwd = getRoot();
|
27
|
+
const files = await globAsync(useForwardSlashes(pattern + fullExt), { cwd });
|
28
|
+
return files.map(f => path.join(cwd, f));
|
29
|
+
},
|
30
|
+
};
|
31
|
+
}
|
32
|
+
|
5
33
|
function createTempFileBuilderFn(fileExtension) {
|
6
34
|
/**
|
7
35
|
* @param {string} [basename]
|
8
36
|
*/
|
9
37
|
return (basename) => {
|
10
38
|
return basename
|
11
|
-
? path.join(
|
39
|
+
? path.join(getRoot(), `${basename}.detox.${fileExtension}`)
|
12
40
|
: tempfile(`.detox.${fileExtension}`);
|
13
41
|
};
|
14
42
|
}
|
@@ -23,5 +51,7 @@ module.exports = {
|
|
23
51
|
dtxrec: createTempFileBuilderFn('dtxrec'),
|
24
52
|
viewhierarchy: createTempFileBuilderFn('viewhierarchy'),
|
25
53
|
},
|
26
|
-
|
54
|
+
find: {
|
55
|
+
jsonl: createGlobber('jsonl'),
|
56
|
+
},
|
27
57
|
};
|
@@ -232,6 +232,27 @@
|
|
232
232
|
],
|
233
233
|
"additionalProperties":false
|
234
234
|
},
|
235
|
+
{
|
236
|
+
"properties":{
|
237
|
+
"name":{
|
238
|
+
"const":"bg"
|
239
|
+
},
|
240
|
+
"description":{
|
241
|
+
"type":"object",
|
242
|
+
"properties":{
|
243
|
+
"reason":{
|
244
|
+
"type":"string"
|
245
|
+
}
|
246
|
+
},
|
247
|
+
"additionalProperties":false
|
248
|
+
}
|
249
|
+
},
|
250
|
+
"required":[
|
251
|
+
"name",
|
252
|
+
"description"
|
253
|
+
],
|
254
|
+
"additionalProperties":false
|
255
|
+
},
|
235
256
|
{
|
236
257
|
"properties":{
|
237
258
|
"name":{
|
@@ -4,6 +4,7 @@ const Ajv = require('ajv');
|
|
4
4
|
const DetoxInternalError = require('../../../errors/DetoxInternalError');
|
5
5
|
const statusSchema = require('../SyncStatusSchema.json');
|
6
6
|
|
7
|
+
const bgThreadFormatter = require('./sync-resources/BgThreadFormatter');
|
7
8
|
const delayedPerformSelectorFormatter = require('./sync-resources/DelayedPerformSelectorFormatter');
|
8
9
|
const dispatchQueueFormatter = require('./sync-resources/DispatchQueueFormatter');
|
9
10
|
const jsTimersFormatter = require('./sync-resources/JavaScriptTimersFormatter');
|
@@ -51,6 +52,7 @@ function resourcesDescriptionsFromJSON(jsonDescriptions) {
|
|
51
52
|
}
|
52
53
|
|
53
54
|
const resourceFormatters = {
|
55
|
+
bg: bgThreadFormatter,
|
54
56
|
delayed_perform_selector: delayedPerformSelectorFormatter,
|
55
57
|
dispatch_queue: dispatchQueueFormatter,
|
56
58
|
run_loop: runLoopFormatter,
|
@@ -91,7 +91,7 @@ function adaptLegacyRunnerConfig(globalConfig) {
|
|
91
91
|
return globalConfig.testRunner;
|
92
92
|
}
|
93
93
|
|
94
|
-
log.warn(`Please migrate your Detox config according to the guide:\nhttps://wix.github.io/Detox/docs/
|
94
|
+
log.warn(`Please migrate your Detox config according to the guide:\nhttps://wix.github.io/Detox/docs/guide/migration\n`);
|
95
95
|
const testRunner = globalConfig[testRunnerKey];
|
96
96
|
const runnerConfig = globalConfig[runnerConfigKey];
|
97
97
|
const specs = globalConfig.specs != null ? String(globalConfig.specs) : undefined;
|
@@ -36,7 +36,7 @@ class EmulatorLauncher extends DeviceLauncher {
|
|
36
36
|
retries: 2,
|
37
37
|
interval: 100,
|
38
38
|
conditionFn: isUnknownEmulatorError,
|
39
|
-
}, () => this._launchEmulator(avdName, launchCommand));
|
39
|
+
}, () => this._launchEmulator(avdName, launchCommand, adbName));
|
40
40
|
}
|
41
41
|
await this._awaitEmulatorBoot(adbName);
|
42
42
|
await this._notifyBootEvent(adbName, avdName, !isRunning);
|
@@ -60,8 +60,8 @@ class EmulatorLauncher extends DeviceLauncher {
|
|
60
60
|
await this._notifyShutdownCompleted(adbName);
|
61
61
|
}
|
62
62
|
|
63
|
-
_launchEmulator(emulatorName, launchCommand) {
|
64
|
-
return launchEmulatorProcess(emulatorName, this._emulatorExec, launchCommand);
|
63
|
+
_launchEmulator(emulatorName, launchCommand, adbName) {
|
64
|
+
return launchEmulatorProcess(emulatorName, this._emulatorExec, launchCommand, this._adb, adbName);
|
65
65
|
}
|
66
66
|
|
67
67
|
async _awaitEmulatorBoot(adbName) {
|
@@ -1,29 +1,15 @@
|
|
1
1
|
const fs = require('fs');
|
2
2
|
|
3
3
|
const _ = require('lodash');
|
4
|
-
const { Tail } = require('tail');
|
5
4
|
|
6
5
|
const unitLogger = require('../../../../../utils/logger').child({ cat: 'device' });
|
7
6
|
|
8
|
-
function launchEmulatorProcess(emulatorName, emulatorExec, emulatorLaunchCommand) {
|
7
|
+
function launchEmulatorProcess(emulatorName, emulatorExec, emulatorLaunchCommand, adb, adbName) {
|
9
8
|
let childProcessOutput;
|
10
|
-
|
11
9
|
const portName = emulatorLaunchCommand.port ? `-${emulatorLaunchCommand.port}` : '';
|
12
10
|
const tempLog = `./${emulatorName}${portName}.log`;
|
13
11
|
const stdout = fs.openSync(tempLog, 'a');
|
14
12
|
const stderr = fs.openSync(tempLog, 'a');
|
15
|
-
const tailOptions = {
|
16
|
-
useWatchFile: true,
|
17
|
-
fsWatchOptions: {
|
18
|
-
interval: 1500,
|
19
|
-
},
|
20
|
-
};
|
21
|
-
const tail = new Tail(tempLog, tailOptions)
|
22
|
-
.on('line', (line) => {
|
23
|
-
if (line.includes('Adb connected, start proxing data')) {
|
24
|
-
childProcessPromise._cpResolve();
|
25
|
-
}
|
26
|
-
});
|
27
13
|
|
28
14
|
function detach() {
|
29
15
|
if (childProcessOutput) {
|
@@ -32,7 +18,6 @@ function launchEmulatorProcess(emulatorName, emulatorExec, emulatorLaunchCommand
|
|
32
18
|
|
33
19
|
childProcessOutput = fs.readFileSync(tempLog, 'utf8');
|
34
20
|
|
35
|
-
tail.unwatch();
|
36
21
|
fs.closeSync(stdout);
|
37
22
|
fs.closeSync(stderr);
|
38
23
|
fs.unlink(tempLog, _.noop);
|
@@ -46,6 +31,8 @@ function launchEmulatorProcess(emulatorName, emulatorExec, emulatorLaunchCommand
|
|
46
31
|
|
47
32
|
log = log.child({ child_pid: childProcessPromise.childProcess.pid });
|
48
33
|
|
34
|
+
adb.waitForDevice(adbName).then(() => childProcessPromise._cpResolve());
|
35
|
+
|
49
36
|
return childProcessPromise.then(() => true).catch((err) => {
|
50
37
|
detach();
|
51
38
|
|
@@ -189,6 +189,10 @@ class ADB {
|
|
189
189
|
}
|
190
190
|
}
|
191
191
|
|
192
|
+
async waitForDevice(deviceId) {
|
193
|
+
return await this.adbCmd(deviceId, 'wait-for-device');
|
194
|
+
}
|
195
|
+
|
192
196
|
async apiLevel(deviceId) {
|
193
197
|
if (this._cachedApiLevels.has(deviceId)) {
|
194
198
|
return this._cachedApiLevels.get(deviceId);
|
@@ -93,7 +93,7 @@ class AppleSimUtils {
|
|
93
93
|
`(https://developer.apple.com/xcode/). In case you already have the latest Xcode version installed, ` +
|
94
94
|
`try run the command: \`sudo xcode-select -s /Applications/Xcode.app\`. If you are running tests from CI, ` +
|
95
95
|
`we recommend running them with "--headless" device configuration (see: ` +
|
96
|
-
`https://wix.github.io/Detox/docs/
|
96
|
+
`https://wix.github.io/Detox/docs/cli/test/#options).`
|
97
97
|
);
|
98
98
|
}
|
99
99
|
|
@@ -6,7 +6,9 @@ const cleanupLogData = {
|
|
6
6
|
|
7
7
|
class GenyGlobalLifecycleHandler {
|
8
8
|
constructor({ deviceCleanupRegistry, instanceLifecycleService }) {
|
9
|
+
/** @private */
|
9
10
|
this._deviceCleanupRegistry = deviceCleanupRegistry;
|
11
|
+
/** @private */
|
10
12
|
this._instanceLifecycleService = instanceLifecycleService;
|
11
13
|
}
|
12
14
|
|
package/src/errors/DetoxError.js
CHANGED
@@ -8,6 +8,10 @@ class DetoxError extends Error {
|
|
8
8
|
this.name = 'DetoxError';
|
9
9
|
}
|
10
10
|
|
11
|
+
format() {
|
12
|
+
return this.message;
|
13
|
+
}
|
14
|
+
|
11
15
|
static get reportIssue() {
|
12
16
|
return 'Please report this issue on our GitHub tracker:\nhttps://github.com/wix/Detox/issues';
|
13
17
|
}
|
@@ -32,7 +36,7 @@ class DetoxError extends Error {
|
|
32
36
|
*/
|
33
37
|
static format(err, inspectOptions = { depth: 1 }) {
|
34
38
|
if (err instanceof DetoxError) {
|
35
|
-
return err.
|
39
|
+
return err.format();
|
36
40
|
}
|
37
41
|
|
38
42
|
if (_.isError(err) && /^Command failed:/.test(err.message)) {
|
package/src/ipc/IPCClient.js
CHANGED
@@ -4,21 +4,21 @@ const { DetoxInternalError } = require('../errors');
|
|
4
4
|
const { serializeObjectWithError } = require('../utils/errorUtils');
|
5
5
|
|
6
6
|
class IPCClient {
|
7
|
-
constructor({ id, logger,
|
7
|
+
constructor({ id, logger, sessionState }) {
|
8
8
|
this._id = id;
|
9
9
|
/** @type {import('../logger/DetoxLogger')} logger */
|
10
10
|
this._logger = logger.child({ cat: 'ipc' });
|
11
11
|
/** @type {import('./SessionState')} */
|
12
|
-
this.
|
12
|
+
this._sessionState = sessionState;
|
13
13
|
|
14
|
-
this.
|
14
|
+
this._ipc = null;
|
15
15
|
this._serverConnection = null;
|
16
16
|
}
|
17
17
|
|
18
18
|
async init() {
|
19
|
-
this.
|
19
|
+
this._ipc = new IPC();
|
20
20
|
|
21
|
-
Object.assign(this.
|
21
|
+
Object.assign(this._ipc.config, {
|
22
22
|
id: this._id,
|
23
23
|
appspace: 'detox.',
|
24
24
|
logger: (msg) => this._logger.trace(msg),
|
@@ -33,14 +33,22 @@ class IPCClient {
|
|
33
33
|
async dispose() {
|
34
34
|
this._serverConnection = null;
|
35
35
|
|
36
|
-
if (this.
|
37
|
-
|
38
|
-
|
36
|
+
if (this._ipc) {
|
37
|
+
await new Promise((resolve, reject) => {
|
38
|
+
this._ipc.of[this.serverId]
|
39
|
+
// @ts-ignore
|
40
|
+
.once('disconnect', resolve)
|
41
|
+
.once('error', reject);
|
42
|
+
|
43
|
+
this._ipc.disconnect(this.serverId);
|
44
|
+
});
|
45
|
+
|
46
|
+
this._ipc = null;
|
39
47
|
}
|
40
48
|
}
|
41
49
|
|
42
50
|
get sessionState() {
|
43
|
-
return this.
|
51
|
+
return this._sessionState;
|
44
52
|
}
|
45
53
|
|
46
54
|
get serverId() {
|
@@ -49,7 +57,7 @@ class IPCClient {
|
|
49
57
|
|
50
58
|
async registerWorker(workerId) {
|
51
59
|
const sessionState = await this._emit('registerWorker', { workerId });
|
52
|
-
this.
|
60
|
+
this._sessionState.patch(sessionState);
|
53
61
|
}
|
54
62
|
|
55
63
|
/**
|
@@ -59,18 +67,18 @@ class IPCClient {
|
|
59
67
|
const sessionState = await this._emit('reportTestResults', {
|
60
68
|
testResults: testResults.map(r => serializeObjectWithError(r, 'testExecError')),
|
61
69
|
});
|
62
|
-
this.
|
70
|
+
this._sessionState.patch(sessionState);
|
63
71
|
}
|
64
72
|
|
65
73
|
async _connectToServer() {
|
66
74
|
const serverId = this.serverId;
|
67
75
|
|
68
76
|
this._serverConnection = await new Promise((resolve, reject) => {
|
69
|
-
this.
|
77
|
+
this._ipc.connectTo(serverId, (client) => {
|
70
78
|
client.of[serverId]
|
71
|
-
.
|
72
|
-
.
|
73
|
-
.
|
79
|
+
.once('error', reject)
|
80
|
+
.once('disconnect', () => reject(new DetoxInternalError('IPC server has unexpectedly disconnected.')))
|
81
|
+
.once('connect', () => resolve(client.of[serverId]));
|
74
82
|
});
|
75
83
|
});
|
76
84
|
|
@@ -79,7 +87,7 @@ class IPCClient {
|
|
79
87
|
|
80
88
|
async _registerContext() {
|
81
89
|
const sessionState = await this._emit('registerContext', { id: this._id });
|
82
|
-
this.
|
90
|
+
this._sessionState.patch(sessionState);
|
83
91
|
}
|
84
92
|
|
85
93
|
async _emit(event, payload) {
|
@@ -90,6 +98,7 @@ class IPCClient {
|
|
90
98
|
return new Promise((resolve, reject) => {
|
91
99
|
const server = this._serverConnection;
|
92
100
|
|
101
|
+
/* istanbul ignore next */
|
93
102
|
function onError(err) {
|
94
103
|
server.off('error', onError);
|
95
104
|
server.off(`${event}Done`, onDone);
|
@@ -110,7 +119,7 @@ class IPCClient {
|
|
110
119
|
}
|
111
120
|
|
112
121
|
_onSessionStateUpdate = (payload) => {
|
113
|
-
this.
|
122
|
+
this._sessionState.patch(payload);
|
114
123
|
};
|
115
124
|
}
|
116
125
|
|
package/src/ipc/IPCServer.js
CHANGED
@@ -14,12 +14,17 @@ class IPCServer {
|
|
14
14
|
this._logger = logger.child({ cat: 'ipc,ipc-server' });
|
15
15
|
this._ipc = null;
|
16
16
|
this._workers = new Set();
|
17
|
+
this._contexts = new Set();
|
17
18
|
}
|
18
19
|
|
19
20
|
get id() {
|
20
21
|
return this._sessionState.detoxIPCServer;
|
21
22
|
}
|
22
23
|
|
24
|
+
get contexts() {
|
25
|
+
return [...this._contexts];
|
26
|
+
}
|
27
|
+
|
23
28
|
get sessionState() {
|
24
29
|
return this._sessionState;
|
25
30
|
}
|
@@ -45,15 +50,18 @@ class IPCServer {
|
|
45
50
|
return;
|
46
51
|
}
|
47
52
|
|
48
|
-
|
53
|
+
await new Promise((resolve, reject) =>{
|
49
54
|
// @ts-ignore
|
50
|
-
this._ipc.server.server.close(e =>
|
55
|
+
this._ipc.server.server.close(e => /* istanbul ignore next */
|
56
|
+
e ? reject(e) : resolve());
|
51
57
|
this._ipc.server.stop();
|
52
58
|
});
|
59
|
+
|
60
|
+
this._ipc = null;
|
53
61
|
}
|
54
62
|
|
55
63
|
onRegisterContext({ id }, socket) {
|
56
|
-
this.
|
64
|
+
this._contexts.add(id);
|
57
65
|
|
58
66
|
this._ipc.server.emit(socket, 'registerContextDone', {
|
59
67
|
testResults: this._sessionState.testResults,
|
package/src/ipc/SessionState.js
CHANGED
@@ -9,7 +9,6 @@ const context = vm.createContext({ require }, {
|
|
9
9
|
class SessionState {
|
10
10
|
constructor({
|
11
11
|
id = '',
|
12
|
-
contexts = [],
|
13
12
|
detoxConfig = null,
|
14
13
|
detoxIPCServer = '',
|
15
14
|
testResults = [],
|
@@ -17,7 +16,6 @@ class SessionState {
|
|
17
16
|
workersCount = 0
|
18
17
|
}) {
|
19
18
|
this.id = id;
|
20
|
-
this.contexts = contexts;
|
21
19
|
this.detoxConfig = detoxConfig;
|
22
20
|
this.detoxIPCServer = detoxIPCServer;
|
23
21
|
this.testResults = testResults;
|
@@ -30,7 +28,7 @@ class SessionState {
|
|
30
28
|
}
|
31
29
|
|
32
30
|
stringify() {
|
33
|
-
return cycle.stringify(this, SessionState.
|
31
|
+
return cycle.stringify(this, SessionState._stringifier);
|
34
32
|
}
|
35
33
|
|
36
34
|
/**
|
@@ -39,10 +37,10 @@ class SessionState {
|
|
39
37
|
static parse(stringified) {
|
40
38
|
const Class = this; // eslint-disable-line unicorn/no-this-assignment
|
41
39
|
// @ts-ignore
|
42
|
-
return new Class(cycle.parse(stringified, SessionState.
|
40
|
+
return new Class(cycle.parse(stringified, SessionState._reviver));
|
43
41
|
}
|
44
42
|
|
45
|
-
static
|
43
|
+
static _reviver(key, val) {
|
46
44
|
if (typeof val === 'object' && val !== null && typeof val.$fn == 'string') {
|
47
45
|
return vm.runInContext(val.$fn, context);
|
48
46
|
} else {
|
@@ -50,7 +48,7 @@ class SessionState {
|
|
50
48
|
}
|
51
49
|
}
|
52
50
|
|
53
|
-
static
|
51
|
+
static _stringifier(key, val) {
|
54
52
|
if (typeof val === 'function') {
|
55
53
|
return { $fn: `(${val})` };
|
56
54
|
} else {
|
@@ -19,11 +19,12 @@ const sanitizeBunyanContext = require('./utils/sanitizeBunyanContext');
|
|
19
19
|
* @property {CategoryThreadDispatcher} [dispatcher]
|
20
20
|
* @property {BunyanLogger} [bunyan]
|
21
21
|
* @property {MessageStack} [messageStack]
|
22
|
+
* @property {boolean} [unsafeMode] Disables sanitization of user input, used for integration tests.
|
22
23
|
*/
|
23
24
|
|
24
25
|
class DetoxLogger {
|
25
26
|
/**
|
26
|
-
* @param {
|
27
|
+
* @param {SharedLoggerConfig} sharedConfig
|
27
28
|
* @param {object} [context]
|
28
29
|
*/
|
29
30
|
constructor(sharedConfig, context) {
|
@@ -91,7 +92,7 @@ class DetoxLogger {
|
|
91
92
|
* @returns {DetoxLogger}
|
92
93
|
*/
|
93
94
|
child(overrides) {
|
94
|
-
const merged = this._mergeContexts(this._context,
|
95
|
+
const merged = this._mergeContexts(this._context, this._sanitizeContext(overrides));
|
95
96
|
return new DetoxLogger(this._sharedConfig, merged);
|
96
97
|
}
|
97
98
|
|
@@ -119,6 +120,25 @@ class DetoxLogger {
|
|
119
120
|
this.overrideConsole();
|
120
121
|
}
|
121
122
|
|
123
|
+
/**
|
124
|
+
* Closes the file descriptors to make sure that the temporary
|
125
|
+
* JSONL files are flushed and contain the last error messages.
|
126
|
+
* This safety measure is especially important for Windows OS.
|
127
|
+
*
|
128
|
+
* @async
|
129
|
+
* @internal
|
130
|
+
*/
|
131
|
+
async close() {
|
132
|
+
if (this._context) {
|
133
|
+
throw new DetoxInternalError(
|
134
|
+
'Trying to close file streams from a non-root logger.\n' +
|
135
|
+
'If you are not fiddling with Detox internals on purpose, yet you see this error, then...'
|
136
|
+
);
|
137
|
+
}
|
138
|
+
|
139
|
+
await this._sharedConfig.bunyan.closeFileStreams();
|
140
|
+
}
|
141
|
+
|
122
142
|
/**
|
123
143
|
* @internal
|
124
144
|
*/
|
@@ -192,7 +212,7 @@ class DetoxLogger {
|
|
192
212
|
|
193
213
|
/** @private */
|
194
214
|
_beginInternal(level, context, msg) {
|
195
|
-
this._sharedConfig.messageStack.push(context
|
215
|
+
this._sharedConfig.messageStack.push(context, msg);
|
196
216
|
this._sharedConfig.bunyan.logger[level](context, ...msg);
|
197
217
|
}
|
198
218
|
|
@@ -204,7 +224,7 @@ class DetoxLogger {
|
|
204
224
|
|
205
225
|
/** @private */
|
206
226
|
_endInternal(level, context, msg) {
|
207
|
-
const beginMsg = this._sharedConfig.messageStack.pop(context
|
227
|
+
const beginMsg = this._sharedConfig.messageStack.pop(context);
|
208
228
|
if (msg.length === 0) {
|
209
229
|
msg = beginMsg;
|
210
230
|
}
|
@@ -272,12 +292,21 @@ class DetoxLogger {
|
|
272
292
|
const context = this._mergeContexts(
|
273
293
|
this._context,
|
274
294
|
boundContext,
|
275
|
-
|
295
|
+
this._sanitizeContext(userContext),
|
276
296
|
);
|
277
297
|
|
278
298
|
return { context, msg };
|
279
299
|
}
|
280
300
|
|
301
|
+
/** @private */
|
302
|
+
_sanitizeContext(context) {
|
303
|
+
if (this._sharedConfig.unsafeMode) {
|
304
|
+
return context;
|
305
|
+
}
|
306
|
+
|
307
|
+
return sanitizeBunyanContext(context);
|
308
|
+
}
|
309
|
+
|
281
310
|
/** @internal */
|
282
311
|
static defaultOptions({ level }) {
|
283
312
|
const ph = level === 'trace' || level === 'debug'
|
@@ -71,6 +71,45 @@ class BunyanLogger {
|
|
71
71
|
|
72
72
|
return this;
|
73
73
|
}
|
74
|
+
|
75
|
+
async closeFileStreams() {
|
76
|
+
const { _closeStream } = BunyanLogger;
|
77
|
+
const internalBunyanStreams = this._bunyan['streams'];
|
78
|
+
const openFileStreams = _.filter(internalBunyanStreams, this._isOpenFileStream);
|
79
|
+
_.remove(internalBunyanStreams, openFileStreams);
|
80
|
+
|
81
|
+
await Promise.all(openFileStreams.map(_closeStream));
|
82
|
+
}
|
83
|
+
|
84
|
+
/** @private */
|
85
|
+
_isOpenFileStream = (bunyanStream) => {
|
86
|
+
switch (bunyanStream.type) {
|
87
|
+
case 'file':
|
88
|
+
return bunyanStream.path && !bunyanStream.stream.destroyed;
|
89
|
+
case 'raw':
|
90
|
+
/* istanbul ignore next */
|
91
|
+
const stream = bunyanStream.stream === this._debugStream.stream
|
92
|
+
? bunyanStream.stream._out
|
93
|
+
: bunyanStream.stream;
|
94
|
+
|
95
|
+
/* istanbul ignore next */
|
96
|
+
return stream.fd !== undefined && !stream.closed;
|
97
|
+
}
|
98
|
+
};
|
99
|
+
|
100
|
+
/** @private */
|
101
|
+
static _closeStream(bunyanStream) {
|
102
|
+
return new Promise((resolve, reject) => {
|
103
|
+
bunyanStream.stream.end((err) => {
|
104
|
+
/* istanbul ignore next */
|
105
|
+
if (err) {
|
106
|
+
reject(err);
|
107
|
+
} else {
|
108
|
+
resolve();
|
109
|
+
}
|
110
|
+
});
|
111
|
+
});
|
112
|
+
}
|
74
113
|
}
|
75
114
|
|
76
115
|
module.exports = BunyanLogger;
|
@@ -1,4 +1,5 @@
|
|
1
1
|
const ThreadDispatcher = require('./ThreadDispatcher');
|
2
|
+
const getMainCategory = require('./getMainCategory');
|
2
3
|
|
3
4
|
class CategoryThreadDispatcher {
|
4
5
|
constructor() {
|
@@ -24,7 +25,7 @@ class CategoryThreadDispatcher {
|
|
24
25
|
|
25
26
|
/** @returns {ThreadDispatcher} */
|
26
27
|
_resolveDispatcher(cat) {
|
27
|
-
const mainCategory = cat
|
28
|
+
const mainCategory = getMainCategory(cat);
|
28
29
|
if (!this._dispatchers[mainCategory]) {
|
29
30
|
this._dispatchers[mainCategory] = new ThreadDispatcher(mainCategory);
|
30
31
|
}
|