detox 20.1.0-next-is-hittable-check.0 → 20.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. package/Detox-android/com/wix/detox/{20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-javadoc.jar → 20.1.0/detox-20.1.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-sources.jar → 20.1.0/detox-20.1.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.pom → 20.1.0/detox-20.1.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.1.0/detox-20.1.0.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/build.gradle +0 -1
  29. package/android/detox/src/full/java/com/wix/detox/TestEngineFacade.kt +3 -3
  30. package/android/detox/src/full/java/com/wix/detox/adapters/server/QueryStatusActionHandler.kt +12 -80
  31. package/android/detox/src/full/java/com/wix/detox/espresso/common/UiControllerImplReflected.kt +16 -0
  32. package/android/detox/src/full/java/com/wix/detox/espresso/idlingresources/DescriptiveIdlingResource.kt +8 -0
  33. package/android/detox/src/full/java/com/wix/detox/espresso/registry/BusyResourcesInquirer.kt +48 -0
  34. package/android/detox/src/full/java/com/wix/detox/inquiry/DetoxBusyResource.kt +92 -0
  35. package/android/detox/src/full/java/com/wix/detox/{reactnative/idlingresources/IdlingResourceDescription.kt → inquiry/DetoxBusyResourceDescription.kt} +6 -6
  36. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +18 -7
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResource.kt +2 -4
  38. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +12 -6
  39. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +2 -0
  40. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +14 -8
  41. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +1 -6
  42. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +1 -1
  43. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +4 -6
  44. package/android/detox/src/testFull/java/com/wix/detox/adapters/server/QueryStatusActionHandlerSpec.kt +35 -94
  45. package/android/detox/src/testFull/java/com/wix/detox/espresso/registry/{IRStatusInquirerTest.kt → BusyResourcesInquirerTest.kt} +46 -7
  46. package/android/detox/src/testFull/java/com/wix/detox/{reactnative/idlingresources/IdlingResourceDescriptionSpec.kt → inquiry/DetoxBusyResourceDescriptionSpec.kt} +6 -6
  47. package/android/detox/src/testFull/java/com/wix/detox/inquiry/DetoxBusyResourceSpec.kt +134 -0
  48. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +4 -5
  49. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +5 -5
  50. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +4 -6
  51. package/index.d.ts +102 -18
  52. package/internals.d.ts +34 -9
  53. package/local-cli/cli.js +6 -3
  54. package/local-cli/init.js +1 -1
  55. package/local-cli/test.js +6 -6
  56. package/local-cli/testCommand/TestRunnerCommand.js +97 -94
  57. package/local-cli/testCommand/TestRunnerError.js +17 -0
  58. package/local-cli/testCommand/builder.js +0 -1
  59. package/local-cli/testCommand/middlewares.js +4 -13
  60. package/local-cli/testCommand/warnings.js +0 -3
  61. package/package.json +18 -15
  62. package/runners/deprecation.js +42 -44
  63. package/runners/jest/index.d.ts +60 -0
  64. package/runners/jest/index.js +3 -8
  65. package/runners/jest/reporters/DetoxReporter.js +21 -10
  66. package/runners/jest/testEnvironment/index.js +57 -41
  67. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +62 -35
  68. package/runners/jest/testEnvironment/listeners/SpecReporter.js +12 -14
  69. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +1 -5
  70. package/runners/jest/testEnvironment/utils/assertJestCircus27.js +17 -3
  71. package/src/DetoxWorker.js +95 -49
  72. package/src/android/interactions/native.js +3 -2
  73. package/src/artifacts/ArtifactsManager.js +6 -6
  74. package/src/artifacts/utils/temporaryPath.js +32 -2
  75. package/src/client/actions/SyncStatusSchema.json +21 -0
  76. package/src/client/actions/formatters/SyncStatusFormatter.js +2 -0
  77. package/src/client/actions/formatters/sync-resources/BgThreadFormatter.js +5 -0
  78. package/src/configuration/collectCliConfig.js +1 -12
  79. package/src/configuration/composeRunnerConfig.js +5 -4
  80. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -3
  81. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -16
  82. package/src/devices/common/drivers/android/exec/ADB.js +4 -0
  83. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
  84. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +4 -0
  85. package/src/devices/runtime/RuntimeDevice.js +3 -3
  86. package/src/errors/DetoxConfigErrorComposer.js +6 -1
  87. package/src/errors/DetoxError.js +5 -1
  88. package/src/ios/expectTwo.js +3 -2
  89. package/src/ipc/IPCClient.js +26 -17
  90. package/src/ipc/IPCServer.js +11 -3
  91. package/src/ipc/SessionState.js +11 -11
  92. package/src/logger/DetoxLogger.js +63 -43
  93. package/src/logger/index.js +1 -0
  94. package/src/logger/utils/BunyanLogger.js +50 -7
  95. package/src/logger/utils/CategoryThreadDispatcher.js +8 -29
  96. package/src/logger/utils/DetoxLogFinalizer.js +166 -0
  97. package/src/logger/utils/MessageStack.js +17 -6
  98. package/src/logger/utils/ThreadDispatcher.js +5 -25
  99. package/src/logger/utils/customConsoleLogger.js +22 -5
  100. package/src/logger/utils/getMainCategory.js +5 -0
  101. package/src/logger/utils/sanitizeBunyanContext.js +3 -1
  102. package/src/logger/utils/streams/BunyanTransformer.js +72 -0
  103. package/src/logger/utils/streams/ChromeTraceTransformer.js +132 -0
  104. package/src/logger/utils/streams/DetoxJSONLParser.js +31 -0
  105. package/src/logger/utils/streams/JSONLStringer.js +55 -0
  106. package/src/logger/utils/streams/index.js +7 -0
  107. package/src/logger/utils/streams/transformers.js +39 -0
  108. package/src/logger/utils/tracerLegacy.js +14 -25
  109. package/src/realms/DetoxContext.js +11 -7
  110. package/src/realms/DetoxInternalsFacade.js +0 -6
  111. package/src/realms/DetoxPrimaryContext.js +42 -87
  112. package/src/realms/DetoxSecondaryContext.js +8 -12
  113. package/src/utils/argparse.js +11 -0
  114. package/src/utils/logger.js +1 -1
  115. package/src/utils/pathUtils.js +11 -0
  116. package/src/utils/shellUtils.js +17 -0
  117. package/src/utils/traceInvocationCall.js +21 -0
  118. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-javadoc.jar.md5 +0 -1
  119. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-javadoc.jar.sha1 +0 -1
  120. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-javadoc.jar.sha256 +0 -1
  121. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-javadoc.jar.sha512 +0 -1
  122. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-sources.jar.md5 +0 -1
  123. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-sources.jar.sha1 +0 -1
  124. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-sources.jar.sha256 +0 -1
  125. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0-sources.jar.sha512 +0 -1
  126. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.aar +0 -0
  127. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.aar.md5 +0 -1
  128. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.aar.sha1 +0 -1
  129. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.aar.sha256 +0 -1
  130. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.aar.sha512 +0 -1
  131. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.pom.md5 +0 -1
  132. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.pom.sha1 +0 -1
  133. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.pom.sha256 +0 -1
  134. package/Detox-android/com/wix/detox/20.1.0-next-is-hittable-check.0/detox-20.1.0-next-is-hittable-check.0.pom.sha512 +0 -1
  135. package/android/detox/src/full/java/com/wix/detox/espresso/registry/IRStatusInquirer.kt +0 -24
  136. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DescriptiveIdlingResource.kt +0 -10
  137. package/local-cli/build.test.js +0 -104
  138. package/local-cli/run-server.test.js +0 -23
  139. package/local-cli/test.test.js +0 -569
  140. package/runners/jest/deprecation.js +0 -25
  141. package/runners/jest/testEnvironment/utils/assertJestCircus27.test.js +0 -23
  142. package/src/configuration/utils/warnings.js +0 -12
  143. package/src/logger/utils/streamUtils.js +0 -240
  144. package/src/utils/trace.js +0 -3
@@ -0,0 +1,132 @@
1
+ const { AbstractEventBuilder } = require('trace-event-lib');
2
+
3
+ const getMainCategory = require('../getMainCategory');
4
+
5
+ const JSONLStringer = require('./JSONLStringer');
6
+ const { flatMapTransform } = require('./transformers');
7
+
8
+ class ChromeTraceTransformer {
9
+ constructor() {
10
+ /** @type {Map<string, number>} */
11
+ this._globalThreadMap = null;
12
+ }
13
+
14
+ /**
15
+ * @param {NodeJS.ReadableStream} eventStream
16
+ */
17
+ async scanThreadIDs(eventStream) {
18
+ const processes = await new Promise((resolve, reject) => {
19
+ const result = {};
20
+ eventStream
21
+ .on('end', () => resolve(result))
22
+ .on('error', /* istanbul ignore next */ (err) => reject(err))
23
+ .on('data', (event) => {
24
+ const { ph, pid, tid, cat } = event;
25
+ if (ph === 'B' || ph === 'i') {
26
+ const categories = (result[pid] = result[pid] || {});
27
+ const mainCategory = String(cat).split(',')[0];
28
+ const tids = (categories[mainCategory] = categories[mainCategory] || []);
29
+ if (!tids.includes(tid)) {
30
+ tids.push(tid);
31
+ }
32
+ }
33
+ });
34
+ });
35
+
36
+ const tidArray = Object.entries(processes).flatMap(([pid, categories]) => {
37
+ return Object.entries(categories).flatMap(([category, tids]) => {
38
+ return tids.map(tid => `${pid}:${category}:${tid}`);
39
+ });
40
+ });
41
+
42
+ this._globalThreadMap = new Map(tidArray.map((hash, index) => [hash, index]));
43
+ }
44
+
45
+ /**
46
+ * @returns {module:stream.internal.Transform}
47
+ */
48
+ createStream() {
49
+ const transformFn = this._transformBunyanRecord.bind(this, {
50
+ primaryPid: NaN,
51
+ knownPids: new Set(),
52
+ knownTids: new Set(),
53
+ });
54
+
55
+ return flatMapTransform(transformFn);
56
+ }
57
+
58
+ createSerializedStream() {
59
+ const writable = this.createStream();
60
+ const readable = JSONLStringer.serializeJSON();
61
+ writable.pipe(readable);
62
+ return { writable, readable };
63
+ }
64
+
65
+ /**
66
+ * @param {{ knownPids: Set<number>; knownTids: Set<number>; primaryPid: number; }} state
67
+ * @param {*} bunyanLogRecord
68
+ * @returns {import('trace-event-lib').Event[]}
69
+ * @private
70
+ */
71
+ _transformBunyanRecord(state, bunyanLogRecord) {
72
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
73
+ const { cat: rawCat, msg: name, ph, pid, tid: _tid, time, name: _name, hostname: _hostname, ...args } = bunyanLogRecord;
74
+ const ts = new Date(time).getTime() * 1E3;
75
+ const cat = rawCat || 'undefined';
76
+ const tid = this._resolveGlobalTID(bunyanLogRecord);
77
+
78
+ const builder = new SimpleEventBuilder();
79
+ if (!state.knownPids.has(pid)) {
80
+ if (Number.isNaN(state.primaryPid)) {
81
+ state.primaryPid = pid;
82
+ }
83
+
84
+ builder.metadata({ pid, ts, name: 'process_name', args: { name: pid === state.primaryPid ? 'primary' : 'secondary' } });
85
+ builder.metadata({ pid, ts, name: 'process_sort_index', args: { sort_index: state.knownPids.size } });
86
+ state.knownPids.add(pid);
87
+ }
88
+
89
+ if (!state.knownTids.has(tid)) {
90
+ const mainCategory = getMainCategory(cat);
91
+ builder.metadata({ pid, tid, ts, name: 'thread_name', args: { name: mainCategory } });
92
+ builder.metadata({ pid, tid, ts, name: 'thread_sort_index', args: { sort_index: tid } });
93
+ state.knownTids.add(tid);
94
+ }
95
+
96
+ const event = { ph, name, pid, tid, cat, ts, args };
97
+ if (ph === 'E') {
98
+ delete event.name;
99
+ }
100
+
101
+ builder.events.push(event);
102
+ return builder.events;
103
+ }
104
+
105
+ _resolveGlobalTID(event) {
106
+ const hash = this._computeThreadHash(event);
107
+ const tid = this._globalThreadMap ? this._globalThreadMap.get(hash) : event.tid;
108
+
109
+ // Impossible condition, but anyway it is better to be safe than sorry.
110
+ /* istanbul ignore next */
111
+ return tid === undefined ? ChromeTraceTransformer.ERROR_TID : tid;
112
+ }
113
+
114
+ _computeThreadHash({ pid, tid, cat }) {
115
+ return `${pid}:${getMainCategory(cat)}:${tid}`;
116
+ }
117
+
118
+ /* istanbul ignore next */
119
+ static get ERROR_TID() {
120
+ return 37707;
121
+ }
122
+ }
123
+
124
+ class SimpleEventBuilder extends AbstractEventBuilder {
125
+ events = [];
126
+
127
+ send(event) {
128
+ this.events.push(event);
129
+ }
130
+ }
131
+
132
+ module.exports = ChromeTraceTransformer;
@@ -0,0 +1,31 @@
1
+ const JsonlParser = require('stream-json/jsonl/Parser');
2
+
3
+ const { through } = require('./transformers');
4
+
5
+ class DetoxJSONLParser {
6
+ constructor(log) {
7
+ this._log = log;
8
+ }
9
+
10
+ createTransformer() {
11
+ const log = this._log;
12
+ const readable = through();
13
+ const writable = JsonlParser.make({ checkErrors: true })
14
+ .on('error', (err) => {
15
+ /* istanbul ignore else */
16
+ if (err instanceof SyntaxError) {
17
+ log.debug({ err });
18
+ readable.end();
19
+ } else {
20
+ readable.emit('error', err);
21
+ }
22
+ });
23
+
24
+ return {
25
+ writable,
26
+ readable: writable.pipe(readable),
27
+ };
28
+ }
29
+ }
30
+
31
+ module.exports = DetoxJSONLParser;
@@ -0,0 +1,55 @@
1
+ const { Transform } = require('stream');
2
+
3
+ class JSONLStringer extends Transform {
4
+ constructor({ replacer, header, delimiter, footer }) {
5
+ super({ writableObjectMode: true, readableObjectMode: false });
6
+
7
+ this._replacer = replacer;
8
+ this._header = header;
9
+ this._delimiter = delimiter;
10
+ this._footer = footer;
11
+ }
12
+
13
+ _transform(chunk, _, callback) {
14
+ if (this._header) {
15
+ this.push(this._header);
16
+ }
17
+
18
+ this.push(JSON.stringify(chunk, this._replacer));
19
+ this._transform = this._nextTransform;
20
+ callback(null);
21
+ }
22
+
23
+ _nextTransform(chunk, _, callback) {
24
+ this.push(this._delimiter + JSON.stringify(chunk, this._replacer));
25
+ callback(null);
26
+ }
27
+
28
+ _flush(callback) {
29
+ if (this._footer) {
30
+ this.push(this._footer);
31
+ }
32
+
33
+ callback();
34
+ }
35
+
36
+ static serializeJSONL() {
37
+ return new JSONLStringer({
38
+ replacer: undefined,
39
+ header: '',
40
+ delimiter: '\n',
41
+ footer: '',
42
+ });
43
+ }
44
+
45
+ static serializeJSON() {
46
+ return new JSONLStringer({
47
+ replacer: undefined,
48
+ header: '[\n\t',
49
+ delimiter: ',\n\t',
50
+ footer: '\n]\n',
51
+ });
52
+ }
53
+ }
54
+
55
+ module.exports = JSONLStringer;
@@ -0,0 +1,7 @@
1
+ const BunyanTransformer = require('./BunyanTransformer');
2
+ const ChromeTraceTransformer = require('./ChromeTraceTransformer');
3
+
4
+ module.exports = {
5
+ BunyanTransformer,
6
+ ChromeTraceTransformer,
7
+ };
@@ -0,0 +1,39 @@
1
+ const { PassThrough, Transform } = require('stream');
2
+
3
+ function through() {
4
+ return new PassThrough({ objectMode: true });
5
+ }
6
+
7
+ function mapTransform(fn) {
8
+ return new Transform({
9
+ objectMode: true,
10
+ transform(chunk, encoding, callback){
11
+ this.push(fn(chunk));
12
+ callback();
13
+ },
14
+ });
15
+ }
16
+
17
+ function flatMapTransform(fn) {
18
+ let index = 0;
19
+
20
+ return new Transform({
21
+ objectMode: true,
22
+ transform(chunk, encoding, callback){
23
+ const results = fn(chunk, index++);
24
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
25
+ results.forEach(pushThis, this);
26
+ callback();
27
+ },
28
+ });
29
+ }
30
+
31
+ function pushThis(x) {
32
+ return this.push(x);
33
+ }
34
+
35
+ module.exports = {
36
+ through,
37
+ mapTransform,
38
+ flatMapTransform,
39
+ };
@@ -1,45 +1,34 @@
1
1
  const methods = {
2
2
  startSection(logger) {
3
- return (msg, args) => logger.trace.begin(args, msg);
3
+ return (msg, args) => {
4
+ if (args !== undefined) {
5
+ return logger.trace.begin(args, msg);
6
+ } else {
7
+ return logger.trace.begin(msg);
8
+ }
9
+ };
4
10
  },
5
11
 
6
12
  endSection(logger) {
7
- return (msg, args) => logger.trace.end(args);
13
+ return (_msg, args) => {
14
+ if (args !== undefined) {
15
+ return logger.trace.end(args);
16
+ } else {
17
+ return logger.trace.end();
18
+ }
19
+ };
8
20
  },
9
21
 
10
22
  traceCall(logger) {
11
23
  return (name, action, args = {}) => logger.trace.complete(args, name, action);
12
24
  },
13
-
14
- invocationCall(logger) {
15
- return (sectionName, invocation, action) => {
16
- return logger.trace.complete({
17
- cat: 'ws-client,ws-client-invocation',
18
- data: invocation,
19
- stack: _getCallStackTrace(),
20
- }, sectionName, action);
21
- };
22
- },
23
25
  };
24
26
 
25
- function _getCallStackTrace() {
26
- return new Error().stack
27
- .split('\n')
28
- .slice(1) // Ignore Error message
29
- .map(line => line
30
- .replace(/^\s*at\s+/, '')
31
- .replace(process.cwd(), '')
32
- )
33
- .filter(line => !line.includes('/detox/src')) // Ignore detox internal calls
34
- .join('\n');
35
- }
36
-
37
27
  function installLegacyTracerInterface(logger, target) {
38
28
  target.traceCall = methods.traceCall(logger);
39
29
  target.trace = Object.freeze({
40
30
  startSection: methods.startSection(logger),
41
31
  endSection: methods.endSection(logger),
42
- invocationCall: methods.invocationCall(logger),
43
32
  });
44
33
 
45
34
  return this;
@@ -2,16 +2,19 @@ const funpermaproxy = require('funpermaproxy');
2
2
 
3
3
  const temporary = require('../artifacts/utils/temporaryPath');
4
4
  const { DetoxRuntimeError } = require('../errors');
5
- const { DetoxLogger, installLegacyTracerInterface } = require('../logger');
5
+ const { DetoxLogger, DetoxLogFinalizer, installLegacyTracerInterface } = require('../logger');
6
6
  const symbols = require('../symbols');
7
7
 
8
8
  const DetoxConstants = require('./DetoxConstants');
9
9
 
10
+ //#region Protected symbols
10
11
  const $cleanup = Symbol('cleanup');
12
+ const $logFinalizer = Symbol('logFinalizer');
11
13
  const $restoreSessionState = Symbol('restoreSessionState');
12
14
  const $sessionState = Symbol('restoreSessionState');
13
15
  const $status = Symbol('status');
14
16
  const $worker = Symbol('worker');
17
+ //#endregion
15
18
 
16
19
  class DetoxContext {
17
20
  constructor() {
@@ -56,6 +59,11 @@ class DetoxContext {
56
59
  this.log = this[symbols.logger].child({ cat: 'user' });
57
60
  installLegacyTracerInterface(this.log, this);
58
61
 
62
+ this[$logFinalizer] = new DetoxLogFinalizer({
63
+ session: this[$sessionState],
64
+ logger: this[symbols.logger],
65
+ });
66
+
59
67
  /** @type {import('../DetoxWorker') | null} */
60
68
  this[$worker] = null;
61
69
  }
@@ -89,12 +97,7 @@ class DetoxContext {
89
97
  [symbols.config] = funpermaproxy(() => this[symbols.session].detoxConfig);
90
98
  [symbols.session] = funpermaproxy(() => this[$sessionState]);
91
99
  [symbols.tracing] = Object.freeze({
92
- createEventStream: () => {
93
- const streamUtils = require('../logger/utils/streamUtils');
94
- return streamUtils
95
- .uniteSessionLogs(this[$sessionState].id)
96
- .pipe(streamUtils.chromeTraceStream());
97
- },
100
+ createEventStream: () => this[$logFinalizer].createEventStream(),
98
101
  });
99
102
  /** @abstract */
100
103
  [symbols.reportTestResults](_testResults) {}
@@ -173,6 +176,7 @@ class DetoxContext {
173
176
  module.exports = DetoxContext;
174
177
  module.exports.protected = {
175
178
  $cleanup,
179
+ $logFinalizer,
176
180
  $restoreSessionState,
177
181
  $status,
178
182
  $sessionState,
@@ -15,16 +15,10 @@ class DetoxInternalsFacade {
15
15
  this.installWorker = context[symbols.installWorker];
16
16
  this.uninstallWorker = context[symbols.uninstallWorker];
17
17
  this.onHookFailure = context[symbols.onHookFailure];
18
- this.onHookStart = context[symbols.onHookStart];
19
- this.onHookSuccess = context[symbols.onHookSuccess];
20
18
  this.onRunDescribeFinish = context[symbols.onRunDescribeFinish];
21
19
  this.onRunDescribeStart = context[symbols.onRunDescribeStart];
22
- this.onRunFinish = context[symbols.onRunFinish];
23
- this.onRunStart = context[symbols.onRunStart];
24
20
  this.onTestDone = context[symbols.onTestDone];
25
21
  this.onTestFnFailure = context[symbols.onTestFnFailure];
26
- this.onTestFnStart = context[symbols.onTestFnStart];
27
- this.onTestFnSuccess = context[symbols.onTestFnSuccess];
28
22
  this.onTestStart = context[symbols.onTestStart];
29
23
  this.reportTestResults = context[symbols.reportTestResults];
30
24
  this.resolveConfig = context[symbols.resolveConfig];
@@ -1,34 +1,31 @@
1
- const path = require('path');
2
1
  const { URL } = require('url');
3
- const { promisify } = require('util');
4
2
 
5
3
  const fs = require('fs-extra');
6
- const glob = require('glob');
7
- const pipe = require('multipipe');
8
4
  const onSignalExit = require('signal-exit');
9
5
 
10
6
  const temporary = require('../artifacts/utils/temporaryPath');
11
7
  const { DetoxRuntimeError } = require('../errors');
12
8
  const SessionState = require('../ipc/SessionState');
13
9
  const symbols = require('../symbols');
14
-
15
- const globAsync = promisify(glob);
16
- const globSync = glob.sync;
10
+ const { getCurrentCommand } = require('../utils/argparse');
11
+ const uuid = require('../utils/uuid');
17
12
 
18
13
  const DetoxContext = require('./DetoxContext');
19
14
 
20
- const { $restoreSessionState, $sessionState, $worker } = DetoxContext.protected;
15
+ // Protected symbols
16
+ const { $logFinalizer, $restoreSessionState, $sessionState, $worker } = DetoxContext.protected;
21
17
 
22
- const _finalizeLogs = Symbol('finalizeLogs');
23
- const _finalizeLogsSync = Symbol('finalizeLogsSync');
18
+ //#region Private symbols
24
19
  const _globalLifecycleHandler = Symbol('globalLifecycleHandler');
25
20
  const _ipcServer = Symbol('ipcServer');
26
21
  const _resetLockFile = Symbol('resetLockFile');
27
22
  const _wss = Symbol('wss');
28
23
  const _dirty = Symbol('dirty');
29
24
  const _emergencyTeardown = Symbol('emergencyTeardown');
30
- const _areLogsEnabled = Symbol('areLogsEnabled');
31
25
  const _lifecycleLogger = Symbol('lifecycleLogger');
26
+ const _sessionFile = Symbol('sessionFile');
27
+ const _logFinalError = Symbol('logFinalError');
28
+ //#endregion
32
29
 
33
30
  class DetoxPrimaryContext extends DetoxContext {
34
31
  constructor() {
@@ -37,6 +34,8 @@ class DetoxPrimaryContext extends DetoxContext {
37
34
  this[_dirty] = false;
38
35
  this[_wss] = null;
39
36
  this[_globalLifecycleHandler] = null;
37
+ /** Path to file where the initial session object is serialized */
38
+ this[_sessionFile] = '';
40
39
  /**
41
40
  * @type {import('../ipc/IPCServer') | null}
42
41
  */
@@ -88,9 +87,11 @@ class DetoxPrimaryContext extends DetoxContext {
88
87
  await this[symbols.logger].setConfig(loggerConfig);
89
88
 
90
89
  this[_lifecycleLogger].trace.begin({
90
+ cwd: process.cwd(),
91
91
  data: this[$sessionState],
92
- }, process.argv.slice(1).join(' '));
92
+ }, getCurrentCommand());
93
93
 
94
+ // TODO: IPC Server creation ought to be delegated to a generator/factory.
94
95
  const IPCServer = require('../ipc/IPCServer');
95
96
  this[_ipcServer] = new IPCServer({
96
97
  sessionState: this[$sessionState],
@@ -110,6 +111,7 @@ class DetoxPrimaryContext extends DetoxContext {
110
111
  await this[_resetLockFile]();
111
112
  }
112
113
 
114
+ // TODO: Detox-server creation ought to be delegated to a generator/factory.
113
115
  const DetoxServer = require('../server/DetoxServer');
114
116
  if (sessionConfig.autoStart) {
115
117
  this[_wss] = new DetoxServer({
@@ -122,15 +124,18 @@ class DetoxPrimaryContext extends DetoxContext {
122
124
  await this[_wss].open();
123
125
  }
124
126
 
127
+ // TODO: double check that this config is indeed propogated onto the client create at the detox-worker side
125
128
  if (!sessionConfig.server && this[_wss]) {
126
129
  // @ts-ignore
127
130
  sessionConfig.server = `ws://localhost:${this[_wss].port}`;
128
131
  }
129
132
 
130
- await fs.writeFile(this[$sessionState].detoxConfigSnapshotPath, this[$sessionState].stringify());
131
- process.env.DETOX_CONFIG_SNAPSHOT_PATH = this[$sessionState].detoxConfigSnapshotPath;
133
+ this[_sessionFile] = temporary.for.json(this[$sessionState].id);
134
+ await fs.writeFile(this[_sessionFile], this[$sessionState].stringify());
135
+ process.env.DETOX_CONFIG_SNAPSHOT_PATH = this[_sessionFile];
136
+ this[_lifecycleLogger].trace(`Serialized the session state at: ${this[_sessionFile]}`);
132
137
 
133
- if (opts.workerId !== null) {
138
+ if (opts.workerId != null) {
134
139
  await this[symbols.installWorker](opts);
135
140
  }
136
141
  }
@@ -140,10 +145,12 @@ class DetoxPrimaryContext extends DetoxContext {
140
145
  * @param {Partial<DetoxInternals.DetoxInstallWorkerOptions>} [opts]
141
146
  */
142
147
  async [symbols.installWorker](opts = {}) {
143
- const workerId = this[$sessionState].workerId = opts.workerId = opts.workerId || 'worker';
148
+ const workerId = opts.workerId || 'worker';
149
+
150
+ this[$sessionState].workerId = workerId;
144
151
  this[_ipcServer].onRegisterWorker({ workerId });
145
152
 
146
- await super[symbols.installWorker](opts);
153
+ await super[symbols.installWorker]({ ...opts, workerId });
147
154
  }
148
155
 
149
156
  /** @override */
@@ -168,14 +175,17 @@ class DetoxPrimaryContext extends DetoxContext {
168
175
  this[_ipcServer] = null;
169
176
  }
170
177
 
171
- await fs.remove(this[$sessionState].detoxConfigSnapshotPath);
178
+ if (this[_sessionFile]) {
179
+ await fs.remove(this[_sessionFile]);
180
+ }
172
181
 
173
182
  if (this[_dirty]) {
174
183
  try {
175
184
  this[_lifecycleLogger].trace.end();
176
- await this[_finalizeLogs]();
185
+ await this[symbols.logger].close();
186
+ await this[$logFinalizer].finalize();
177
187
  } catch (err) {
178
- this[_lifecycleLogger].error({ err }, 'Encountered an error while merging the process logs:');
188
+ this[_logFinalError](err);
179
189
  }
180
190
  }
181
191
  }
@@ -199,14 +209,23 @@ class DetoxPrimaryContext extends DetoxContext {
199
209
  this[_ipcServer].dispose();
200
210
  }
201
211
 
212
+ if (this[_sessionFile]) {
213
+ fs.removeSync(this[_sessionFile]);
214
+ }
215
+
202
216
  try {
203
217
  this[_lifecycleLogger].trace.end({ abortSignal: signal });
204
- this[_finalizeLogsSync]();
218
+ this[symbols.logger].close().catch(this[_logFinalError]);
219
+ this[$logFinalizer].finalizeSync();
205
220
  } catch (err) {
206
- this[symbols.logger].error({ err }, 'Encountered an error while merging the process logs:');
221
+ this[_logFinalError](err);
207
222
  }
208
223
  };
209
224
 
225
+ [_logFinalError] = (err) => {
226
+ this[_lifecycleLogger].error(err, 'Encountered an error while merging the process logs:');
227
+ };
228
+
210
229
  //#endregion
211
230
 
212
231
  //#region Protected members
@@ -217,77 +236,13 @@ class DetoxPrimaryContext extends DetoxContext {
217
236
  */
218
237
  [$restoreSessionState]() {
219
238
  return new SessionState({
220
- detoxConfigSnapshotPath: temporary.for.json(),
239
+ id: uuid.UUID(),
221
240
  detoxIPCServer: `primary-${process.pid}`,
222
241
  });
223
242
  }
224
243
  //#endregion
225
244
 
226
245
  //#region Private members
227
- async[_finalizeLogs]() {
228
- const sessionId = this[$sessionState].id;
229
- const logs = await globAsync(temporary.for.jsonl(`${sessionId}.*`));
230
- if (logs.length === 0) {
231
- return;
232
- }
233
-
234
- if (this[_areLogsEnabled]()) {
235
- const streamUtils = require('../logger/utils/streamUtils');
236
- const { rootDir } = this[symbols.config].artifacts;
237
-
238
- await fs.mkdirp(rootDir);
239
- const [out1Stream, out2Stream] = ['detox.log', 'detox.trace.json']
240
- .map((filename) => fs.createWriteStream(path.join(rootDir, filename)));
241
-
242
- const mergedStream = streamUtils.uniteSessionLogs(sessionId);
243
-
244
- await Promise.all([
245
- pipe(mergedStream, streamUtils.debugStream(this[symbols.logger].config.options), out1Stream),
246
- pipe(mergedStream, streamUtils.chromeTraceStream(), streamUtils.writeJSON(), out2Stream),
247
- ]);
248
- }
249
-
250
- await Promise.all(logs.map(filepath => fs.remove(filepath)));
251
- }
252
-
253
- async[_finalizeLogsSync]() {
254
- const logsEnabled = this[_areLogsEnabled]();
255
-
256
- const { rootDir } = this[symbols.config].artifacts;
257
-
258
- if (logsEnabled) {
259
- fs.mkdirpSync(rootDir);
260
- }
261
-
262
- const sessionId = this[$sessionState].id;
263
- const logs = globSync(temporary.for.jsonl(`${sessionId}.*`));
264
-
265
- for (const log of logs) {
266
- if (logsEnabled) {
267
- fs.moveSync(log, path.join(rootDir, path.basename(log)));
268
- } else {
269
- fs.removeSync(log);
270
- }
271
- }
272
- }
273
-
274
- [_areLogsEnabled]() {
275
- const { rootDir, plugins } = this[symbols.config].artifacts || {};
276
- if (!rootDir || !plugins) {
277
- return false;
278
- }
279
-
280
- if (!plugins.log.enabled) {
281
- return false;
282
- }
283
-
284
- if (!plugins.log.keepOnlyFailedTestsArtifacts) {
285
- return true;
286
- }
287
-
288
- return this[$sessionState].testResults.some(r => !r.success);
289
- }
290
-
291
246
  async[_resetLockFile]() {
292
247
  const DeviceRegistry = require('../devices/DeviceRegistry');
293
248
 
@@ -1,4 +1,4 @@
1
- const fs = require('fs');
1
+ const fs = require('fs-extra');
2
2
 
3
3
  const { DetoxInternalError } = require('../errors');
4
4
  const SessionState = require('../ipc/SessionState');
@@ -6,9 +6,12 @@ const symbols = require('../symbols');
6
6
 
7
7
  const DetoxContext = require('./DetoxContext');
8
8
 
9
+ // Protected symbols
9
10
  const { $restoreSessionState, $sessionState, $worker } = DetoxContext.protected;
11
+
12
+ //#region Private symbols
10
13
  const _ipcClient = Symbol('ipcClient');
11
- const _shortLifecycle = Symbol('shortLifecycle');
14
+ //#endregion
12
15
 
13
16
  class DetoxSecondaryContext extends DetoxContext {
14
17
  constructor() {
@@ -19,13 +22,6 @@ class DetoxSecondaryContext extends DetoxContext {
19
22
  * @type {import('../ipc/IPCClient')}
20
23
  */
21
24
  this[_ipcClient] = null;
22
- /**
23
- * @private
24
- * @type {undefined | boolean}
25
- *
26
- * TODO: explain what is short lifecycle and why we need it
27
- */
28
- this[_shortLifecycle] = false;
29
25
  }
30
26
 
31
27
  //#region Internal members
@@ -47,7 +43,7 @@ class DetoxSecondaryContext extends DetoxContext {
47
43
 
48
44
  this[_ipcClient] = new IPCClient({
49
45
  id: `secondary-${process.pid}`,
50
- state: this[$sessionState],
46
+ sessionState: this[$sessionState],
51
47
  logger: this[symbols.logger],
52
48
  });
53
49
 
@@ -74,9 +70,9 @@ class DetoxSecondaryContext extends DetoxContext {
74
70
 
75
71
  /** @override */
76
72
  async [symbols.installWorker](opts = {}) {
77
- const workerId = opts.workerId = opts.workerId || 'worker';
73
+ const workerId = opts.workerId || 'worker';
78
74
  await this[_ipcClient].registerWorker(workerId);
79
- await super[symbols.installWorker](opts);
75
+ await super[symbols.installWorker]({ ...opts, workerId });
80
76
  }
81
77
  //#endregion
82
78