@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.
Files changed (93) hide show
  1. package/lib/api/formatters.js +5 -4
  2. package/lib/api/formatters.js.map +1 -1
  3. package/lib/api/run_cucumber.js +8 -10
  4. package/lib/api/run_cucumber.js.map +1 -1
  5. package/lib/{runtime → assemble}/assemble_test_cases.d.ts +4 -6
  6. package/lib/{runtime → assemble}/assemble_test_cases.js +9 -8
  7. package/lib/assemble/assemble_test_cases.js.map +1 -0
  8. package/lib/assemble/index.d.ts +2 -0
  9. package/lib/assemble/index.js +19 -0
  10. package/lib/assemble/index.js.map +1 -0
  11. package/lib/assemble/types.d.ts +10 -0
  12. package/lib/{runtime/parallel/command_types.js → assemble/types.js} +1 -1
  13. package/lib/assemble/types.js.map +1 -0
  14. package/lib/cli/helpers.d.ts +0 -23
  15. package/lib/cli/helpers.js +1 -33
  16. package/lib/cli/helpers.js.map +1 -1
  17. package/lib/formatter/builtin/html.d.ts +5 -1
  18. package/lib/formatter/builtin/html.js +55 -4
  19. package/lib/formatter/builtin/html.js.map +1 -1
  20. package/lib/formatter/create_stream.d.ts +4 -1
  21. package/lib/formatter/create_stream.js +6 -2
  22. package/lib/formatter/create_stream.js.map +1 -1
  23. package/lib/formatter/index.d.ts +3 -0
  24. package/lib/formatter/index.js.map +1 -1
  25. package/lib/index.d.ts +0 -16
  26. package/lib/index.js +1 -16
  27. package/lib/index.js.map +1 -1
  28. package/lib/plugin/plugin_manager.d.ts +1 -1
  29. package/lib/plugin/plugin_manager.js +6 -2
  30. package/lib/plugin/plugin_manager.js.map +1 -1
  31. package/lib/plugin/types.d.ts +3 -0
  32. package/lib/plugin/types.js.map +1 -1
  33. package/lib/runtime/attachment_manager/index.d.ts +2 -0
  34. package/lib/runtime/attachment_manager/index.js +3 -0
  35. package/lib/runtime/attachment_manager/index.js.map +1 -1
  36. package/lib/runtime/coordinator.d.ts +16 -0
  37. package/lib/runtime/coordinator.js +42 -0
  38. package/lib/runtime/coordinator.js.map +1 -0
  39. package/lib/runtime/helpers.d.ts +3 -3
  40. package/lib/runtime/helpers.js.map +1 -1
  41. package/lib/runtime/index.d.ts +2 -41
  42. package/lib/runtime/index.js +14 -81
  43. package/lib/runtime/index.js.map +1 -1
  44. package/lib/runtime/make_runtime.d.ts +17 -0
  45. package/lib/runtime/make_runtime.js +14 -0
  46. package/lib/runtime/make_runtime.js.map +1 -0
  47. package/lib/runtime/parallel/adapter.d.ts +48 -0
  48. package/lib/runtime/parallel/adapter.js +152 -0
  49. package/lib/runtime/parallel/adapter.js.map +1 -0
  50. package/lib/runtime/parallel/run_worker.js +2 -5
  51. package/lib/runtime/parallel/run_worker.js.map +1 -1
  52. package/lib/runtime/parallel/types.d.ts +32 -0
  53. package/lib/runtime/parallel/types.js +3 -0
  54. package/lib/runtime/parallel/types.js.map +1 -0
  55. package/lib/runtime/parallel/worker.d.ts +8 -9
  56. package/lib/runtime/parallel/worker.js +28 -44
  57. package/lib/runtime/parallel/worker.js.map +1 -1
  58. package/lib/runtime/serial/adapter.d.ts +13 -0
  59. package/lib/runtime/serial/adapter.js +24 -0
  60. package/lib/runtime/serial/adapter.js.map +1 -0
  61. package/lib/runtime/stopwatch.d.ts +2 -2
  62. package/lib/runtime/stopwatch.js +3 -4
  63. package/lib/runtime/stopwatch.js.map +1 -1
  64. package/lib/runtime/test_case_runner.d.ts +2 -5
  65. package/lib/runtime/test_case_runner.js +7 -7
  66. package/lib/runtime/test_case_runner.js.map +1 -1
  67. package/lib/runtime/types.d.ts +17 -0
  68. package/lib/runtime/types.js +3 -0
  69. package/lib/runtime/types.js.map +1 -0
  70. package/lib/runtime/worker.d.ts +18 -0
  71. package/lib/runtime/worker.js +57 -0
  72. package/lib/runtime/worker.js.map +1 -0
  73. package/lib/support_code_library_builder/index.d.ts +2 -3
  74. package/lib/support_code_library_builder/index.js.map +1 -1
  75. package/lib/support_code_library_builder/types.d.ts +5 -0
  76. package/lib/support_code_library_builder/types.js.map +1 -1
  77. package/lib/support_code_library_builder/world.d.ts +5 -2
  78. package/lib/support_code_library_builder/world.js +3 -1
  79. package/lib/support_code_library_builder/world.js.map +1 -1
  80. package/lib/version.d.ts +1 -1
  81. package/lib/version.js +1 -1
  82. package/lib/version.js.map +1 -1
  83. package/lib/wrapper.mjs +0 -3
  84. package/package.json +6 -6
  85. package/lib/api/runtime.d.ts +0 -18
  86. package/lib/api/runtime.js +0 -33
  87. package/lib/api/runtime.js.map +0 -1
  88. package/lib/runtime/assemble_test_cases.js.map +0 -1
  89. package/lib/runtime/parallel/command_types.d.ts +0 -31
  90. package/lib/runtime/parallel/command_types.js.map +0 -1
  91. package/lib/runtime/parallel/coordinator.d.ts +0 -66
  92. package/lib/runtime/parallel/coordinator.js +0 -209
  93. package/lib/runtime/parallel/coordinator.js.map +0 -1
