@cucumber/cucumber 10.8.0 → 11.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.
- package/lib/api/formatters.js +5 -4
- package/lib/api/formatters.js.map +1 -1
- package/lib/api/run_cucumber.js +8 -10
- package/lib/api/run_cucumber.js.map +1 -1
- package/lib/{runtime → assemble}/assemble_test_cases.d.ts +4 -6
- package/lib/{runtime → assemble}/assemble_test_cases.js +9 -8
- package/lib/assemble/assemble_test_cases.js.map +1 -0
- package/lib/assemble/index.d.ts +2 -0
- package/lib/assemble/index.js +19 -0
- package/lib/assemble/index.js.map +1 -0
- package/lib/assemble/types.d.ts +10 -0
- package/lib/{runtime/parallel/command_types.js → assemble/types.js} +1 -1
- package/lib/assemble/types.js.map +1 -0
- package/lib/cli/helpers.d.ts +0 -23
- package/lib/cli/helpers.js +1 -33
- package/lib/cli/helpers.js.map +1 -1
- package/lib/formatter/builtin/html.d.ts +5 -1
- package/lib/formatter/builtin/html.js +55 -4
- package/lib/formatter/builtin/html.js.map +1 -1
- package/lib/formatter/create_stream.d.ts +4 -1
- package/lib/formatter/create_stream.js +6 -2
- package/lib/formatter/create_stream.js.map +1 -1
- package/lib/formatter/index.d.ts +3 -0
- package/lib/formatter/index.js.map +1 -1
- package/lib/index.d.ts +0 -16
- package/lib/index.js +1 -16
- package/lib/index.js.map +1 -1
- package/lib/plugin/plugin_manager.d.ts +1 -1
- package/lib/plugin/plugin_manager.js +6 -2
- package/lib/plugin/plugin_manager.js.map +1 -1
- package/lib/plugin/types.d.ts +3 -0
- package/lib/plugin/types.js.map +1 -1
- package/lib/runtime/attachment_manager/index.d.ts +2 -0
- package/lib/runtime/attachment_manager/index.js +3 -0
- package/lib/runtime/attachment_manager/index.js.map +1 -1
- package/lib/runtime/coordinator.d.ts +16 -0
- package/lib/runtime/coordinator.js +42 -0
- package/lib/runtime/coordinator.js.map +1 -0
- package/lib/runtime/helpers.d.ts +3 -3
- package/lib/runtime/helpers.js.map +1 -1
- package/lib/runtime/index.d.ts +2 -41
- package/lib/runtime/index.js +14 -81
- package/lib/runtime/index.js.map +1 -1
- package/lib/runtime/make_runtime.d.ts +17 -0
- package/lib/runtime/make_runtime.js +14 -0
- package/lib/runtime/make_runtime.js.map +1 -0
- package/lib/runtime/parallel/adapter.d.ts +48 -0
- package/lib/runtime/parallel/adapter.js +152 -0
- package/lib/runtime/parallel/adapter.js.map +1 -0
- package/lib/runtime/parallel/run_worker.js +2 -5
- package/lib/runtime/parallel/run_worker.js.map +1 -1
- package/lib/runtime/parallel/types.d.ts +32 -0
- package/lib/runtime/parallel/types.js +3 -0
- package/lib/runtime/parallel/types.js.map +1 -0
- package/lib/runtime/parallel/worker.d.ts +8 -9
- package/lib/runtime/parallel/worker.js +28 -44
- package/lib/runtime/parallel/worker.js.map +1 -1
- package/lib/runtime/serial/adapter.d.ts +13 -0
- package/lib/runtime/serial/adapter.js +24 -0
- package/lib/runtime/serial/adapter.js.map +1 -0
- package/lib/runtime/stopwatch.d.ts +2 -2
- package/lib/runtime/stopwatch.js +3 -4
- package/lib/runtime/stopwatch.js.map +1 -1
- package/lib/runtime/test_case_runner.d.ts +2 -5
- package/lib/runtime/test_case_runner.js +7 -7
- package/lib/runtime/test_case_runner.js.map +1 -1
- package/lib/runtime/types.d.ts +17 -0
- package/lib/runtime/types.js +3 -0
- package/lib/runtime/types.js.map +1 -0
- package/lib/runtime/worker.d.ts +18 -0
- package/lib/runtime/worker.js +57 -0
- package/lib/runtime/worker.js.map +1 -0
- package/lib/support_code_library_builder/index.d.ts +2 -3
- package/lib/support_code_library_builder/index.js.map +1 -1
- package/lib/support_code_library_builder/types.d.ts +5 -0
- package/lib/support_code_library_builder/types.js.map +1 -1
- package/lib/support_code_library_builder/world.d.ts +5 -2
- package/lib/support_code_library_builder/world.js +3 -1
- package/lib/support_code_library_builder/world.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/lib/wrapper.mjs +0 -3
- package/package.json +6 -6
- package/lib/api/runtime.d.ts +0 -18
- package/lib/api/runtime.js +0 -33
- package/lib/api/runtime.js.map +0 -1
- package/lib/runtime/assemble_test_cases.js.map +0 -1
- package/lib/runtime/parallel/command_types.d.ts +0 -31
- package/lib/runtime/parallel/command_types.js.map +0 -1
- package/lib/runtime/parallel/coordinator.d.ts +0 -66
- package/lib/runtime/parallel/coordinator.js +0 -209
- package/lib/runtime/parallel/coordinator.js.map +0 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ChildProcessAdapter = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const runWorkerPath = node_path_1.default.resolve(__dirname, 'run_worker.js');
|
|
10
|
+
class ChildProcessAdapter {
|
|
11
|
+
environment;
|
|
12
|
+
logger;
|
|
13
|
+
eventBroadcaster;
|
|
14
|
+
options;
|
|
15
|
+
supportCodeLibrary;
|
|
16
|
+
idleInterventions = 0;
|
|
17
|
+
failing = false;
|
|
18
|
+
onFinish;
|
|
19
|
+
todo = [];
|
|
20
|
+
inProgress = {};
|
|
21
|
+
workers = {};
|
|
22
|
+
constructor(environment, logger, eventBroadcaster, options, supportCodeLibrary) {
|
|
23
|
+
this.environment = environment;
|
|
24
|
+
this.logger = logger;
|
|
25
|
+
this.eventBroadcaster = eventBroadcaster;
|
|
26
|
+
this.options = options;
|
|
27
|
+
this.supportCodeLibrary = supportCodeLibrary;
|
|
28
|
+
}
|
|
29
|
+
parseWorkerMessage(worker, message) {
|
|
30
|
+
switch (message.type) {
|
|
31
|
+
case 'READY':
|
|
32
|
+
worker.state = 0 /* WorkerState.idle */;
|
|
33
|
+
this.awakenWorkers(worker);
|
|
34
|
+
break;
|
|
35
|
+
case 'ENVELOPE':
|
|
36
|
+
this.eventBroadcaster.emit('envelope', message.envelope);
|
|
37
|
+
break;
|
|
38
|
+
case 'FINISHED':
|
|
39
|
+
if (!message.success) {
|
|
40
|
+
this.failing = true;
|
|
41
|
+
}
|
|
42
|
+
delete this.inProgress[worker.id];
|
|
43
|
+
worker.state = 0 /* WorkerState.idle */;
|
|
44
|
+
this.awakenWorkers(worker);
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
throw new Error(`Unexpected message from worker: ${JSON.stringify(message)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
awakenWorkers(triggeringWorker) {
|
|
51
|
+
Object.values(this.workers).forEach((worker) => {
|
|
52
|
+
if (worker.state === 0 /* WorkerState.idle */) {
|
|
53
|
+
this.giveWork(worker);
|
|
54
|
+
}
|
|
55
|
+
return worker.state !== 0 /* WorkerState.idle */;
|
|
56
|
+
});
|
|
57
|
+
if (Object.keys(this.inProgress).length == 0 && this.todo.length > 0) {
|
|
58
|
+
this.giveWork(triggeringWorker, true);
|
|
59
|
+
this.idleInterventions++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
startWorker(id, total) {
|
|
63
|
+
const workerProcess = (0, node_child_process_1.fork)(runWorkerPath, [], {
|
|
64
|
+
cwd: this.environment.cwd,
|
|
65
|
+
env: {
|
|
66
|
+
...this.environment.env,
|
|
67
|
+
CUCUMBER_PARALLEL: 'true',
|
|
68
|
+
CUCUMBER_TOTAL_WORKERS: total.toString(),
|
|
69
|
+
CUCUMBER_WORKER_ID: id,
|
|
70
|
+
},
|
|
71
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
72
|
+
});
|
|
73
|
+
const worker = { state: 3 /* WorkerState.new */, process: workerProcess, id };
|
|
74
|
+
this.workers[id] = worker;
|
|
75
|
+
worker.process.on('message', (message) => {
|
|
76
|
+
this.parseWorkerMessage(worker, message);
|
|
77
|
+
});
|
|
78
|
+
worker.process.on('close', (exitCode) => {
|
|
79
|
+
worker.state = 1 /* WorkerState.closed */;
|
|
80
|
+
this.onWorkerProcessClose(exitCode);
|
|
81
|
+
});
|
|
82
|
+
worker.process.send({
|
|
83
|
+
type: 'INITIALIZE',
|
|
84
|
+
supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,
|
|
85
|
+
supportCodeIds: {
|
|
86
|
+
stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map((s) => s.id),
|
|
87
|
+
beforeTestCaseHookDefinitionIds: this.supportCodeLibrary.beforeTestCaseHookDefinitions.map((h) => h.id),
|
|
88
|
+
afterTestCaseHookDefinitionIds: this.supportCodeLibrary.afterTestCaseHookDefinitions.map((h) => h.id),
|
|
89
|
+
},
|
|
90
|
+
options: this.options,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
onWorkerProcessClose(exitCode) {
|
|
94
|
+
if (exitCode !== 0) {
|
|
95
|
+
this.failing = true;
|
|
96
|
+
}
|
|
97
|
+
if (Object.values(this.workers).every((x) => x.state === 1 /* WorkerState.closed */)) {
|
|
98
|
+
this.onFinish(!this.failing);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async run(assembledTestCases) {
|
|
102
|
+
this.todo = Array.from(assembledTestCases);
|
|
103
|
+
return await new Promise((resolve) => {
|
|
104
|
+
for (let i = 0; i < this.options.parallel; i++) {
|
|
105
|
+
this.startWorker(i.toString(), this.options.parallel);
|
|
106
|
+
}
|
|
107
|
+
this.onFinish = (status) => {
|
|
108
|
+
if (this.idleInterventions > 0) {
|
|
109
|
+
this.logger.warn(`WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`);
|
|
110
|
+
}
|
|
111
|
+
resolve(status);
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
nextWorkPlacement() {
|
|
116
|
+
for (let index = 0; index < this.todo.length; index++) {
|
|
117
|
+
const placement = this.placementAt(index);
|
|
118
|
+
if (this.supportCodeLibrary.parallelCanAssign(placement.item.pickle, Object.values(this.inProgress).map(({ pickle }) => pickle))) {
|
|
119
|
+
return placement;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
placementAt(index) {
|
|
125
|
+
return {
|
|
126
|
+
index,
|
|
127
|
+
item: this.todo[index],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
giveWork(worker, force = false) {
|
|
131
|
+
if (this.todo.length < 1) {
|
|
132
|
+
worker.state = 2 /* WorkerState.running */;
|
|
133
|
+
worker.process.send({ type: 'FINALIZE' });
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const workPlacement = force ? this.placementAt(0) : this.nextWorkPlacement();
|
|
137
|
+
if (workPlacement === null) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const { index: nextIndex, item } = workPlacement;
|
|
141
|
+
this.todo.splice(nextIndex, 1);
|
|
142
|
+
this.inProgress[worker.id] = item;
|
|
143
|
+
worker.state = 2 /* WorkerState.running */;
|
|
144
|
+
worker.process.send({
|
|
145
|
+
type: 'RUN',
|
|
146
|
+
assembledTestCase: item,
|
|
147
|
+
failing: this.failing,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.ChildProcessAdapter = ChildProcessAdapter;
|
|
152
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/runtime/parallel/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChildProcess, fork } from 'node:child_process'\nimport path from 'node:path'\nimport { EventEmitter } from 'node:events'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\nimport { AssembledTestCase } from '../../assemble'\nimport { ILogger } from '../../logger'\nimport { RuntimeAdapter } from '../types'\nimport { IRunEnvironment, IRunOptionsRuntime } from '../../api'\nimport {\n FinalizeCommand,\n InitializeCommand,\n RunCommand,\n WorkerToCoordinatorEvent,\n} from './types'\n\nconst runWorkerPath = path.resolve(__dirname, 'run_worker.js')\n\nconst enum WorkerState {\n 'idle',\n 'closed',\n 'running',\n 'new',\n}\n\ninterface ManagedWorker {\n state: WorkerState\n process: ChildProcess\n id: string\n}\n\ninterface WorkPlacement {\n index: number\n item: AssembledTestCase\n}\n\nexport class ChildProcessAdapter implements RuntimeAdapter {\n private idleInterventions: number = 0\n private failing: boolean = false\n private onFinish: (success: boolean) => void\n private todo: Array<AssembledTestCase> = []\n private readonly inProgress: Record<string, AssembledTestCase> = {}\n private readonly workers: Record<string, ManagedWorker> = {}\n\n constructor(\n private readonly environment: IRunEnvironment,\n private readonly logger: ILogger,\n private readonly eventBroadcaster: EventEmitter,\n private readonly options: IRunOptionsRuntime,\n private readonly supportCodeLibrary: SupportCodeLibrary\n ) {}\n\n parseWorkerMessage(\n worker: ManagedWorker,\n message: WorkerToCoordinatorEvent\n ): void {\n switch (message.type) {\n case 'READY':\n worker.state = WorkerState.idle\n this.awakenWorkers(worker)\n break\n case 'ENVELOPE':\n this.eventBroadcaster.emit('envelope', message.envelope)\n break\n case 'FINISHED':\n if (!message.success) {\n this.failing = true\n }\n delete this.inProgress[worker.id]\n worker.state = WorkerState.idle\n this.awakenWorkers(worker)\n break\n default:\n throw new Error(\n `Unexpected message from worker: ${JSON.stringify(message)}`\n )\n }\n }\n\n awakenWorkers(triggeringWorker: ManagedWorker): void {\n Object.values(this.workers).forEach((worker) => {\n if (worker.state === WorkerState.idle) {\n this.giveWork(worker)\n }\n return worker.state !== WorkerState.idle\n })\n\n if (Object.keys(this.inProgress).length == 0 && this.todo.length > 0) {\n this.giveWork(triggeringWorker, true)\n this.idleInterventions++\n }\n }\n\n startWorker(id: string, total: number): void {\n const workerProcess = fork(runWorkerPath, [], {\n cwd: this.environment.cwd,\n env: {\n ...this.environment.env,\n CUCUMBER_PARALLEL: 'true',\n CUCUMBER_TOTAL_WORKERS: total.toString(),\n CUCUMBER_WORKER_ID: id,\n },\n stdio: ['inherit', 'inherit', 'inherit', 'ipc'],\n })\n const worker = { state: WorkerState.new, process: workerProcess, id }\n this.workers[id] = worker\n worker.process.on('message', (message: WorkerToCoordinatorEvent) => {\n this.parseWorkerMessage(worker, message)\n })\n worker.process.on('close', (exitCode) => {\n worker.state = WorkerState.closed\n this.onWorkerProcessClose(exitCode)\n })\n worker.process.send({\n type: 'INITIALIZE',\n supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,\n supportCodeIds: {\n stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(\n (s) => s.id\n ),\n beforeTestCaseHookDefinitionIds:\n this.supportCodeLibrary.beforeTestCaseHookDefinitions.map(\n (h) => h.id\n ),\n afterTestCaseHookDefinitionIds:\n this.supportCodeLibrary.afterTestCaseHookDefinitions.map((h) => h.id),\n },\n options: this.options,\n } satisfies InitializeCommand)\n }\n\n onWorkerProcessClose(exitCode: number): void {\n if (exitCode !== 0) {\n this.failing = true\n }\n\n if (\n Object.values(this.workers).every((x) => x.state === WorkerState.closed)\n ) {\n this.onFinish(!this.failing)\n }\n }\n\n async run(\n assembledTestCases: ReadonlyArray<AssembledTestCase>\n ): Promise<boolean> {\n this.todo = Array.from(assembledTestCases)\n return await new Promise<boolean>((resolve) => {\n for (let i = 0; i < this.options.parallel; i++) {\n this.startWorker(i.toString(), this.options.parallel)\n }\n this.onFinish = (status) => {\n if (this.idleInterventions > 0) {\n this.logger.warn(\n `WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`\n )\n }\n\n resolve(status)\n }\n })\n }\n\n nextWorkPlacement(): WorkPlacement {\n for (let index = 0; index < this.todo.length; index++) {\n const placement = this.placementAt(index)\n if (\n this.supportCodeLibrary.parallelCanAssign(\n placement.item.pickle,\n Object.values(this.inProgress).map(({ pickle }) => pickle)\n )\n ) {\n return placement\n }\n }\n\n return null\n }\n\n placementAt(index: number): WorkPlacement {\n return {\n index,\n item: this.todo[index],\n }\n }\n\n giveWork(worker: ManagedWorker, force: boolean = false): void {\n if (this.todo.length < 1) {\n worker.state = WorkerState.running\n worker.process.send({ type: 'FINALIZE' } satisfies FinalizeCommand)\n return\n }\n\n const workPlacement = force ? this.placementAt(0) : this.nextWorkPlacement()\n\n if (workPlacement === null) {\n return\n }\n\n const { index: nextIndex, item } = workPlacement\n\n this.todo.splice(nextIndex, 1)\n this.inProgress[worker.id] = item\n worker.state = WorkerState.running\n worker.process.send({\n type: 'RUN',\n assembledTestCase: item,\n failing: this.failing,\n } satisfies RunCommand)\n }\n}\n"]}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
const value_checker_1 = require("../../value_checker");
|
|
7
|
-
const worker_1 =
|
|
4
|
+
const worker_1 = require("./worker");
|
|
8
5
|
function run() {
|
|
9
6
|
const exit = (exitCode, error, message) => {
|
|
10
7
|
if ((0, value_checker_1.doesHaveValue)(error)) {
|
|
@@ -12,7 +9,7 @@ function run() {
|
|
|
12
9
|
}
|
|
13
10
|
process.exit(exitCode);
|
|
14
11
|
};
|
|
15
|
-
const worker = new worker_1.
|
|
12
|
+
const worker = new worker_1.ChildProcessWorker({
|
|
16
13
|
id: process.env.CUCUMBER_WORKER_ID,
|
|
17
14
|
sendMessage: (message) => process.send(message),
|
|
18
15
|
cwd: process.cwd(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run_worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/run_worker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run_worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/run_worker.ts"],"names":[],"mappings":";;AAAA,uDAAmD;AACnD,qCAA6C;AAE7C,SAAS,GAAG;IACV,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAE,KAAa,EAAE,OAAgB,EAAQ,EAAE;QACvE,IAAI,IAAA,6BAAa,EAAC,KAAK,CAAC,EAAE;YACxB,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA,CAAC,iCAAiC;SACtF;QACD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACxB,CAAC,CAAA;IACD,MAAM,MAAM,GAAG,IAAI,2BAAkB,CAAC;QACpC,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAClC,WAAW,EAAE,CAAC,OAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QACpD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI;KACL,CAAC,CAAA;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAM,EAAQ,EAAE;QACrC,MAAM;aACH,cAAc,CAAC,CAAC,CAAC;aACjB,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE,CACtB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,2CAA2C,CAAC,CAC5D,CAAA;IACL,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,GAAG,EAAE,CAAA","sourcesContent":["import { doesHaveValue } from '../../value_checker'\nimport { ChildProcessWorker } from './worker'\n\nfunction run(): void {\n const exit = (exitCode: number, error?: Error, message?: string): void => {\n if (doesHaveValue(error)) {\n console.error(new Error(message, { cause: error })) // eslint-disable-line no-console\n }\n process.exit(exitCode)\n }\n const worker = new ChildProcessWorker({\n id: process.env.CUCUMBER_WORKER_ID,\n sendMessage: (message: any) => process.send(message),\n cwd: process.cwd(),\n exit,\n })\n process.on('message', (m: any): void => {\n worker\n .receiveMessage(m)\n .catch((error: Error) =>\n exit(1, error, 'Unexpected error on worker.receiveMessage')\n )\n })\n}\n\nrun()\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Envelope } from '@cucumber/messages';
|
|
2
|
+
import { RuntimeOptions } from '../index';
|
|
3
|
+
import { ISupportCodeCoordinates } from '../../api';
|
|
4
|
+
import { AssembledTestCase } from '../../assemble';
|
|
5
|
+
import { CanonicalSupportCodeIds } from '../../support_code_library_builder/types';
|
|
6
|
+
export type CoordinatorToWorkerCommand = InitializeCommand | RunCommand | FinalizeCommand;
|
|
7
|
+
export interface InitializeCommand {
|
|
8
|
+
type: 'INITIALIZE';
|
|
9
|
+
supportCodeCoordinates: ISupportCodeCoordinates;
|
|
10
|
+
supportCodeIds: CanonicalSupportCodeIds;
|
|
11
|
+
options: RuntimeOptions;
|
|
12
|
+
}
|
|
13
|
+
export interface RunCommand {
|
|
14
|
+
type: 'RUN';
|
|
15
|
+
assembledTestCase: AssembledTestCase;
|
|
16
|
+
failing: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface FinalizeCommand {
|
|
19
|
+
type: 'FINALIZE';
|
|
20
|
+
}
|
|
21
|
+
export type WorkerToCoordinatorEvent = ReadyEvent | EnvelopeEvent | FinishedEvent;
|
|
22
|
+
export interface ReadyEvent {
|
|
23
|
+
type: 'READY';
|
|
24
|
+
}
|
|
25
|
+
export interface EnvelopeEvent {
|
|
26
|
+
type: 'ENVELOPE';
|
|
27
|
+
envelope: Envelope;
|
|
28
|
+
}
|
|
29
|
+
export interface FinishedEvent {
|
|
30
|
+
type: 'FINISHED';
|
|
31
|
+
success: boolean;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/runtime/parallel/types.ts"],"names":[],"mappings":"","sourcesContent":["import { Envelope } from '@cucumber/messages'\nimport { RuntimeOptions } from '../index'\nimport { ISupportCodeCoordinates } from '../../api'\nimport { AssembledTestCase } from '../../assemble'\nimport { CanonicalSupportCodeIds } from '../../support_code_library_builder/types'\n\n// Messages from Coordinator to Worker\n\nexport type CoordinatorToWorkerCommand =\n | InitializeCommand\n | RunCommand\n | FinalizeCommand\n\nexport interface InitializeCommand {\n type: 'INITIALIZE'\n supportCodeCoordinates: ISupportCodeCoordinates\n supportCodeIds: CanonicalSupportCodeIds\n options: RuntimeOptions\n}\n\nexport interface RunCommand {\n type: 'RUN'\n assembledTestCase: AssembledTestCase\n failing: boolean\n}\n\nexport interface FinalizeCommand {\n type: 'FINALIZE'\n}\n\n// Messages from Worker to Coordinator\n\nexport type WorkerToCoordinatorEvent =\n | ReadyEvent\n | EnvelopeEvent\n | FinishedEvent\n\nexport interface ReadyEvent {\n type: 'READY'\n}\n\nexport interface EnvelopeEvent {\n type: 'ENVELOPE'\n envelope: Envelope\n}\n\nexport interface FinishedEvent {\n type: 'FINISHED'\n success: boolean\n}\n"]}
|
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WorkerToCoordinatorEvent, CoordinatorToWorkerCommand, InitializeCommand, RunCommand } from './types';
|
|
2
2
|
type IExitFunction = (exitCode: number, error?: Error, message?: string) => void;
|
|
3
|
-
type IMessageSender = (command:
|
|
4
|
-
export
|
|
3
|
+
type IMessageSender = (command: WorkerToCoordinatorEvent) => void;
|
|
4
|
+
export declare class ChildProcessWorker {
|
|
5
5
|
private readonly cwd;
|
|
6
6
|
private readonly exit;
|
|
7
7
|
private readonly id;
|
|
8
8
|
private readonly eventBroadcaster;
|
|
9
|
-
private filterStacktraces;
|
|
10
9
|
private readonly newId;
|
|
11
10
|
private readonly sendMessage;
|
|
11
|
+
private options;
|
|
12
12
|
private supportCodeLibrary;
|
|
13
|
-
private
|
|
14
|
-
private runTestRunHooks;
|
|
13
|
+
private worker;
|
|
15
14
|
constructor({ cwd, exit, id, sendMessage, }: {
|
|
16
15
|
cwd: string;
|
|
17
16
|
exit: IExitFunction;
|
|
18
17
|
id: string;
|
|
19
18
|
sendMessage: IMessageSender;
|
|
20
19
|
});
|
|
21
|
-
initialize({ supportCodeCoordinates, supportCodeIds, options, }:
|
|
20
|
+
initialize({ supportCodeCoordinates, supportCodeIds, options, }: InitializeCommand): Promise<void>;
|
|
22
21
|
finalize(): Promise<void>;
|
|
23
|
-
receiveMessage(
|
|
24
|
-
runTestCase(
|
|
22
|
+
receiveMessage(command: CoordinatorToWorkerCommand): Promise<void>;
|
|
23
|
+
runTestCase(command: RunCommand): Promise<void>;
|
|
25
24
|
}
|
|
26
25
|
export {};
|
|
@@ -3,28 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ChildProcessWorker = void 0;
|
|
6
7
|
const node_events_1 = require("node:events");
|
|
7
8
|
const node_url_1 = require("node:url");
|
|
8
9
|
const node_module_1 = require("node:module");
|
|
9
10
|
const messages_1 = require("@cucumber/messages");
|
|
10
11
|
const support_code_library_builder_1 = __importDefault(require("../../support_code_library_builder"));
|
|
11
|
-
const value_checker_1 = require("../../value_checker");
|
|
12
|
-
const run_test_run_hooks_1 = require("../run_test_run_hooks");
|
|
13
|
-
const stopwatch_1 = require("../stopwatch");
|
|
14
|
-
const test_case_runner_1 = __importDefault(require("../test_case_runner"));
|
|
15
12
|
const try_require_1 = __importDefault(require("../../try_require"));
|
|
13
|
+
const worker_1 = require("../worker");
|
|
16
14
|
const { uuid } = messages_1.IdGenerator;
|
|
17
|
-
class
|
|
15
|
+
class ChildProcessWorker {
|
|
18
16
|
cwd;
|
|
19
17
|
exit;
|
|
20
18
|
id;
|
|
21
19
|
eventBroadcaster;
|
|
22
|
-
filterStacktraces;
|
|
23
20
|
newId;
|
|
24
21
|
sendMessage;
|
|
22
|
+
options;
|
|
25
23
|
supportCodeLibrary;
|
|
26
|
-
|
|
27
|
-
runTestRunHooks;
|
|
24
|
+
worker;
|
|
28
25
|
constructor({ cwd, exit, id, sendMessage, }) {
|
|
29
26
|
this.id = id;
|
|
30
27
|
this.newId = uuid();
|
|
@@ -32,9 +29,7 @@ class Worker {
|
|
|
32
29
|
this.exit = exit;
|
|
33
30
|
this.sendMessage = sendMessage;
|
|
34
31
|
this.eventBroadcaster = new node_events_1.EventEmitter();
|
|
35
|
-
this.eventBroadcaster.on('envelope', (envelope) => {
|
|
36
|
-
this.sendMessage({ jsonEnvelope: envelope });
|
|
37
|
-
});
|
|
32
|
+
this.eventBroadcaster.on('envelope', (envelope) => this.sendMessage({ type: 'ENVELOPE', envelope }));
|
|
38
33
|
}
|
|
39
34
|
async initialize({ supportCodeCoordinates, supportCodeIds, options, }) {
|
|
40
35
|
support_code_library_builder_1.default.reset(this.cwd, this.newId, supportCodeCoordinates);
|
|
@@ -47,46 +42,35 @@ class Worker {
|
|
|
47
42
|
await import((0, node_url_1.pathToFileURL)(path).toString());
|
|
48
43
|
}
|
|
49
44
|
this.supportCodeLibrary = support_code_library_builder_1.default.finalize(supportCodeIds);
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.sendMessage({ ready: true });
|
|
45
|
+
this.options = options;
|
|
46
|
+
this.worker = new worker_1.Worker(this.id, this.eventBroadcaster, this.newId, this.options, this.supportCodeLibrary);
|
|
47
|
+
await this.worker.runBeforeAllHooks();
|
|
48
|
+
this.sendMessage({ type: 'READY' });
|
|
55
49
|
}
|
|
56
50
|
async finalize() {
|
|
57
|
-
await this.
|
|
51
|
+
await this.worker.runAfterAllHooks();
|
|
58
52
|
this.exit(0);
|
|
59
53
|
}
|
|
60
|
-
async receiveMessage(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
async receiveMessage(command) {
|
|
55
|
+
switch (command.type) {
|
|
56
|
+
case 'INITIALIZE':
|
|
57
|
+
await this.initialize(command);
|
|
58
|
+
break;
|
|
59
|
+
case 'RUN':
|
|
60
|
+
await this.runTestCase(command);
|
|
61
|
+
break;
|
|
62
|
+
case 'FINALIZE':
|
|
63
|
+
await this.finalize();
|
|
64
|
+
break;
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
|
-
async runTestCase(
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
stopwatch,
|
|
77
|
-
gherkinDocument,
|
|
78
|
-
newId: this.newId,
|
|
79
|
-
pickle,
|
|
80
|
-
testCase,
|
|
81
|
-
retries,
|
|
82
|
-
skip,
|
|
83
|
-
filterStackTraces: this.filterStacktraces,
|
|
84
|
-
supportCodeLibrary: this.supportCodeLibrary,
|
|
85
|
-
worldParameters: this.worldParameters,
|
|
67
|
+
async runTestCase(command) {
|
|
68
|
+
const success = await this.worker.runTestCase(command.assembledTestCase, command.failing);
|
|
69
|
+
this.sendMessage({
|
|
70
|
+
type: 'FINISHED',
|
|
71
|
+
success,
|
|
86
72
|
});
|
|
87
|
-
await testCaseRunner.run();
|
|
88
|
-
this.sendMessage({ ready: true });
|
|
89
73
|
}
|
|
90
74
|
}
|
|
91
|
-
exports.
|
|
75
|
+
exports.ChildProcessWorker = ChildProcessWorker;
|
|
92
76
|
//# sourceMappingURL=worker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/worker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from 'node:events'\nimport { pathToFileURL } from 'node:url'\nimport { register } from 'node:module'\nimport { Envelope, IdGenerator } from '@cucumber/messages'\nimport supportCodeLibraryBuilder from '../../support_code_library_builder'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\nimport tryRequire from '../../try_require'\nimport { Worker } from '../worker'\nimport { RuntimeOptions } from '../index'\nimport {\n WorkerToCoordinatorEvent,\n CoordinatorToWorkerCommand,\n InitializeCommand,\n RunCommand,\n} from './types'\n\nconst { uuid } = IdGenerator\n\ntype IExitFunction = (exitCode: number, error?: Error, message?: string) => void\ntype IMessageSender = (command: WorkerToCoordinatorEvent) => void\n\nexport class ChildProcessWorker {\n private readonly cwd: string\n private readonly exit: IExitFunction\n\n private readonly id: string\n private readonly eventBroadcaster: EventEmitter\n private readonly newId: IdGenerator.NewId\n private readonly sendMessage: IMessageSender\n private options: RuntimeOptions\n private supportCodeLibrary: SupportCodeLibrary\n private worker: Worker\n\n constructor({\n cwd,\n exit,\n id,\n sendMessage,\n }: {\n cwd: string\n exit: IExitFunction\n id: string\n sendMessage: IMessageSender\n }) {\n this.id = id\n this.newId = uuid()\n this.cwd = cwd\n this.exit = exit\n this.sendMessage = sendMessage\n this.eventBroadcaster = new EventEmitter()\n this.eventBroadcaster.on('envelope', (envelope: Envelope) =>\n this.sendMessage({ type: 'ENVELOPE', envelope })\n )\n }\n\n async initialize({\n supportCodeCoordinates,\n supportCodeIds,\n options,\n }: InitializeCommand): Promise<void> {\n supportCodeLibraryBuilder.reset(\n this.cwd,\n this.newId,\n supportCodeCoordinates\n )\n supportCodeCoordinates.requireModules.map((module) => tryRequire(module))\n supportCodeCoordinates.requirePaths.map((module) => tryRequire(module))\n for (const specifier of supportCodeCoordinates.loaders) {\n register(specifier, pathToFileURL('./'))\n }\n for (const path of supportCodeCoordinates.importPaths) {\n await import(pathToFileURL(path).toString())\n }\n this.supportCodeLibrary = supportCodeLibraryBuilder.finalize(supportCodeIds)\n\n this.options = options\n this.worker = new Worker(\n this.id,\n this.eventBroadcaster,\n this.newId,\n this.options,\n this.supportCodeLibrary\n )\n await this.worker.runBeforeAllHooks()\n this.sendMessage({ type: 'READY' })\n }\n\n async finalize(): Promise<void> {\n await this.worker.runAfterAllHooks()\n this.exit(0)\n }\n\n async receiveMessage(command: CoordinatorToWorkerCommand): Promise<void> {\n switch (command.type) {\n case 'INITIALIZE':\n await this.initialize(command)\n break\n case 'RUN':\n await this.runTestCase(command)\n break\n case 'FINALIZE':\n await this.finalize()\n break\n }\n }\n\n async runTestCase(command: RunCommand): Promise<void> {\n const success = await this.worker.runTestCase(\n command.assembledTestCase,\n command.failing\n )\n this.sendMessage({\n type: 'FINISHED',\n success,\n })\n }\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { IdGenerator } from '@cucumber/messages';
|
|
4
|
+
import { RuntimeAdapter } from '../types';
|
|
5
|
+
import { AssembledTestCase } from '../../assemble';
|
|
6
|
+
import { RuntimeOptions } from '../index';
|
|
7
|
+
import { SupportCodeLibrary } from '../../support_code_library_builder/types';
|
|
8
|
+
export declare class InProcessAdapter implements RuntimeAdapter {
|
|
9
|
+
private readonly worker;
|
|
10
|
+
private failing;
|
|
11
|
+
constructor(eventBroadcaster: EventEmitter, newId: IdGenerator.NewId, options: RuntimeOptions, supportCodeLibrary: SupportCodeLibrary);
|
|
12
|
+
run(assembledTestCases: ReadonlyArray<AssembledTestCase>): Promise<boolean>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InProcessAdapter = void 0;
|
|
4
|
+
const worker_1 = require("../worker");
|
|
5
|
+
class InProcessAdapter {
|
|
6
|
+
worker;
|
|
7
|
+
failing = false;
|
|
8
|
+
constructor(eventBroadcaster, newId, options, supportCodeLibrary) {
|
|
9
|
+
this.worker = new worker_1.Worker(undefined, eventBroadcaster, newId, options, supportCodeLibrary);
|
|
10
|
+
}
|
|
11
|
+
async run(assembledTestCases) {
|
|
12
|
+
await this.worker.runBeforeAllHooks();
|
|
13
|
+
for (const item of assembledTestCases) {
|
|
14
|
+
const success = await this.worker.runTestCase(item, this.failing);
|
|
15
|
+
if (!success) {
|
|
16
|
+
this.failing = true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
await this.worker.runAfterAllHooks();
|
|
20
|
+
return !this.failing;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.InProcessAdapter = InProcessAdapter;
|
|
24
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/runtime/serial/adapter.ts"],"names":[],"mappings":";;;AAIA,sCAAkC;AAIlC,MAAa,gBAAgB;IACV,MAAM,CAAQ;IACvB,OAAO,GAAY,KAAK,CAAA;IAEhC,YACE,gBAA8B,EAC9B,KAAwB,EACxB,OAAuB,EACvB,kBAAsC;QAEtC,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,CACtB,SAAS,EACT,gBAAgB,EAChB,KAAK,EACL,OAAO,EACP,kBAAkB,CACnB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CACP,kBAAoD;QAEpD,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAA;QACrC,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE;YACrC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;YACjE,IAAI,CAAC,OAAO,EAAE;gBACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;aACpB;SACF;QACD,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAA;QACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAA;IACtB,CAAC;CACF;AAhCD,4CAgCC","sourcesContent":["import { EventEmitter } from 'node:events'\nimport { IdGenerator } from '@cucumber/messages'\nimport { RuntimeAdapter } from '../types'\nimport { AssembledTestCase } from '../../assemble'\nimport { Worker } from '../worker'\nimport { RuntimeOptions } from '../index'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\n\nexport class InProcessAdapter implements RuntimeAdapter {\n private readonly worker: Worker\n private failing: boolean = false\n\n constructor(\n eventBroadcaster: EventEmitter,\n newId: IdGenerator.NewId,\n options: RuntimeOptions,\n supportCodeLibrary: SupportCodeLibrary\n ) {\n this.worker = new Worker(\n undefined,\n eventBroadcaster,\n newId,\n options,\n supportCodeLibrary\n )\n }\n\n async run(\n assembledTestCases: ReadonlyArray<AssembledTestCase>\n ): Promise<boolean> {\n await this.worker.runBeforeAllHooks()\n for (const item of assembledTestCases) {\n const success = await this.worker.runTestCase(item, this.failing)\n if (!success) {\n this.failing = true\n }\n }\n await this.worker.runAfterAllHooks()\n return !this.failing\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Duration
|
|
1
|
+
import { Duration } from '@cucumber/messages';
|
|
2
2
|
/**
|
|
3
3
|
* A utility for timing test run operations and returning duration and
|
|
4
4
|
* timestamp objects in messages-compatible formats
|
|
@@ -7,6 +7,6 @@ export interface IStopwatch {
|
|
|
7
7
|
start: () => IStopwatch;
|
|
8
8
|
stop: () => IStopwatch;
|
|
9
9
|
duration: () => Duration;
|
|
10
|
-
timestamp: () => Timestamp;
|
|
11
10
|
}
|
|
12
11
|
export declare const create: (base?: Duration) => IStopwatch;
|
|
12
|
+
export declare const timestamp: () => import("@cucumber/messages").Timestamp;
|
package/lib/runtime/stopwatch.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.create = void 0;
|
|
6
|
+
exports.timestamp = exports.create = void 0;
|
|
7
7
|
const messages_1 = require("@cucumber/messages");
|
|
8
8
|
const time_1 = __importDefault(require("../time"));
|
|
9
9
|
class StopwatchImpl {
|
|
@@ -27,10 +27,9 @@ class StopwatchImpl {
|
|
|
27
27
|
}
|
|
28
28
|
return messages_1.TimeConversion.addDurations(this.base, messages_1.TimeConversion.millisecondsToDuration(time_1.default.performance.now() - this.started));
|
|
29
29
|
}
|
|
30
|
-
timestamp() {
|
|
31
|
-
return messages_1.TimeConversion.millisecondsSinceEpochToTimestamp(time_1.default.Date.now());
|
|
32
|
-
}
|
|
33
30
|
}
|
|
34
31
|
const create = (base) => new StopwatchImpl(base);
|
|
35
32
|
exports.create = create;
|
|
33
|
+
const timestamp = () => messages_1.TimeConversion.millisecondsSinceEpochToTimestamp(time_1.default.Date.now());
|
|
34
|
+
exports.timestamp = timestamp;
|
|
36
35
|
//# sourceMappingURL=stopwatch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stopwatch.js","sourceRoot":"","sources":["../../src/runtime/stopwatch.ts"],"names":[],"mappings":";;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"stopwatch.js","sourceRoot":"","sources":["../../src/runtime/stopwatch.ts"],"names":[],"mappings":";;;;;;AAAA,iDAA6D;AAC7D,mDAA6B;AAY7B,MAAM,aAAa;IAGG;IAFZ,OAAO,CAAQ;IAEvB,YAAoB,OAAiB,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;QAAzC,SAAI,GAAJ,IAAI,CAAqC;IAAG,CAAC;IAEjE,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,cAAO,CAAC,WAAW,CAAC,GAAG,EAAE,CAAA;QACxC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC3B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAA;QACxB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,QAAQ;QACN,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE;YACpC,OAAO,IAAI,CAAC,IAAI,CAAA;SACjB;QACD,OAAO,yBAAc,CAAC,YAAY,CAChC,IAAI,CAAC,IAAI,EACT,yBAAc,CAAC,sBAAsB,CACnC,cAAO,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CACzC,CACF,CAAA;IACH,CAAC;CACF;AAEM,MAAM,MAAM,GAAG,CAAC,IAAe,EAAc,EAAE,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAA;AAAjE,QAAA,MAAM,UAA2D;AAEvE,MAAM,SAAS,GAAG,GAAG,EAAE,CAC5B,yBAAc,CAAC,iCAAiC,CAAC,cAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;AADzD,QAAA,SAAS,aACgD","sourcesContent":["import { Duration, TimeConversion } from '@cucumber/messages'\nimport methods from '../time'\n\n/**\n * A utility for timing test run operations and returning duration and\n * timestamp objects in messages-compatible formats\n */\nexport interface IStopwatch {\n start: () => IStopwatch\n stop: () => IStopwatch\n duration: () => Duration\n}\n\nclass StopwatchImpl implements IStopwatch {\n private started: number\n\n constructor(private base: Duration = { seconds: 0, nanos: 0 }) {}\n\n start(): IStopwatch {\n this.started = methods.performance.now()\n return this\n }\n\n stop(): IStopwatch {\n this.base = this.duration()\n this.started = undefined\n return this\n }\n\n duration(): Duration {\n if (typeof this.started !== 'number') {\n return this.base\n }\n return TimeConversion.addDurations(\n this.base,\n TimeConversion.millisecondsToDuration(\n methods.performance.now() - this.started\n )\n )\n }\n}\n\nexport const create = (base?: Duration): IStopwatch => new StopwatchImpl(base)\n\nexport const timestamp = () =>\n TimeConversion.millisecondsSinceEpochToTimestamp(methods.Date.now())\n"]}
|
|
@@ -3,15 +3,13 @@ import { EventEmitter } from 'node:events';
|
|
|
3
3
|
import * as messages from '@cucumber/messages';
|
|
4
4
|
import { IdGenerator } from '@cucumber/messages';
|
|
5
5
|
import { JsonObject } from 'type-fest';
|
|
6
|
-
import {
|
|
6
|
+
import { ITestCaseHookParameter, SupportCodeLibrary } from '../support_code_library_builder/types';
|
|
7
7
|
import TestCaseHookDefinition from '../models/test_case_hook_definition';
|
|
8
8
|
import TestStepHookDefinition from '../models/test_step_hook_definition';
|
|
9
9
|
import { IDefinition } from '../models/definition';
|
|
10
|
-
import { IStopwatch } from './stopwatch';
|
|
11
10
|
export interface INewTestCaseRunnerOptions {
|
|
12
11
|
workerId?: string;
|
|
13
12
|
eventBroadcaster: EventEmitter;
|
|
14
|
-
stopwatch: IStopwatch;
|
|
15
13
|
gherkinDocument: messages.GherkinDocument;
|
|
16
14
|
newId: IdGenerator.NewId;
|
|
17
15
|
pickle: messages.Pickle;
|
|
@@ -28,7 +26,6 @@ export default class TestCaseRunner {
|
|
|
28
26
|
private currentTestCaseStartedId;
|
|
29
27
|
private currentTestStepId;
|
|
30
28
|
private readonly eventBroadcaster;
|
|
31
|
-
private readonly stopwatch;
|
|
32
29
|
private readonly gherkinDocument;
|
|
33
30
|
private readonly newId;
|
|
34
31
|
private readonly pickle;
|
|
@@ -40,7 +37,7 @@ export default class TestCaseRunner {
|
|
|
40
37
|
private testStepResults;
|
|
41
38
|
private world;
|
|
42
39
|
private readonly worldParameters;
|
|
43
|
-
constructor({ workerId, eventBroadcaster,
|
|
40
|
+
constructor({ workerId, eventBroadcaster, gherkinDocument, newId, pickle, testCase, retries, skip, filterStackTraces, supportCodeLibrary, worldParameters, }: INewTestCaseRunnerOptions);
|
|
44
41
|
resetTestProgressData(): void;
|
|
45
42
|
getBeforeStepHookDefinitions(): TestStepHookDefinition[];
|
|
46
43
|
getAfterStepHookDefinitions(): TestStepHookDefinition[];
|