testit-adapter-jest 3.7.9 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const testit_js_commons_1 = require("testit-js-commons");
4
+ const globalUnhandledRejectionLogger = (reason) => {
5
+ const normalized = reason?.body ?? reason?.error ?? reason;
6
+ console.error("[jest-globalSetup] unhandledRejection:", normalized);
7
+ };
4
8
  exports.default = async (globalConfig, projectConfig) => {
5
- const config = new testit_js_commons_1.ConfigComposer().compose(projectConfig.testEnvironmentOptions);
6
- const strategy = testit_js_commons_1.StrategyFactory.create(config);
7
- await strategy.setup();
8
- const testRunId = await strategy.testRunId;
9
- projectConfig.testEnvironmentOptions["testRunId"] = testRunId;
10
- projectConfig.testEnvironmentOptions["adapterMode"] = 1;
9
+ process.on("unhandledRejection", globalUnhandledRejectionLogger);
10
+ try {
11
+ const config = new testit_js_commons_1.ConfigComposer().compose(projectConfig.testEnvironmentOptions);
12
+ const strategy = testit_js_commons_1.StrategyFactory.create(config);
13
+ // Do not run setup in globalSetup: Jest workers run in separate processes and would then
14
+ // send results from non-master contexts. Let each worker environment run setup locally.
15
+ const testRunId = await strategy.testRunId;
16
+ projectConfig.testEnvironmentOptions["testRunId"] = testRunId;
17
+ projectConfig.testEnvironmentOptions["adapterMode"] = 1;
18
+ }
19
+ catch (err) {
20
+ console.error("Failed globalSetup for testit-adapter-jest:", err?.body ?? err?.error ?? err);
21
+ }
11
22
  };
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = async (globalConfig, projectConfig) => {
4
4
  try {
5
- await globalThis.strategy.teardown();
5
+ if (globalThis.strategy) {
6
+ await globalThis.strategy.teardown();
7
+ }
6
8
  }
7
9
  catch (err) {
8
10
  console.error('Failed to complete test run');
@@ -15,12 +15,16 @@ export default class TestItEnvironment extends NodeEnvironment {
15
15
  private attachmentsQueue;
16
16
  private readonly strategy;
17
17
  private readonly additions;
18
+ private readonly usesGlobalStrategy;
19
+ private readonly unhandledRejectionHandler;
20
+ private finalized;
18
21
  constructor(jestConfig: JestEnvironmentConfig, jestContext: EnvironmentContext);
19
22
  setup(): Promise<void>;
20
23
  teardown(): Promise<void>;
21
24
  getVmContext(): import("vm").Context | null;
22
25
  exportConditions(): string[];
23
26
  handleTestEvent(event: Event): Promise<void>;
27
+ private formatError;
24
28
  startHookCapture(hook: Extract<Event, {
25
29
  name: "hook_start";
26
30
  }>["hook"]): void;
@@ -34,13 +34,55 @@ class TestItEnvironment extends jest_environment_node_1.default {
34
34
  this.autotestResults = [];
35
35
  this.autotests = [];
36
36
  this.attachmentsQueue = [];
37
+ this.finalized = false;
37
38
  const config = new testit_js_commons_1.ConfigComposer().compose(jestConfig.projectConfig.testEnvironmentOptions);
38
39
  this.additions = new testit_js_commons_1.Additions(config);
39
- this.strategy = testit_js_commons_1.StrategyFactory.create(config);
40
+ this.usesGlobalStrategy = Boolean(globalThis.strategy);
41
+ this.strategy = globalThis.strategy ?? testit_js_commons_1.StrategyFactory.create(config);
42
+ this.unhandledRejectionHandler = (reason) => {
43
+ console.error("Unhandled promise rejection in Jest environment:", this.formatError(reason));
44
+ };
40
45
  this.testPath = (0, utils_1.excludePath)(jestContext.testPath, jestConfig.globalConfig.rootDir);
41
46
  }
42
47
  async setup() {
48
+ // Register as early as possible for this worker process.
49
+ process.on("unhandledRejection", this.unhandledRejectionHandler);
43
50
  await super.setup();
51
+ const testRunId = await this.strategy.testRunId;
52
+ const syncRunner = this.strategy.syncStorageRunner;
53
+ console.log("[jest-env] setup start", {
54
+ pid: process.pid,
55
+ testRunId,
56
+ usesGlobalStrategy: this.usesGlobalStrategy,
57
+ syncRunnerActive: Boolean(syncRunner?.isActive?.()),
58
+ syncRunnerMaster: Boolean(syncRunner?.isMasterWorker?.()),
59
+ });
60
+ // Jest workers run in separate processes and do not share globalThis.strategy from globalSetup.
61
+ // For those workers, run setup locally to register in sync storage (master will publish in-progress).
62
+ if (!this.usesGlobalStrategy) {
63
+ try {
64
+ await this.strategy.setup();
65
+ const localSyncRunner = this.strategy.syncStorageRunner;
66
+ console.log("[jest-env] local setup done", {
67
+ pid: process.pid,
68
+ testRunId,
69
+ syncRunnerActive: Boolean(localSyncRunner?.isActive?.()),
70
+ syncRunnerMaster: Boolean(localSyncRunner?.isMasterWorker?.()),
71
+ });
72
+ }
73
+ catch (err) {
74
+ console.error("Failed local strategy.setup() in Jest environment:", this.formatError(err));
75
+ }
76
+ }
77
+ else {
78
+ const sharedSyncRunner = this.strategy.syncStorageRunner;
79
+ console.log("[jest-env] shared strategy mode", {
80
+ pid: process.pid,
81
+ testRunId,
82
+ syncRunnerActive: Boolean(sharedSyncRunner?.isActive?.()),
83
+ syncRunnerMaster: Boolean(sharedSyncRunner?.isMasterWorker?.()),
84
+ });
85
+ }
44
86
  this.global.testit = {
45
87
  externalId: this.setExternalId.bind(this),
46
88
  displayName: this.setDisplayName.bind(this),
@@ -60,6 +102,7 @@ class TestItEnvironment extends jest_environment_node_1.default {
60
102
  };
61
103
  }
62
104
  async teardown() {
105
+ process.off("unhandledRejection", this.unhandledRejectionHandler);
63
106
  await super.teardown();
64
107
  }
65
108
  getVmContext() {
@@ -69,38 +112,63 @@ class TestItEnvironment extends jest_environment_node_1.default {
69
112
  return super.exportConditions();
70
113
  }
71
114
  async handleTestEvent(event) {
72
- switch (event.name) {
73
- case "hook_start": {
74
- this.startHookCapture(event.hook);
75
- break;
76
- }
77
- case "hook_success":
78
- case "hook_failure": {
79
- this.finishHookCapture(event.hook);
80
- break;
81
- }
82
- case "test_fn_start": {
83
- this.startTestCapture(event.test);
84
- break;
85
- }
86
- case "test_fn_success":
87
- case "test_fn_failure": {
88
- this.finishTestCapture(event.test);
89
- break;
90
- }
91
- case "test_done": {
92
- await this.saveResult(event.test);
93
- break;
94
- }
95
- case "test_skip": {
96
- this.resetTest();
97
- break;
98
- }
99
- case "run_finish": {
100
- await this.loadResults();
101
- break;
115
+ try {
116
+ switch (event.name) {
117
+ case "hook_start": {
118
+ this.startHookCapture(event.hook);
119
+ break;
120
+ }
121
+ case "hook_success":
122
+ case "hook_failure": {
123
+ this.finishHookCapture(event.hook);
124
+ break;
125
+ }
126
+ case "test_fn_start": {
127
+ this.startTestCapture(event.test);
128
+ break;
129
+ }
130
+ case "test_fn_success":
131
+ case "test_fn_failure": {
132
+ this.finishTestCapture(event.test);
133
+ break;
134
+ }
135
+ case "test_done": {
136
+ await this.saveResult(event.test);
137
+ break;
138
+ }
139
+ case "test_skip": {
140
+ this.resetTest();
141
+ break;
142
+ }
143
+ case "run_finish": {
144
+ try {
145
+ await this.loadResults();
146
+ }
147
+ catch (err) {
148
+ console.error("Failed to load results in Jest run_finish:", this.formatError(err));
149
+ }
150
+ finally {
151
+ // In worker mode we run local setup, so finalization must happen here even if loadResults fails.
152
+ if (!this.finalized) {
153
+ this.finalized = true;
154
+ try {
155
+ await this.strategy.teardown();
156
+ }
157
+ catch (err) {
158
+ console.error("Failed strategy.teardown() in Jest run_finish:", this.formatError(err));
159
+ }
160
+ }
161
+ }
162
+ break;
163
+ }
102
164
  }
103
165
  }
166
+ catch (err) {
167
+ console.error("Unhandled async error in Jest environment event handler:", this.formatError(err));
168
+ }
169
+ }
170
+ formatError(err) {
171
+ return err?.body ?? err?.error ?? err;
104
172
  }
105
173
  startHookCapture(hook) {
106
174
  log("Starting hook capture %s", hook.type);
@@ -151,7 +219,7 @@ class TestItEnvironment extends jest_environment_node_1.default {
151
219
  }
152
220
  async saveResult(test) {
153
221
  log("Saving result for %s", test.name);
154
- await Promise.all(this.attachmentsQueue);
222
+ await Promise.allSettled(this.attachmentsQueue);
155
223
  const errorMessage = test.errors.length > 0 ? test.errors.map((err) => err[0]?.message).join("\n") : undefined;
156
224
  const errorTraces = test.errors.length > 0 ? test.errors.map((err) => err[0]?.stack).join("\n") : undefined;
157
225
  const result = {
@@ -170,7 +238,7 @@ class TestItEnvironment extends jest_environment_node_1.default {
170
238
  }
171
239
  async loadResults() {
172
240
  log("Waiting for attachments to be uploaded");
173
- await Promise.all(this.attachmentsQueue);
241
+ await Promise.allSettled(this.attachmentsQueue);
174
242
  const results = [];
175
243
  for (let i = 0; i < this.autotests.length; i++) {
176
244
  const autotest = this.autotests[i];
@@ -193,7 +261,12 @@ class TestItEnvironment extends jest_environment_node_1.default {
193
261
  teardown: teardownSteps,
194
262
  externalKey: autotest.externalKey,
195
263
  };
196
- await this.strategy.loadAutotest(autotestPost, result.outcome);
264
+ try {
265
+ await this.strategy.loadAutotest(autotestPost, result.outcome);
266
+ }
267
+ catch (err) {
268
+ console.error("Failed to load autotest in Jest environment:", this.formatError(err));
269
+ }
197
270
  results.push({
198
271
  autoTestExternalId: autotestPost.externalId,
199
272
  outcome: result.outcome,
@@ -210,7 +283,12 @@ class TestItEnvironment extends jest_environment_node_1.default {
210
283
  });
211
284
  }
212
285
  log("Loading results");
213
- await this.strategy.loadTestRun(results);
286
+ try {
287
+ await this.strategy.loadTestRun(results);
288
+ }
289
+ catch (err) {
290
+ console.error("Failed to load test run in Jest environment:", this.formatError(err));
291
+ }
214
292
  }
215
293
  resetTest() {
216
294
  this.autotestData = emptyAutotestData();
@@ -252,9 +330,15 @@ class TestItEnvironment extends jest_environment_node_1.default {
252
330
  const autotest = this.autotestData;
253
331
  const step = this.currentStepData;
254
332
  const currentType = this.currentType;
255
- // @ts-ignore
256
- const promise = this.additions.addAttachments(attachments, name).then((ids) => {
333
+ // @ts-ignore — overload: paths[] | text content + fileName
334
+ const promise = this.additions.addAttachments(attachments, name)
335
+ .then((ids) => {
257
336
  currentType === "test" ? autotest.attachments.push(...ids) : step.attachments?.push(...ids);
337
+ return ids;
338
+ })
339
+ .catch((err) => {
340
+ console.log("Error uploading attachment (Jest). \n", err?.body ?? err?.error ?? err);
341
+ return [];
258
342
  });
259
343
  this.attachmentsQueue.push(promise);
260
344
  return promise;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testit-adapter-jest",
3
- "version": "3.7.9",
3
+ "version": "4.0.0",
4
4
  "description": "Jest adapter for Test IT",
5
5
  "main": "dist/testitEnvironment.js",
6
6
  "scripts": {
@@ -16,7 +16,7 @@
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
18
  "debug": "^4.3.4",
19
- "testit-js-commons": "3.7.9"
19
+ "testit-js-commons": "4.0.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/debug": "^4.1.7",