@@ -1,18 +0,0 @@
1
- /// <reference types="node" />
2
- import { EventEmitter } from 'node:events';
3
- import { IdGenerator } from '@cucumber/messages';
4
- import { IRuntime } from '../runtime';
5
- import { EventDataCollector } from '../formatter/helpers';
6
- import { SupportCodeLibrary } from '../support_code_library_builder/types';
7
- import { ILogger } from '../logger';
8
- import { IRunOptionsRuntime } from './types';
9
- export declare function makeRuntime({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, newId, supportCodeLibrary, options: { parallel, ...options }, }: {
10
- cwd: string;
11
- logger: ILogger;
12
- eventBroadcaster: EventEmitter;
13
- eventDataCollector: EventDataCollector;
14
- newId: IdGenerator.NewId;
15
- pickleIds: string[];
16
- supportCodeLibrary: SupportCodeLibrary;
17
- options: IRunOptionsRuntime;
18
- }): IRuntime;
@@ -1,33 +0,0 @@
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.makeRuntime = void 0;
7
- const runtime_1 = __importDefault(require("../runtime"));
8
- const coordinator_1 = __importDefault(require("../runtime/parallel/coordinator"));
9
- function makeRuntime({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, newId, supportCodeLibrary, options: { parallel, ...options }, }) {
10
- if (parallel > 0) {
11
- return new coordinator_1.default({
12
- cwd,
13
- logger,
14
- eventBroadcaster,
15
- eventDataCollector,
16
- pickleIds,
17
- options,
18
- newId,
19
- supportCodeLibrary,
20
- numberOfWorkers: parallel,
21
- });
22
- }
23
- return new runtime_1.default({
24
- eventBroadcaster,
25
- eventDataCollector,
26
- newId,
27
- pickleIds,
28
- supportCodeLibrary,
29
- options,
30
- });
31
- }
32
- exports.makeRuntime = makeRuntime;
33
- //# sourceMappingURL=runtime.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/api/runtime.ts"],"names":[],"mappings":";;;;;;AAEA,yDAA8C;AAG9C,kFAAyD;AAIzD,SAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,KAAK,EACL,kBAAkB,EAClB,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,GAUlC;IACC,IAAI,QAAQ,GAAG,CAAC,EAAE;QAChB,OAAO,IAAI,qBAAW,CAAC;YACrB,GAAG;YACH,MAAM;YACN,gBAAgB;YAChB,kBAAkB;YAClB,SAAS;YACT,OAAO;YACP,KAAK;YACL,kBAAkB;YAClB,eAAe,EAAE,QAAQ;SAC1B,CAAC,CAAA;KACH;IACD,OAAO,IAAI,iBAAO,CAAC;QACjB,gBAAgB;QAChB,kBAAkB;QAClB,KAAK;QACL,SAAS;QACT,kBAAkB;QAClB,OAAO;KACR,CAAC,CAAA;AACJ,CAAC;AAxCD,kCAwCC","sourcesContent":["import { EventEmitter } from 'node:events'\nimport { IdGenerator } from '@cucumber/messages'\nimport Runtime, { IRuntime } from '../runtime'\nimport { EventDataCollector } from '../formatter/helpers'\nimport { SupportCodeLibrary } from '../support_code_library_builder/types'\nimport Coordinator from '../runtime/parallel/coordinator'\nimport { ILogger } from '../logger'\nimport { IRunOptionsRuntime } from './types'\n\nexport function makeRuntime({\n cwd,\n logger,\n eventBroadcaster,\n eventDataCollector,\n pickleIds,\n newId,\n supportCodeLibrary,\n options: { parallel, ...options },\n}: {\n cwd: string\n logger: ILogger\n eventBroadcaster: EventEmitter\n eventDataCollector: EventDataCollector\n newId: IdGenerator.NewId\n pickleIds: string[]\n supportCodeLibrary: SupportCodeLibrary\n options: IRunOptionsRuntime\n}): IRuntime {\n if (parallel > 0) {\n return new Coordinator({\n cwd,\n logger,\n eventBroadcaster,\n eventDataCollector,\n pickleIds,\n options,\n newId,\n supportCodeLibrary,\n numberOfWorkers: parallel,\n })\n }\n return new Runtime({\n eventBroadcaster,\n eventDataCollector,\n newId,\n pickleIds,\n supportCodeLibrary,\n options,\n })\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"assemble_test_cases.js","sourceRoot":"","sources":["../../src/runtime/assemble_test_cases.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from 'node:events'\nimport * as messages from '@cucumber/messages'\nimport { IdGenerator } from '@cucumber/messages'\nimport { Group } from '@cucumber/cucumber-expressions'\nimport { SupportCodeLibrary } from '../support_code_library_builder/types'\nimport { doesHaveValue } from '../value_checker'\n\nexport declare type IAssembledTestCases = Record<string, messages.TestCase>\n\nexport interface IAssembleTestCasesOptions {\n eventBroadcaster: EventEmitter\n newId: IdGenerator.NewId\n pickles: messages.Pickle[]\n supportCodeLibrary: SupportCodeLibrary\n}\n\nexport async function assembleTestCases({\n eventBroadcaster,\n newId,\n pickles,\n supportCodeLibrary,\n}: IAssembleTestCasesOptions): Promise<IAssembledTestCases> {\n const result: IAssembledTestCases = {}\n for (const pickle of pickles) {\n const { id: pickleId } = pickle\n const testCaseId = newId()\n const fromBeforeHooks: messages.TestStep[] = makeBeforeHookSteps({\n supportCodeLibrary,\n pickle,\n newId,\n })\n const fromStepDefinitions: messages.TestStep[] = makeSteps({\n pickle,\n supportCodeLibrary,\n newId,\n })\n const fromAfterHooks: messages.TestStep[] = makeAfterHookSteps({\n supportCodeLibrary,\n pickle,\n newId,\n })\n const testCase: messages.TestCase = {\n pickleId,\n id: testCaseId,\n testSteps: [\n ...fromBeforeHooks,\n ...fromStepDefinitions,\n ...fromAfterHooks,\n ],\n }\n eventBroadcaster.emit('envelope', { testCase })\n result[pickleId] = testCase\n }\n return result\n}\n\nfunction makeAfterHookSteps({\n supportCodeLibrary,\n pickle,\n newId,\n}: {\n supportCodeLibrary: SupportCodeLibrary\n pickle: messages.Pickle\n newId: IdGenerator.NewId\n}): messages.TestStep[] {\n return supportCodeLibrary.afterTestCaseHookDefinitions\n .slice(0)\n .reverse()\n .filter((hookDefinition) => hookDefinition.appliesToTestCase(pickle))\n .map((hookDefinition) => ({\n id: newId(),\n hookId: hookDefinition.id,\n }))\n}\n\nfunction makeBeforeHookSteps({\n supportCodeLibrary,\n pickle,\n newId,\n}: {\n supportCodeLibrary: SupportCodeLibrary\n pickle: messages.Pickle\n newId: IdGenerator.NewId\n}): messages.TestStep[] {\n return supportCodeLibrary.beforeTestCaseHookDefinitions\n .filter((hookDefinition) => hookDefinition.appliesToTestCase(pickle))\n .map((hookDefinition) => ({\n id: newId(),\n hookId: hookDefinition.id,\n }))\n}\n\nfunction makeSteps({\n pickle,\n supportCodeLibrary,\n newId,\n}: {\n pickle: messages.Pickle\n supportCodeLibrary: SupportCodeLibrary\n newId: () => string\n}): messages.TestStep[] {\n return pickle.steps.map((pickleStep) => {\n const stepDefinitions = supportCodeLibrary.stepDefinitions.filter(\n (stepDefinition) => stepDefinition.matchesStepName(pickleStep.text)\n )\n return {\n id: newId(),\n pickleStepId: pickleStep.id,\n stepDefinitionIds: stepDefinitions.map(\n (stepDefinition) => stepDefinition.id\n ),\n stepMatchArgumentsLists: stepDefinitions.map((stepDefinition) => {\n const result = stepDefinition.expression.match(pickleStep.text)\n return {\n stepMatchArguments: result.map((arg) => {\n return {\n group: mapArgumentGroup(arg.group),\n parameterTypeName: arg.parameterType.name,\n }\n }),\n }\n }),\n }\n })\n}\n\nfunction mapArgumentGroup(group: Group): messages.Group {\n return {\n start: group.start,\n value: group.value,\n children: doesHaveValue(group.children)\n ? group.children.map((child) => mapArgumentGroup(child))\n : undefined,\n }\n}\n"]}
@@ -1,31 +0,0 @@
1
- import * as messages from '@cucumber/messages';
2
- import { Envelope } from '@cucumber/messages';
3
- import { IRuntimeOptions } from '../index';
4
- import { ISupportCodeCoordinates } from '../../api';
5
- export interface IWorkerCommand {
6
- initialize?: IWorkerCommandInitialize;
7
- run?: IWorkerCommandRun;
8
- finalize?: boolean;
9
- }
10
- export interface IWorkerCommandInitialize {
11
- supportCodeCoordinates: ISupportCodeCoordinates;
12
- supportCodeIds?: ICanonicalSupportCodeIds;
13
- options: IRuntimeOptions;
14
- }
15
- export interface ICanonicalSupportCodeIds {
16
- stepDefinitionIds: string[];
17
- beforeTestCaseHookDefinitionIds: string[];
18
- afterTestCaseHookDefinitionIds: string[];
19
- }
20
- export interface IWorkerCommandRun {
21
- retries: number;
22
- skip: boolean;
23
- elapsed: messages.Duration;
24
- pickle: messages.Pickle;
25
- testCase: messages.TestCase;
26
- gherkinDocument: messages.GherkinDocument;
27
- }
28
- export interface ICoordinatorReport {
29
- jsonEnvelope?: Envelope;
30
- ready?: boolean;
31
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"command_types.js","sourceRoot":"","sources":["../../../src/runtime/parallel/command_types.ts"],"names":[],"mappings":"","sourcesContent":["import * as messages from '@cucumber/messages'\nimport { Envelope } from '@cucumber/messages'\nimport { IRuntimeOptions } from '../index'\nimport { ISupportCodeCoordinates } from '../../api'\n\n// Messages from Coordinator to Worker\n\nexport interface IWorkerCommand {\n initialize?: IWorkerCommandInitialize\n run?: IWorkerCommandRun\n finalize?: boolean\n}\n\nexport interface IWorkerCommandInitialize {\n supportCodeCoordinates: ISupportCodeCoordinates\n supportCodeIds?: ICanonicalSupportCodeIds\n options: IRuntimeOptions\n}\n\nexport interface ICanonicalSupportCodeIds {\n stepDefinitionIds: string[]\n beforeTestCaseHookDefinitionIds: string[]\n afterTestCaseHookDefinitionIds: string[]\n}\n\nexport interface IWorkerCommandRun {\n retries: number\n skip: boolean\n elapsed: messages.Duration\n pickle: messages.Pickle\n testCase: messages.TestCase\n gherkinDocument: messages.GherkinDocument\n}\n\n// Messages from Worker to Coordinator\n\nexport interface ICoordinatorReport {\n jsonEnvelope?: Envelope\n ready?: boolean\n}\n"]}
@@ -1,66 +0,0 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- import { ChildProcess } from 'node:child_process';
4
- import { EventEmitter } from 'node:events';
5
- import * as messages from '@cucumber/messages';
6
- import { IdGenerator } from '@cucumber/messages';
7
- import { EventDataCollector } from '../../formatter/helpers';
8
- import { IRuntime, IRuntimeOptions } from '..';
9
- import { SupportCodeLibrary } from '../../support_code_library_builder/types';
10
- import { ILogger } from '../../logger';
11
- import { ICoordinatorReport } from './command_types';
12
- export interface INewCoordinatorOptions {
13
- cwd: string;
14
- logger: ILogger;
15
- eventBroadcaster: EventEmitter;
16
- eventDataCollector: EventDataCollector;
17
- options: IRuntimeOptions;
18
- newId: IdGenerator.NewId;
19
- pickleIds: string[];
20
- supportCodeLibrary: SupportCodeLibrary;
21
- numberOfWorkers: number;
22
- }
23
- declare const enum WorkerState {
24
- 'idle' = 0,
25
- 'closed' = 1,
26
- 'running' = 2,
27
- 'new' = 3
28
- }
29
- interface IWorker {
30
- state: WorkerState;
31
- process: ChildProcess;
32
- id: string;
33
- }
34
- interface IPicklePlacement {
35
- index: number;
36
- pickle: messages.Pickle;
37
- }
38
- export default class Coordinator implements IRuntime {
39
- private readonly cwd;
40
- private readonly eventBroadcaster;
41
- private readonly eventDataCollector;
42
- private readonly stopwatch;
43
- private onFinish;
44
- private readonly options;
45
- private readonly newId;
46
- private readonly pickleIds;
47
- private assembledTestCases;
48
- private readonly inProgressPickles;
49
- private readonly workers;
50
- private readonly supportCodeLibrary;
51
- private readonly numberOfWorkers;
52
- private readonly logger;
53
- private success;
54
- private idleInterventions;
55
- constructor({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, options, newId, supportCodeLibrary, numberOfWorkers, }: INewCoordinatorOptions);
56
- parseWorkerMessage(worker: IWorker, message: ICoordinatorReport): void;
57
- awakenWorkers(triggeringWorker: IWorker): void;
58
- startWorker(id: string, total: number): void;
59
- onWorkerProcessClose(exitCode: number): void;
60
- parseTestCaseResult(testCaseFinished: messages.TestCaseFinished, workerId: string): void;
61
- start(): Promise<boolean>;
62
- nextPicklePlacement(): IPicklePlacement;
63
- placementAt(index: number): IPicklePlacement;
64
- giveWork(worker: IWorker, force?: boolean): void;
65
- }
66
- export {};
@@ -1,209 +0,0 @@
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
- const node_child_process_1 = require("node:child_process");
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const helpers_1 = require("../helpers");
9
- const value_checker_1 = require("../../value_checker");
10
- const stopwatch_1 = require("../stopwatch");
11
- const assemble_test_cases_1 = require("../assemble_test_cases");
12
- const runWorkerPath = node_path_1.default.resolve(__dirname, 'run_worker.js');
13
- class Coordinator {
14
- cwd;
15
- eventBroadcaster;
16
- eventDataCollector;
17
- stopwatch;
18
- onFinish;
19
- options;
20
- newId;
21
- pickleIds;
22
- assembledTestCases;
23
- inProgressPickles;
24
- workers;
25
- supportCodeLibrary;
26
- numberOfWorkers;
27
- logger;
28
- success;
29
- idleInterventions;
30
- constructor({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, options, newId, supportCodeLibrary, numberOfWorkers, }) {
31
- this.cwd = cwd;
32
- this.logger = logger;
33
- this.eventBroadcaster = eventBroadcaster;
34
- this.eventDataCollector = eventDataCollector;
35
- this.stopwatch = (0, stopwatch_1.create)();
36
- this.options = options;
37
- this.newId = newId;
38
- this.supportCodeLibrary = supportCodeLibrary;
39
- this.pickleIds = Array.from(pickleIds);
40
- this.numberOfWorkers = numberOfWorkers;
41
- this.success = true;
42
- this.workers = {};
43
- this.inProgressPickles = {};
44
- this.idleInterventions = 0;
45
- }
46
- parseWorkerMessage(worker, message) {
47
- if (message.ready) {
48
- worker.state = 0 /* WorkerState.idle */;
49
- this.awakenWorkers(worker);
50
- }
51
- else if ((0, value_checker_1.doesHaveValue)(message.jsonEnvelope)) {
52
- const envelope = message.jsonEnvelope;
53
- this.eventBroadcaster.emit('envelope', envelope);
54
- if ((0, value_checker_1.doesHaveValue)(envelope.testCaseFinished)) {
55
- this.parseTestCaseResult(envelope.testCaseFinished, worker.id);
56
- }
57
- }
58
- else {
59
- throw new Error(`Unexpected message from worker: ${JSON.stringify(message)}`);
60
- }
61
- }
62
- awakenWorkers(triggeringWorker) {
63
- Object.values(this.workers).forEach((worker) => {
64
- if (worker.state === 0 /* WorkerState.idle */) {
65
- this.giveWork(worker);
66
- }
67
- return worker.state !== 0 /* WorkerState.idle */;
68
- });
69
- if (Object.keys(this.inProgressPickles).length == 0 &&
70
- this.pickleIds.length > 0) {
71
- this.giveWork(triggeringWorker, true);
72
- this.idleInterventions++;
73
- }
74
- }
75
- startWorker(id, total) {
76
- const workerProcess = (0, node_child_process_1.fork)(runWorkerPath, [], {
77
- cwd: this.cwd,
78
- env: {
79
- ...process.env,
80
- CUCUMBER_PARALLEL: 'true',
81
- CUCUMBER_TOTAL_WORKERS: total.toString(),
82
- CUCUMBER_WORKER_ID: id,
83
- },
84
- stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
85
- });
86
- const worker = { state: 3 /* WorkerState.new */, process: workerProcess, id };
87
- this.workers[id] = worker;
88
- worker.process.on('message', (message) => {
89
- this.parseWorkerMessage(worker, message);
90
- });
91
- worker.process.on('close', (exitCode) => {
92
- worker.state = 1 /* WorkerState.closed */;
93
- this.onWorkerProcessClose(exitCode);
94
- });
95
- const initializeCommand = {
96
- initialize: {
97
- supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,
98
- supportCodeIds: {
99
- stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map((s) => s.id),
100
- beforeTestCaseHookDefinitionIds: this.supportCodeLibrary.beforeTestCaseHookDefinitions.map((h) => h.id),
101
- afterTestCaseHookDefinitionIds: this.supportCodeLibrary.afterTestCaseHookDefinitions.map((h) => h.id),
102
- },
103
- options: this.options,
104
- },
105
- };
106
- worker.process.send(initializeCommand);
107
- }
108
- onWorkerProcessClose(exitCode) {
109
- const success = exitCode === 0;
110
- if (!success) {
111
- this.success = false;
112
- }
113
- if (Object.values(this.workers).every((x) => x.state === 1 /* WorkerState.closed */)) {
114
- const envelope = {
115
- testRunFinished: {
116
- timestamp: this.stopwatch.timestamp(),
117
- success,
118
- },
119
- };
120
- this.eventBroadcaster.emit('envelope', envelope);
121
- this.onFinish(this.success);
122
- }
123
- }
124
- parseTestCaseResult(testCaseFinished, workerId) {
125
- const { worstTestStepResult } = this.eventDataCollector.getTestCaseAttempt(testCaseFinished.testCaseStartedId);
126
- if (!testCaseFinished.willBeRetried) {
127
- delete this.inProgressPickles[workerId];
128
- if ((0, helpers_1.shouldCauseFailure)(worstTestStepResult.status, this.options)) {
129
- this.success = false;
130
- }
131
- }
132
- }
133
- async start() {
134
- const envelope = {
135
- testRunStarted: {
136
- timestamp: this.stopwatch.timestamp(),
137
- },
138
- };
139
- this.eventBroadcaster.emit('envelope', envelope);
140
- this.stopwatch.start();
141
- this.assembledTestCases = await (0, assemble_test_cases_1.assembleTestCases)({
142
- eventBroadcaster: this.eventBroadcaster,
143
- newId: this.newId,
144
- pickles: this.pickleIds.map((pickleId) => this.eventDataCollector.getPickle(pickleId)),
145
- supportCodeLibrary: this.supportCodeLibrary,
146
- });
147
- return await new Promise((resolve) => {
148
- for (let i = 0; i < this.numberOfWorkers; i++) {
149
- this.startWorker(i.toString(), this.numberOfWorkers);
150
- }
151
- this.onFinish = (status) => {
152
- if (this.idleInterventions > 0) {
153
- this.logger.warn(`WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`);
154
- }
155
- resolve(status);
156
- };
157
- });
158
- }
159
- nextPicklePlacement() {
160
- for (let index = 0; index < this.pickleIds.length; index++) {
161
- const placement = this.placementAt(index);
162
- if (this.supportCodeLibrary.parallelCanAssign(placement.pickle, Object.values(this.inProgressPickles))) {
163
- return placement;
164
- }
165
- }
166
- return null;
167
- }
168
- placementAt(index) {
169
- return {
170
- index,
171
- pickle: this.eventDataCollector.getPickle(this.pickleIds[index]),
172
- };
173
- }
174
- giveWork(worker, force = false) {
175
- if (this.pickleIds.length < 1) {
176
- const finalizeCommand = { finalize: true };
177
- worker.state = 2 /* WorkerState.running */;
178
- worker.process.send(finalizeCommand);
179
- return;
180
- }
181
- const picklePlacement = force
182
- ? this.placementAt(0)
183
- : this.nextPicklePlacement();
184
- if (picklePlacement === null) {
185
- return;
186
- }
187
- const { index: nextPickleIndex, pickle } = picklePlacement;
188
- this.pickleIds.splice(nextPickleIndex, 1);
189
- this.inProgressPickles[worker.id] = pickle;
190
- const testCase = this.assembledTestCases[pickle.id];
191
- const gherkinDocument = this.eventDataCollector.getGherkinDocument(pickle.uri);
192
- const retries = (0, helpers_1.retriesForPickle)(pickle, this.options);
193
- const skip = this.options.dryRun || (this.options.failFast && !this.success);
194
- const runCommand = {
195
- run: {
196
- retries,
197
- skip,
198
- elapsed: this.stopwatch.duration(),
199
- pickle,
200
- testCase,
201
- gherkinDocument,
202
- },
203
- };
204
- worker.state = 2 /* WorkerState.running */;
205
- worker.process.send(runCommand);
206
- }
207
- }
208
- exports.default = Coordinator;
209
- //# sourceMappingURL=coordinator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../../src/runtime/parallel/coordinator.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 * as messages from '@cucumber/messages'\nimport { IdGenerator } from '@cucumber/messages'\nimport { retriesForPickle, shouldCauseFailure } from '../helpers'\nimport { EventDataCollector } from '../../formatter/helpers'\nimport { IRuntime, IRuntimeOptions } from '..'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\nimport { doesHaveValue } from '../../value_checker'\nimport { IStopwatch, create } from '../stopwatch'\nimport { assembleTestCases, IAssembledTestCases } from '../assemble_test_cases'\nimport { ILogger } from '../../logger'\nimport { ICoordinatorReport, IWorkerCommand } from './command_types'\n\nconst runWorkerPath = path.resolve(__dirname, 'run_worker.js')\n\nexport interface INewCoordinatorOptions {\n cwd: string\n logger: ILogger\n eventBroadcaster: EventEmitter\n eventDataCollector: EventDataCollector\n options: IRuntimeOptions\n newId: IdGenerator.NewId\n pickleIds: string[]\n supportCodeLibrary: SupportCodeLibrary\n numberOfWorkers: number\n}\n\nconst enum WorkerState {\n 'idle',\n 'closed',\n 'running',\n 'new',\n}\n\ninterface IWorker {\n state: WorkerState\n process: ChildProcess\n id: string\n}\n\ninterface IPicklePlacement {\n index: number\n pickle: messages.Pickle\n}\n\nexport default class Coordinator implements IRuntime {\n private readonly cwd: string\n private readonly eventBroadcaster: EventEmitter\n private readonly eventDataCollector: EventDataCollector\n private readonly stopwatch: IStopwatch\n private onFinish: (success: boolean) => void\n private readonly options: IRuntimeOptions\n private readonly newId: IdGenerator.NewId\n private readonly pickleIds: string[]\n private assembledTestCases: IAssembledTestCases\n private readonly inProgressPickles: Record<string, messages.Pickle>\n private readonly workers: Record<string, IWorker>\n private readonly supportCodeLibrary: SupportCodeLibrary\n private readonly numberOfWorkers: number\n private readonly logger: ILogger\n private success: boolean\n private idleInterventions: number\n\n constructor({\n cwd,\n logger,\n eventBroadcaster,\n eventDataCollector,\n pickleIds,\n options,\n newId,\n supportCodeLibrary,\n numberOfWorkers,\n }: INewCoordinatorOptions) {\n this.cwd = cwd\n this.logger = logger\n this.eventBroadcaster = eventBroadcaster\n this.eventDataCollector = eventDataCollector\n this.stopwatch = create()\n this.options = options\n this.newId = newId\n this.supportCodeLibrary = supportCodeLibrary\n this.pickleIds = Array.from(pickleIds)\n this.numberOfWorkers = numberOfWorkers\n this.success = true\n this.workers = {}\n this.inProgressPickles = {}\n this.idleInterventions = 0\n }\n\n parseWorkerMessage(worker: IWorker, message: ICoordinatorReport): void {\n if (message.ready) {\n worker.state = WorkerState.idle\n this.awakenWorkers(worker)\n } else if (doesHaveValue(message.jsonEnvelope)) {\n const envelope = message.jsonEnvelope\n this.eventBroadcaster.emit('envelope', envelope)\n if (doesHaveValue(envelope.testCaseFinished)) {\n this.parseTestCaseResult(envelope.testCaseFinished, worker.id)\n }\n } else {\n throw new Error(\n `Unexpected message from worker: ${JSON.stringify(message)}`\n )\n }\n }\n\n awakenWorkers(triggeringWorker: IWorker): 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 (\n Object.keys(this.inProgressPickles).length == 0 &&\n this.pickleIds.length > 0\n ) {\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.cwd,\n env: {\n ...process.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: ICoordinatorReport) => {\n this.parseWorkerMessage(worker, message)\n })\n worker.process.on('close', (exitCode) => {\n worker.state = WorkerState.closed\n this.onWorkerProcessClose(exitCode)\n })\n const initializeCommand: IWorkerCommand = {\n 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(\n (h) => h.id\n ),\n },\n options: this.options,\n },\n }\n worker.process.send(initializeCommand)\n }\n\n onWorkerProcessClose(exitCode: number): void {\n const success = exitCode === 0\n if (!success) {\n this.success = false\n }\n\n if (\n Object.values(this.workers).every((x) => x.state === WorkerState.closed)\n ) {\n const envelope: messages.Envelope = {\n testRunFinished: {\n timestamp: this.stopwatch.timestamp(),\n success,\n },\n }\n this.eventBroadcaster.emit('envelope', envelope)\n this.onFinish(this.success)\n }\n }\n\n parseTestCaseResult(\n testCaseFinished: messages.TestCaseFinished,\n workerId: string\n ): void {\n const { worstTestStepResult } = this.eventDataCollector.getTestCaseAttempt(\n testCaseFinished.testCaseStartedId\n )\n if (!testCaseFinished.willBeRetried) {\n delete this.inProgressPickles[workerId]\n\n if (shouldCauseFailure(worstTestStepResult.status, this.options)) {\n this.success = false\n }\n }\n }\n\n async start(): Promise<boolean> {\n const envelope: messages.Envelope = {\n testRunStarted: {\n timestamp: this.stopwatch.timestamp(),\n },\n }\n this.eventBroadcaster.emit('envelope', envelope)\n this.stopwatch.start()\n this.assembledTestCases = await assembleTestCases({\n eventBroadcaster: this.eventBroadcaster,\n newId: this.newId,\n pickles: this.pickleIds.map((pickleId) =>\n this.eventDataCollector.getPickle(pickleId)\n ),\n supportCodeLibrary: this.supportCodeLibrary,\n })\n return await new Promise<boolean>((resolve) => {\n for (let i = 0; i < this.numberOfWorkers; i++) {\n this.startWorker(i.toString(), this.numberOfWorkers)\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 nextPicklePlacement(): IPicklePlacement {\n for (let index = 0; index < this.pickleIds.length; index++) {\n const placement = this.placementAt(index)\n if (\n this.supportCodeLibrary.parallelCanAssign(\n placement.pickle,\n Object.values(this.inProgressPickles)\n )\n ) {\n return placement\n }\n }\n\n return null\n }\n\n placementAt(index: number): IPicklePlacement {\n return {\n index,\n pickle: this.eventDataCollector.getPickle(this.pickleIds[index]),\n }\n }\n\n giveWork(worker: IWorker, force: boolean = false): void {\n if (this.pickleIds.length < 1) {\n const finalizeCommand: IWorkerCommand = { finalize: true }\n worker.state = WorkerState.running\n worker.process.send(finalizeCommand)\n return\n }\n\n const picklePlacement = force\n ? this.placementAt(0)\n : this.nextPicklePlacement()\n\n if (picklePlacement === null) {\n return\n }\n\n const { index: nextPickleIndex, pickle } = picklePlacement\n\n this.pickleIds.splice(nextPickleIndex, 1)\n this.inProgressPickles[worker.id] = pickle\n const testCase = this.assembledTestCases[pickle.id]\n const gherkinDocument = this.eventDataCollector.getGherkinDocument(\n pickle.uri\n )\n const retries = retriesForPickle(pickle, this.options)\n const skip = this.options.dryRun || (this.options.failFast && !this.success)\n const runCommand: IWorkerCommand = {\n run: {\n retries,\n skip,\n elapsed: this.stopwatch.duration(),\n pickle,\n testCase,\n gherkinDocument,\n },\n }\n worker.state = WorkerState.running\n worker.process.send(runCommand)\n }\n}\n"]}