@lynxwall/cucumber-tsflow 7.1.0 → 7.1.2

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 (74) hide show
  1. package/README.md +2 -1
  2. package/lib/version.d.ts +1 -1
  3. package/lib/version.js +1 -1
  4. package/lib/version.js.map +1 -1
  5. package/package.json +7 -5
  6. package/lib/cli/load-configuration.d.ts +0 -21
  7. package/lib/cli/load-configuration.js +0 -124
  8. package/lib/cli/load-configuration.js.map +0 -1
  9. package/lib/cucumber/coordinator.d.ts +0 -15
  10. package/lib/cucumber/coordinator.js +0 -40
  11. package/lib/cucumber/coordinator.js.map +0 -1
  12. package/lib/cucumber/make-runtime.d.ts +0 -21
  13. package/lib/cucumber/make-runtime.js +0 -17
  14. package/lib/cucumber/make-runtime.js.map +0 -1
  15. package/lib/cucumber/managed-scenario-context.d.ts +0 -52
  16. package/lib/cucumber/managed-scenario-context.js +0 -149
  17. package/lib/cucumber/managed-scenario-context.js.map +0 -1
  18. package/lib/cucumber/message-collector.d.ts +0 -87
  19. package/lib/cucumber/message-collector.js +0 -280
  20. package/lib/cucumber/message-collector.js.map +0 -1
  21. package/lib/cucumber/parallel/adapter.d.ts +0 -46
  22. package/lib/cucumber/parallel/adapter.js +0 -156
  23. package/lib/cucumber/parallel/adapter.js.map +0 -1
  24. package/lib/cucumber/parallel/run-worker.d.ts +0 -1
  25. package/lib/cucumber/parallel/run-worker.js +0 -24
  26. package/lib/cucumber/parallel/run-worker.js.map +0 -1
  27. package/lib/cucumber/parallel/worker.d.ts +0 -26
  28. package/lib/cucumber/parallel/worker.js +0 -95
  29. package/lib/cucumber/parallel/worker.js.map +0 -1
  30. package/lib/cucumber/run-cucumber.d.ts +0 -16
  31. package/lib/cucumber/run-cucumber.js +0 -139
  32. package/lib/cucumber/run-cucumber.js.map +0 -1
  33. package/lib/cucumber/serial/adapter.d.ts +0 -12
  34. package/lib/cucumber/serial/adapter.js +0 -24
  35. package/lib/cucumber/serial/adapter.js.map +0 -1
  36. package/lib/cucumber/test-case-info.d.ts +0 -23
  37. package/lib/cucumber/test-case-info.js +0 -3
  38. package/lib/cucumber/test-case-info.js.map +0 -1
  39. package/lib/cucumber/test-case-runner.d.ts +0 -48
  40. package/lib/cucumber/test-case-runner.js +0 -359
  41. package/lib/cucumber/test-case-runner.js.map +0 -1
  42. package/lib/cucumber/utils.d.ts +0 -16
  43. package/lib/cucumber/utils.js +0 -78
  44. package/lib/cucumber/utils.js.map +0 -1
  45. package/lib/cucumber/worker.d.ts +0 -17
  46. package/lib/cucumber/worker.js +0 -57
  47. package/lib/cucumber/worker.js.map +0 -1
  48. package/lib/formatters/behave-json-formatter.d.ts +0 -49
  49. package/lib/formatters/behave-json-formatter.js +0 -85
  50. package/lib/formatters/behave-json-formatter.js.map +0 -1
  51. package/lib/formatters/junit-bamboo-formatter.d.ts +0 -17
  52. package/lib/formatters/junit-bamboo-formatter.js +0 -175
  53. package/lib/formatters/junit-bamboo-formatter.js.map +0 -1
  54. package/lib/formatters/tsflow-snippet-syntax.d.ts +0 -9
  55. package/lib/formatters/tsflow-snippet-syntax.js +0 -89
  56. package/lib/formatters/tsflow-snippet-syntax.js.map +0 -1
  57. package/lib/types/parallel.d.ts +0 -11
  58. package/lib/types/parallel.js +0 -3
  59. package/lib/types/parallel.js.map +0 -1
  60. package/lib/types/scenario-context.d.ts +0 -16
  61. package/lib/types/scenario-context.js +0 -18
  62. package/lib/types/scenario-context.js.map +0 -1
  63. package/lib/types/scenario-info.d.ts +0 -16
  64. package/lib/types/scenario-info.js +0 -23
  65. package/lib/types/scenario-info.js.map +0 -1
  66. package/lib/types/step-binding-flags.d.ts +0 -53
  67. package/lib/types/step-binding-flags.js +0 -59
  68. package/lib/types/step-binding-flags.js.map +0 -1
  69. package/lib/types/step-binding.d.ts +0 -60
  70. package/lib/types/step-binding.js +0 -18
  71. package/lib/types/step-binding.js.map +0 -1
  72. package/lib/types/types.d.ts +0 -22
  73. package/lib/types/types.js +0 -3
  74. package/lib/types/types.js.map +0 -1
@@ -1,87 +0,0 @@
1
- import * as messages from '@cucumber/messages';
2
- import { StepBinding } from '../types/step-binding';
3
- import { ManagedScenarioContext } from './managed-scenario-context';
4
- import { EndTestCaseInfo } from './test-case-info';
5
- import { IMessageData } from '../types/parallel';
6
- export interface ITestCaseAttempt {
7
- attempt: number;
8
- willBeRetried: boolean;
9
- gherkinDocument: messages.GherkinDocument;
10
- pickle: messages.Pickle;
11
- stepAttachments: Record<string, messages.Attachment[]>;
12
- stepResults: Record<string, messages.TestStepResult>;
13
- testCase: messages.TestCase;
14
- worstTestStepResult: messages.TestStepResult;
15
- }
16
- /**
17
- * Custom implementation of the EventDataCollector from cucumber.js
18
- *
19
- * This implements all of the functions from the original EventDataCollector along
20
- * with new functions to support binding to tsFlow tests.
21
- *
22
- * By extending the original version we're also reducing the amount of data stored
23
- * during test runs because the original MessageCollector was capturing the same
24
- * pickle and testCase data that the EventDataCollector does.
25
- */
26
- export default class MessageCollector {
27
- private gherkinDocumentMap;
28
- private pickleMap;
29
- private testCaseMap;
30
- private testCaseAttemptDataMap;
31
- readonly undefinedParameterTypes: messages.UndefinedParameterType[];
32
- private testCaseRunningMap;
33
- private collectorEvents;
34
- onTestCaseEnd(Handler: (testCaseFinished: messages.TestCaseFinished) => void): void;
35
- addMessageData(messageData: IMessageData): void;
36
- getMessageData(): IMessageData;
37
- addPickleAndTestCase(pickle: messages.Pickle, testCase: messages.TestCase): void;
38
- hasFailures(): boolean;
39
- getGherkinDocument(uri: string): messages.GherkinDocument;
40
- getPickle(pickleId: string): messages.Pickle;
41
- getTestCaseAttempts(): ITestCaseAttempt[];
42
- getTestCaseAttempt(testCaseStartedId: string): ITestCaseAttempt;
43
- parseEnvelope(envelope: messages.Envelope): void;
44
- private initTestCaseAttempt;
45
- storeAttachment(attachment: messages.Attachment): void;
46
- storeTestStepResult({ testCaseStartedId, testStepId, testStepResult }: messages.TestStepFinished): void;
47
- storeTestCaseResult({ testCaseStartedId, willBeRetried }: messages.TestCaseFinished): void;
48
- /**
49
- * Gets the Pickle from hook parameters passed in from Cucumber
50
- * to find a matching Pickle (scenario) and return the scenario Context
51
- * @param hookParam
52
- * @returns
53
- */
54
- getHookScenarioContext(hookParam: any): ManagedScenarioContext | undefined;
55
- /**
56
- * Uses StepPattern information to find a matching scenario
57
- * and return the ScenarioContext
58
- * @param stepBinding
59
- * @returns
60
- */
61
- getStepScenarioContext(stepBinding: StepBinding): ManagedScenarioContext | undefined;
62
- /**
63
- * Called when a test case (scenario) starts. Intercepting
64
- * this message to initialize a new ScenarioContext
65
- * @param testCaseStarted
66
- */
67
- private startTestCase;
68
- /**
69
- * Called when a test case (scenario) ends. Intercepting
70
- * this message to dispose and clear the ScenarioContext
71
- * @param testCaseFinished
72
- */
73
- endTestCase(endTestCase: EndTestCaseInfo): Promise<void>;
74
- /**
75
- * Uses the testCaleId passed in to find the associated Pickle (scenario)
76
- * @param testCaseId
77
- * @returns
78
- */
79
- private getScenarioForTest;
80
- /**
81
- * StepBinding tags are initialized with an astrick when empty.
82
- * Need to make sure tags has a value and not an astrick
83
- * @param tags
84
- * @returns
85
- */
86
- private stepHasTags;
87
- }
@@ -1,280 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- const messages = __importStar(require("@cucumber/messages"));
40
- const value_checker_1 = require("@cucumber/cucumber/lib/value_checker");
41
- const managed_scenario_context_1 = require("./managed-scenario-context");
42
- const utils_1 = require("./utils");
43
- const helpers_1 = require("../utils/helpers");
44
- const messages_1 = require("@cucumber/messages");
45
- const events_1 = __importDefault(require("events"));
46
- /**
47
- * Custom implementation of the EventDataCollector from cucumber.js
48
- *
49
- * This implements all of the functions from the original EventDataCollector along
50
- * with new functions to support binding to tsFlow tests.
51
- *
52
- * By extending the original version we're also reducing the amount of data stored
53
- * during test runs because the original MessageCollector was capturing the same
54
- * pickle and testCase data that the EventDataCollector does.
55
- */
56
- class MessageCollector {
57
- gherkinDocumentMap = {};
58
- pickleMap = {};
59
- testCaseMap = {};
60
- testCaseAttemptDataMap = {};
61
- undefinedParameterTypes = [];
62
- testCaseRunningMap = {};
63
- collectorEvents = new events_1.default();
64
- onTestCaseEnd(Handler) {
65
- this.collectorEvents.on('testCaseEnd', Handler);
66
- }
67
- addMessageData(messageData) {
68
- this.gherkinDocumentMap = messageData.gherkinDocumentMap;
69
- this.pickleMap = messageData.pickleMap;
70
- this.testCaseMap = messageData.testCaseMap;
71
- }
72
- getMessageData() {
73
- const data = {};
74
- data.gherkinDocumentMap = this.gherkinDocumentMap;
75
- data.pickleMap = this.pickleMap;
76
- data.testCaseMap = this.testCaseMap;
77
- return data;
78
- }
79
- // Used during parallel execution to add the current pickle and testCase
80
- // to a new Worker instance of the MessageCollector
81
- addPickleAndTestCase(pickle, testCase) {
82
- this.pickleMap[pickle.id] = pickle;
83
- this.testCaseMap[testCase.id] = testCase;
84
- }
85
- hasFailures() {
86
- for (const caseKey in this.testCaseAttemptDataMap) {
87
- const stepResults = this.testCaseAttemptDataMap[caseKey].stepResults;
88
- for (const key in stepResults) {
89
- if (stepResults[key].status === messages_1.TestStepResultStatus.FAILED) {
90
- return true;
91
- }
92
- }
93
- }
94
- return false;
95
- }
96
- getGherkinDocument(uri) {
97
- return this.gherkinDocumentMap[uri];
98
- }
99
- getPickle(pickleId) {
100
- return this.pickleMap[pickleId];
101
- }
102
- getTestCaseAttempts() {
103
- return Object.keys(this.testCaseAttemptDataMap).map(testCaseStartedId => {
104
- return this.getTestCaseAttempt(testCaseStartedId);
105
- });
106
- }
107
- getTestCaseAttempt(testCaseStartedId) {
108
- const testCaseAttemptData = this.testCaseAttemptDataMap[testCaseStartedId];
109
- const testCase = this.testCaseMap[testCaseAttemptData.testCaseId];
110
- const pickle = this.pickleMap[testCase.pickleId];
111
- return {
112
- gherkinDocument: this.gherkinDocumentMap[pickle.uri],
113
- pickle,
114
- testCase,
115
- attempt: testCaseAttemptData.attempt,
116
- willBeRetried: testCaseAttemptData.willBeRetried,
117
- stepAttachments: testCaseAttemptData.stepAttachments,
118
- stepResults: testCaseAttemptData.stepResults,
119
- worstTestStepResult: testCaseAttemptData.worstTestStepResult
120
- };
121
- }
122
- parseEnvelope(envelope) {
123
- if ((0, value_checker_1.doesHaveValue)(envelope.gherkinDocument)) {
124
- this.gherkinDocumentMap[envelope.gherkinDocument.uri] = envelope.gherkinDocument;
125
- }
126
- else if ((0, value_checker_1.doesHaveValue)(envelope.pickle)) {
127
- this.pickleMap[envelope.pickle.id] = envelope.pickle;
128
- }
129
- else if ((0, value_checker_1.doesHaveValue)(envelope.undefinedParameterType)) {
130
- this.undefinedParameterTypes.push(envelope.undefinedParameterType);
131
- }
132
- else if ((0, value_checker_1.doesHaveValue)(envelope.testCase)) {
133
- this.testCaseMap[envelope.testCase.id] = envelope.testCase;
134
- }
135
- else if ((0, value_checker_1.doesHaveValue)(envelope.testCaseStarted)) {
136
- this.initTestCaseAttempt(envelope.testCaseStarted);
137
- this.startTestCase(envelope.testCaseStarted);
138
- }
139
- else if ((0, value_checker_1.doesHaveValue)(envelope.attachment)) {
140
- this.storeAttachment(envelope.attachment);
141
- }
142
- else if ((0, value_checker_1.doesHaveValue)(envelope.testStepFinished)) {
143
- this.storeTestStepResult(envelope.testStepFinished);
144
- }
145
- else if ((0, value_checker_1.doesHaveValue)(envelope.testCaseFinished)) {
146
- this.storeTestCaseResult(envelope.testCaseFinished);
147
- }
148
- }
149
- initTestCaseAttempt(testCaseStarted) {
150
- this.testCaseAttemptDataMap[testCaseStarted.id] = {
151
- attempt: testCaseStarted.attempt,
152
- willBeRetried: false,
153
- testCaseId: testCaseStarted.testCaseId,
154
- stepAttachments: {},
155
- stepResults: {},
156
- worstTestStepResult: {
157
- duration: { seconds: 0, nanos: 0 },
158
- status: messages.TestStepResultStatus.UNKNOWN
159
- }
160
- };
161
- }
162
- storeAttachment(attachment) {
163
- const { testCaseStartedId, testStepId } = attachment;
164
- if (testCaseStartedId && testStepId) {
165
- const { stepAttachments } = this.testCaseAttemptDataMap[testCaseStartedId];
166
- if ((0, value_checker_1.doesNotHaveValue)(stepAttachments[testStepId])) {
167
- stepAttachments[testStepId] = [];
168
- }
169
- stepAttachments[testStepId].push(attachment);
170
- }
171
- }
172
- storeTestStepResult({ testCaseStartedId, testStepId, testStepResult }) {
173
- this.testCaseAttemptDataMap[testCaseStartedId].stepResults[testStepId] = testStepResult;
174
- }
175
- storeTestCaseResult({ testCaseStartedId, willBeRetried }) {
176
- const stepResults = Object.values(this.testCaseAttemptDataMap[testCaseStartedId].stepResults);
177
- this.testCaseAttemptDataMap[testCaseStartedId].worstTestStepResult = messages.getWorstTestStepResult(stepResults);
178
- this.testCaseAttemptDataMap[testCaseStartedId].willBeRetried = willBeRetried;
179
- }
180
- /**
181
- * Gets the Pickle from hook parameters passed in from Cucumber
182
- * to find a matching Pickle (scenario) and return the scenario Context
183
- * @param hookParam
184
- * @returns
185
- */
186
- getHookScenarioContext(hookParam) {
187
- let scenarioContext;
188
- if (hookParam) {
189
- const pickle = hookParam.pickle;
190
- const scenario = this.pickleMap[pickle.id];
191
- if (scenario && scenario.scenarioContext) {
192
- scenarioContext = scenario.scenarioContext;
193
- }
194
- }
195
- return scenarioContext;
196
- }
197
- /**
198
- * Uses StepPattern information to find a matching scenario
199
- * and return the ScenarioContext
200
- * @param stepBinding
201
- * @returns
202
- */
203
- getStepScenarioContext(stepBinding) {
204
- let scenarioContext;
205
- for (const [, pickle] of Object.entries(this.pickleMap)) {
206
- const scenario = pickle;
207
- for (const step of scenario.steps) {
208
- if ((0, utils_1.hasMatchingStep)(stepBinding.stepPattern.toString(), step.text)) {
209
- // if we have tags on the step binding check to see if it matches one in the
210
- // current scenario, which also includes tags associated with the feature
211
- if (stepBinding.tags && this.stepHasTags(stepBinding.tags)) {
212
- if (scenario.tags.length > 0 &&
213
- (0, utils_1.hasMatchingTags)(stepBinding.tags, scenario.tags.map(x => x.name))) {
214
- scenarioContext = scenario.scenarioContext;
215
- }
216
- }
217
- else {
218
- scenarioContext = scenario.scenarioContext;
219
- }
220
- }
221
- if (scenarioContext)
222
- break;
223
- }
224
- if (scenarioContext)
225
- break;
226
- }
227
- return scenarioContext;
228
- }
229
- /**
230
- * Called when a test case (scenario) starts. Intercepting
231
- * this message to initialize a new ScenarioContext
232
- * @param testCaseStarted
233
- */
234
- startTestCase(testCaseStarted) {
235
- this.testCaseRunningMap[testCaseStarted.id] = testCaseStarted;
236
- const scenario = this.getScenarioForTest(testCaseStarted.testCaseId);
237
- if (scenario) {
238
- const tags = scenario.tags.map(t => t.name);
239
- scenario.scenarioContext = new managed_scenario_context_1.ManagedScenarioContext(scenario.name, tags);
240
- }
241
- }
242
- /**
243
- * Called when a test case (scenario) ends. Intercepting
244
- * this message to dispose and clear the ScenarioContext
245
- * @param testCaseFinished
246
- */
247
- async endTestCase(endTestCase) {
248
- const testCase = this.testCaseRunningMap[endTestCase.testCaseStartedId];
249
- if (testCase) {
250
- const scenario = this.getScenarioForTest(testCase.testCaseId);
251
- if (scenario && scenario.scenarioContext) {
252
- await scenario.scenarioContext.dispose(endTestCase);
253
- scenario.scenarioContext = undefined;
254
- }
255
- }
256
- }
257
- /**
258
- * Uses the testCaleId passed in to find the associated Pickle (scenario)
259
- * @param testCaseId
260
- * @returns
261
- */
262
- getScenarioForTest(testCaseId) {
263
- const testCase = this.testCaseMap[testCaseId];
264
- if (testCase) {
265
- return this.pickleMap[testCase.pickleId];
266
- }
267
- return undefined;
268
- }
269
- /**
270
- * StepBinding tags are initialized with an astrick when empty.
271
- * Need to make sure tags has a value and not an astrick
272
- * @param tags
273
- * @returns
274
- */
275
- stepHasTags(tags) {
276
- return (0, helpers_1.hasStringValue)(tags) && !tags?.includes('*');
277
- }
278
- }
279
- exports.default = MessageCollector;
280
- //# sourceMappingURL=message-collector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message-collector.js","sourceRoot":"","sources":["../../src/cucumber/message-collector.ts"],"names":[],"mappings":"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","sourcesContent":["import * as messages from '@cucumber/messages';\r\nimport { doesHaveValue, doesNotHaveValue } from '@cucumber/cucumber/lib/value_checker';\r\nimport { StepBinding } from '../types/step-binding';\r\nimport { ManagedScenarioContext } from './managed-scenario-context';\r\nimport { hasMatchingStep, hasMatchingTags } from './utils';\r\nimport { hasStringValue } from '../utils/helpers';\r\nimport { TestStepResultStatus } from '@cucumber/messages';\r\nimport EventEmitter from 'events';\r\nimport { EndTestCaseInfo } from './test-case-info';\r\nimport { IMessageData } from '../types/parallel';\r\n\r\ninterface ITestCaseAttemptData {\r\n\tattempt: number;\r\n\twillBeRetried: boolean;\r\n\ttestCaseId: string;\r\n\tstepAttachments: Record<string, messages.Attachment[]>;\r\n\tstepResults: Record<string, messages.TestStepResult>;\r\n\tworstTestStepResult: messages.TestStepResult;\r\n}\r\n\r\nexport interface ITestCaseAttempt {\r\n\tattempt: number;\r\n\twillBeRetried: boolean;\r\n\tgherkinDocument: messages.GherkinDocument;\r\n\tpickle: messages.Pickle;\r\n\tstepAttachments: Record<string, messages.Attachment[]>;\r\n\tstepResults: Record<string, messages.TestStepResult>;\r\n\ttestCase: messages.TestCase;\r\n\tworstTestStepResult: messages.TestStepResult;\r\n}\r\n\r\ninterface IScenario extends messages.Pickle {\r\n\tscenarioContext: ManagedScenarioContext | undefined;\r\n}\r\n\r\n/**\r\n * Custom implementation of the EventDataCollector from cucumber.js\r\n *\r\n * This implements all of the functions from the original EventDataCollector along\r\n * with new functions to support binding to tsFlow tests.\r\n *\r\n * By extending the original version we're also reducing the amount of data stored\r\n * during test runs because the original MessageCollector was capturing the same\r\n * pickle and testCase data that the EventDataCollector does.\r\n */\r\nexport default class MessageCollector {\r\n\tprivate gherkinDocumentMap: Record<string, messages.GherkinDocument> = {};\r\n\tprivate pickleMap: Record<string, messages.Pickle> = {};\r\n\tprivate testCaseMap: Record<string, messages.TestCase> = {};\r\n\tprivate testCaseAttemptDataMap: Record<string, ITestCaseAttemptData> = {};\r\n\treadonly undefinedParameterTypes: messages.UndefinedParameterType[] = [];\r\n\tprivate testCaseRunningMap: Record<string, messages.TestCaseStarted> = {};\r\n\r\n\tprivate collectorEvents = new EventEmitter();\r\n\r\n\tonTestCaseEnd(Handler: (testCaseFinished: messages.TestCaseFinished) => void): void {\r\n\t\tthis.collectorEvents.on('testCaseEnd', Handler);\r\n\t}\r\n\r\n\taddMessageData(messageData: IMessageData): void {\r\n\t\tthis.gherkinDocumentMap = messageData.gherkinDocumentMap;\r\n\t\tthis.pickleMap = messageData.pickleMap;\r\n\t\tthis.testCaseMap = messageData.testCaseMap;\r\n\t}\r\n\r\n\tgetMessageData(): IMessageData {\r\n\t\tconst data = {} as IMessageData;\r\n\t\tdata.gherkinDocumentMap = this.gherkinDocumentMap;\r\n\t\tdata.pickleMap = this.pickleMap;\r\n\t\tdata.testCaseMap = this.testCaseMap;\r\n\r\n\t\treturn data;\r\n\t}\r\n\r\n\t// Used during parallel execution to add the current pickle and testCase\r\n\t// to a new Worker instance of the MessageCollector\r\n\taddPickleAndTestCase(pickle: messages.Pickle, testCase: messages.TestCase) {\r\n\t\tthis.pickleMap[pickle.id] = pickle;\r\n\t\tthis.testCaseMap[testCase.id] = testCase;\r\n\t}\r\n\r\n\thasFailures(): boolean {\r\n\t\tfor (const caseKey in this.testCaseAttemptDataMap) {\r\n\t\t\tconst stepResults = this.testCaseAttemptDataMap[caseKey].stepResults;\r\n\t\t\tfor (const key in stepResults) {\r\n\t\t\t\tif (stepResults[key].status === TestStepResultStatus.FAILED) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tgetGherkinDocument(uri: string): messages.GherkinDocument {\r\n\t\treturn this.gherkinDocumentMap[uri];\r\n\t}\r\n\r\n\tgetPickle(pickleId: string): messages.Pickle {\r\n\t\treturn this.pickleMap[pickleId];\r\n\t}\r\n\r\n\tgetTestCaseAttempts(): ITestCaseAttempt[] {\r\n\t\treturn Object.keys(this.testCaseAttemptDataMap).map(testCaseStartedId => {\r\n\t\t\treturn this.getTestCaseAttempt(testCaseStartedId);\r\n\t\t});\r\n\t}\r\n\r\n\tgetTestCaseAttempt(testCaseStartedId: string): ITestCaseAttempt {\r\n\t\tconst testCaseAttemptData = this.testCaseAttemptDataMap[testCaseStartedId];\r\n\t\tconst testCase = this.testCaseMap[testCaseAttemptData.testCaseId];\r\n\t\tconst pickle = this.pickleMap[testCase.pickleId];\r\n\t\treturn {\r\n\t\t\tgherkinDocument: this.gherkinDocumentMap[pickle.uri],\r\n\t\t\tpickle,\r\n\t\t\ttestCase,\r\n\t\t\tattempt: testCaseAttemptData.attempt,\r\n\t\t\twillBeRetried: testCaseAttemptData.willBeRetried,\r\n\t\t\tstepAttachments: testCaseAttemptData.stepAttachments,\r\n\t\t\tstepResults: testCaseAttemptData.stepResults,\r\n\t\t\tworstTestStepResult: testCaseAttemptData.worstTestStepResult\r\n\t\t};\r\n\t}\r\n\r\n\tparseEnvelope(envelope: messages.Envelope): void {\r\n\t\tif (doesHaveValue(envelope.gherkinDocument)) {\r\n\t\t\tthis.gherkinDocumentMap[envelope.gherkinDocument.uri] = envelope.gherkinDocument;\r\n\t\t} else if (doesHaveValue(envelope.pickle)) {\r\n\t\t\tthis.pickleMap[envelope.pickle.id] = envelope.pickle;\r\n\t\t} else if (doesHaveValue(envelope.undefinedParameterType)) {\r\n\t\t\tthis.undefinedParameterTypes.push(envelope.undefinedParameterType);\r\n\t\t} else if (doesHaveValue(envelope.testCase)) {\r\n\t\t\tthis.testCaseMap[envelope.testCase.id] = envelope.testCase;\r\n\t\t} else if (doesHaveValue(envelope.testCaseStarted)) {\r\n\t\t\tthis.initTestCaseAttempt(envelope.testCaseStarted);\r\n\t\t\tthis.startTestCase(envelope.testCaseStarted);\r\n\t\t} else if (doesHaveValue(envelope.attachment)) {\r\n\t\t\tthis.storeAttachment(envelope.attachment);\r\n\t\t} else if (doesHaveValue(envelope.testStepFinished)) {\r\n\t\t\tthis.storeTestStepResult(envelope.testStepFinished);\r\n\t\t} else if (doesHaveValue(envelope.testCaseFinished)) {\r\n\t\t\tthis.storeTestCaseResult(envelope.testCaseFinished);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate initTestCaseAttempt(testCaseStarted: messages.TestCaseStarted): void {\r\n\t\tthis.testCaseAttemptDataMap[testCaseStarted.id] = {\r\n\t\t\tattempt: testCaseStarted.attempt,\r\n\t\t\twillBeRetried: false,\r\n\t\t\ttestCaseId: testCaseStarted.testCaseId,\r\n\t\t\tstepAttachments: {},\r\n\t\t\tstepResults: {},\r\n\t\t\tworstTestStepResult: {\r\n\t\t\t\tduration: { seconds: 0, nanos: 0 },\r\n\t\t\t\tstatus: messages.TestStepResultStatus.UNKNOWN\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tstoreAttachment(attachment: messages.Attachment): void {\r\n\t\tconst { testCaseStartedId, testStepId } = attachment;\r\n\t\tif (testCaseStartedId && testStepId) {\r\n\t\t\tconst { stepAttachments } = this.testCaseAttemptDataMap[testCaseStartedId];\r\n\t\t\tif (doesNotHaveValue(stepAttachments[testStepId])) {\r\n\t\t\t\tstepAttachments[testStepId] = [];\r\n\t\t\t}\r\n\t\t\tstepAttachments[testStepId].push(attachment);\r\n\t\t}\r\n\t}\r\n\r\n\tstoreTestStepResult({ testCaseStartedId, testStepId, testStepResult }: messages.TestStepFinished): void {\r\n\t\tthis.testCaseAttemptDataMap[testCaseStartedId].stepResults[testStepId] = testStepResult;\r\n\t}\r\n\r\n\tstoreTestCaseResult({ testCaseStartedId, willBeRetried }: messages.TestCaseFinished): void {\r\n\t\tconst stepResults = Object.values(this.testCaseAttemptDataMap[testCaseStartedId].stepResults);\r\n\t\tthis.testCaseAttemptDataMap[testCaseStartedId].worstTestStepResult = messages.getWorstTestStepResult(stepResults);\r\n\t\tthis.testCaseAttemptDataMap[testCaseStartedId].willBeRetried = willBeRetried;\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the Pickle from hook parameters passed in from Cucumber\r\n\t * to find a matching Pickle (scenario) and return the scenario Context\r\n\t * @param hookParam\r\n\t * @returns\r\n\t */\r\n\tgetHookScenarioContext(hookParam: any): ManagedScenarioContext | undefined {\r\n\t\tlet scenarioContext: ManagedScenarioContext | undefined;\r\n\r\n\t\tif (hookParam) {\r\n\t\t\tconst pickle = hookParam.pickle;\r\n\t\t\tconst scenario = this.pickleMap[pickle.id] as IScenario;\r\n\t\t\tif (scenario && scenario.scenarioContext) {\r\n\t\t\t\tscenarioContext = scenario.scenarioContext;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn scenarioContext;\r\n\t}\r\n\r\n\t/**\r\n\t * Uses StepPattern information to find a matching scenario\r\n\t * and return the ScenarioContext\r\n\t * @param stepBinding\r\n\t * @returns\r\n\t */\r\n\tgetStepScenarioContext(stepBinding: StepBinding): ManagedScenarioContext | undefined {\r\n\t\tlet scenarioContext: ManagedScenarioContext | undefined;\r\n\t\tfor (const [, pickle] of Object.entries(this.pickleMap)) {\r\n\t\t\tconst scenario = pickle as IScenario;\r\n\t\t\tfor (const step of scenario.steps) {\r\n\t\t\t\tif (hasMatchingStep(stepBinding.stepPattern.toString(), step.text)) {\r\n\t\t\t\t\t// if we have tags on the step binding check to see if it matches one in the\r\n\t\t\t\t\t// current scenario, which also includes tags associated with the feature\r\n\t\t\t\t\tif (stepBinding.tags && this.stepHasTags(stepBinding.tags)) {\r\n\t\t\t\t\t\tif (\r\n\t\t\t\t\t\t\tscenario.tags.length > 0 &&\r\n\t\t\t\t\t\t\thasMatchingTags(\r\n\t\t\t\t\t\t\t\tstepBinding.tags,\r\n\t\t\t\t\t\t\t\tscenario.tags.map(x => x.name)\r\n\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t) {\r\n\t\t\t\t\t\t\tscenarioContext = scenario.scenarioContext;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tscenarioContext = scenario.scenarioContext;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (scenarioContext) break;\r\n\t\t\t}\r\n\t\t\tif (scenarioContext) break;\r\n\t\t}\r\n\t\treturn scenarioContext;\r\n\t}\r\n\t/**\r\n\t * Called when a test case (scenario) starts. Intercepting\r\n\t * this message to initialize a new ScenarioContext\r\n\t * @param testCaseStarted\r\n\t */\r\n\tprivate startTestCase(testCaseStarted: messages.TestCaseStarted): void {\r\n\t\tthis.testCaseRunningMap[testCaseStarted.id] = testCaseStarted;\r\n\t\tconst scenario = this.getScenarioForTest(testCaseStarted.testCaseId);\r\n\t\tif (scenario) {\r\n\t\t\tconst tags = scenario.tags.map(t => t.name);\r\n\t\t\tscenario.scenarioContext = new ManagedScenarioContext(scenario.name, tags);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Called when a test case (scenario) ends. Intercepting\r\n\t * this message to dispose and clear the ScenarioContext\r\n\t * @param testCaseFinished\r\n\t */\r\n\tpublic async endTestCase(endTestCase: EndTestCaseInfo): Promise<void> {\r\n\t\tconst testCase = this.testCaseRunningMap[endTestCase.testCaseStartedId];\r\n\t\tif (testCase) {\r\n\t\t\tconst scenario = this.getScenarioForTest(testCase.testCaseId);\r\n\t\t\tif (scenario && scenario.scenarioContext) {\r\n\t\t\t\tawait scenario.scenarioContext.dispose(endTestCase);\r\n\t\t\t\tscenario.scenarioContext = undefined;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Uses the testCaleId passed in to find the associated Pickle (scenario)\r\n\t * @param testCaseId\r\n\t * @returns\r\n\t */\r\n\tprivate getScenarioForTest(testCaseId: string): IScenario | undefined {\r\n\t\tconst testCase = this.testCaseMap[testCaseId];\r\n\t\tif (testCase) {\r\n\t\t\treturn this.pickleMap[testCase.pickleId] as IScenario;\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * StepBinding tags are initialized with an astrick when empty.\r\n\t * Need to make sure tags has a value and not an astrick\r\n\t * @param tags\r\n\t * @returns\r\n\t */\r\n\tprivate stepHasTags(tags: string): boolean {\r\n\t\treturn hasStringValue(tags) && !tags?.includes('*');\r\n\t}\r\n}\r\n"]}
@@ -1,46 +0,0 @@
1
- import { ChildProcess } from 'node:child_process';
2
- import { EventEmitter } from 'node:events';
3
- import { SupportCodeLibrary } from '@cucumber/cucumber/lib/support_code_library_builder/types';
4
- import { AssembledTestCase } from '@cucumber/cucumber/lib/assemble/index';
5
- import { ILogger, IRunEnvironment } from '@cucumber/cucumber/lib/environment/index';
6
- import { RuntimeAdapter } from '@cucumber/cucumber/lib/runtime/types';
7
- import { IRunOptionsRuntime } from '@cucumber/cucumber/lib/api/index';
8
- import { WorkerToCoordinatorEvent } from '@cucumber/cucumber/lib/runtime/parallel/types';
9
- declare const enum WorkerState {
10
- 'idle' = 0,
11
- 'closed' = 1,
12
- 'running' = 2,
13
- 'new' = 3
14
- }
15
- interface ManagedWorker {
16
- state: WorkerState;
17
- process: ChildProcess;
18
- id: string;
19
- }
20
- interface WorkPlacement {
21
- index: number;
22
- item: AssembledTestCase;
23
- }
24
- export declare class ChildProcessAdapter implements RuntimeAdapter {
25
- private readonly environment;
26
- private readonly logger;
27
- private readonly eventBroadcaster;
28
- private readonly options;
29
- private readonly supportCodeLibrary;
30
- private idleInterventions;
31
- private failing;
32
- private onFinish;
33
- private todo;
34
- private readonly inProgress;
35
- private readonly workers;
36
- constructor(environment: IRunEnvironment, logger: ILogger, eventBroadcaster: EventEmitter, options: IRunOptionsRuntime, supportCodeLibrary: SupportCodeLibrary);
37
- parseWorkerMessage(worker: ManagedWorker, message: WorkerToCoordinatorEvent): void;
38
- awakenWorkers(triggeringWorker: ManagedWorker): void;
39
- startWorker(id: string, total: number): void;
40
- onWorkerProcessClose(exitCode: number): void;
41
- run(assembledTestCases: ReadonlyArray<AssembledTestCase>): Promise<boolean>;
42
- nextWorkPlacement(): WorkPlacement | null;
43
- placementAt(index: number): WorkPlacement;
44
- giveWork(worker: ManagedWorker, force?: boolean): void;
45
- }
46
- export {};
@@ -1,156 +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.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');
10
- class ChildProcessAdapter {
11
- environment;
12
- logger;
13
- eventBroadcaster;
14
- options;
15
- supportCodeLibrary;
16
- idleInterventions = 0;
17
- failing = false;
18
- onFinish = success => {
19
- return success;
20
- };
21
- todo = [];
22
- inProgress = {};
23
- workers = {};
24
- constructor(environment, logger, eventBroadcaster, options, supportCodeLibrary) {
25
- this.environment = environment;
26
- this.logger = logger;
27
- this.eventBroadcaster = eventBroadcaster;
28
- this.options = options;
29
- this.supportCodeLibrary = supportCodeLibrary;
30
- }
31
- parseWorkerMessage(worker, message) {
32
- switch (message.type) {
33
- case 'READY':
34
- worker.state = 0 /* WorkerState.idle */;
35
- this.awakenWorkers(worker);
36
- break;
37
- case 'ENVELOPE':
38
- this.eventBroadcaster.emit('envelope', message.envelope);
39
- break;
40
- case 'FINISHED':
41
- if (!message.success) {
42
- this.failing = true;
43
- }
44
- delete this.inProgress[worker.id];
45
- worker.state = 0 /* WorkerState.idle */;
46
- this.awakenWorkers(worker);
47
- break;
48
- default:
49
- throw new Error(`Unexpected message from worker: ${JSON.stringify(message)}`);
50
- }
51
- }
52
- awakenWorkers(triggeringWorker) {
53
- Object.values(this.workers).forEach(worker => {
54
- if (worker.state === 0 /* WorkerState.idle */) {
55
- this.giveWork(worker);
56
- }
57
- return worker.state !== 0 /* WorkerState.idle */;
58
- });
59
- if (Object.keys(this.inProgress).length == 0 && this.todo.length > 0) {
60
- this.giveWork(triggeringWorker, true);
61
- this.idleInterventions++;
62
- }
63
- }
64
- startWorker(id, total) {
65
- const workerProcess = (0, node_child_process_1.fork)(runWorkerPath, [], {
66
- cwd: this.environment.cwd,
67
- env: {
68
- ...this.environment.env,
69
- CUCUMBER_PARALLEL: 'true',
70
- CUCUMBER_TOTAL_WORKERS: total.toString(),
71
- CUCUMBER_WORKER_ID: id
72
- },
73
- stdio: ['inherit', 'inherit', 'inherit', 'ipc']
74
- });
75
- const worker = { state: 3 /* WorkerState.new */, process: workerProcess, id };
76
- this.workers[id] = worker;
77
- worker.process.on('message', (message) => {
78
- this.parseWorkerMessage(worker, message);
79
- });
80
- worker.process.on('close', exitCode => {
81
- worker.state = 1 /* WorkerState.closed */;
82
- this.onWorkerProcessClose(exitCode);
83
- });
84
- const collector = global.messageCollector;
85
- worker.process.send({
86
- type: 'INITIALIZE',
87
- supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,
88
- supportCodeIds: {
89
- stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(s => s.id),
90
- beforeTestCaseHookDefinitionIds: this.supportCodeLibrary.beforeTestCaseHookDefinitions.map(h => h.id),
91
- afterTestCaseHookDefinitionIds: this.supportCodeLibrary.afterTestCaseHookDefinitions.map(h => h.id)
92
- },
93
- options: this.options,
94
- collectorData: collector.getMessageData()
95
- });
96
- }
97
- onWorkerProcessClose(exitCode) {
98
- if (exitCode !== 0) {
99
- this.failing = true;
100
- }
101
- if (Object.values(this.workers).every(x => x.state === 1 /* WorkerState.closed */)) {
102
- this.onFinish(!this.failing);
103
- }
104
- }
105
- async run(assembledTestCases) {
106
- this.todo = Array.from(assembledTestCases);
107
- return await new Promise(resolve => {
108
- for (let i = 0; i < this.options.parallel; i++) {
109
- this.startWorker(i.toString(), this.options.parallel);
110
- }
111
- this.onFinish = status => {
112
- if (this.idleInterventions > 0) {
113
- this.logger.warn(`WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`);
114
- }
115
- resolve(status);
116
- };
117
- });
118
- }
119
- nextWorkPlacement() {
120
- for (let index = 0; index < this.todo.length; index++) {
121
- const placement = this.placementAt(index);
122
- if (this.supportCodeLibrary.parallelCanAssign(placement.item.pickle, Object.values(this.inProgress).map(({ pickle }) => pickle))) {
123
- return placement;
124
- }
125
- }
126
- return null;
127
- }
128
- placementAt(index) {
129
- return {
130
- index,
131
- item: this.todo[index]
132
- };
133
- }
134
- giveWork(worker, force = false) {
135
- if (this.todo.length < 1) {
136
- worker.state = 2 /* WorkerState.running */;
137
- worker.process.send({ type: 'FINALIZE' });
138
- return;
139
- }
140
- const workPlacement = force ? this.placementAt(0) : this.nextWorkPlacement();
141
- if (workPlacement === null) {
142
- return;
143
- }
144
- const { index: nextIndex, item } = workPlacement;
145
- this.todo.splice(nextIndex, 1);
146
- this.inProgress[worker.id] = item;
147
- worker.state = 2 /* WorkerState.running */;
148
- worker.process.send({
149
- type: 'RUN',
150
- assembledTestCase: item,
151
- failing: this.failing
152
- });
153
- }
154
- }
155
- exports.ChildProcessAdapter = ChildProcessAdapter;
156
- //# sourceMappingURL=adapter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/cucumber/parallel/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChildProcess, fork } from 'node:child_process';\r\nimport path from 'node:path';\r\nimport { EventEmitter } from 'node:events';\r\nimport { SupportCodeLibrary } from '@cucumber/cucumber/lib/support_code_library_builder/types';\r\nimport { AssembledTestCase } from '@cucumber/cucumber/lib/assemble/index';\r\nimport { ILogger, IRunEnvironment } from '@cucumber/cucumber/lib/environment/index';\r\nimport { RuntimeAdapter } from '@cucumber/cucumber/lib/runtime/types';\r\nimport { IRunOptionsRuntime } from '@cucumber/cucumber/lib/api/index';\r\nimport { FinalizeCommand, RunCommand, WorkerToCoordinatorEvent } from '@cucumber/cucumber/lib/runtime/parallel/types';\r\nimport { InitializeTsflowCommand } from '../../types/parallel';\r\n\r\nconst runWorkerPath = path.resolve(__dirname, 'run-worker');\r\n\r\nconst enum WorkerState {\r\n\t'idle',\r\n\t'closed',\r\n\t'running',\r\n\t'new'\r\n}\r\n\r\ninterface ManagedWorker {\r\n\tstate: WorkerState;\r\n\tprocess: ChildProcess;\r\n\tid: string;\r\n}\r\n\r\ninterface WorkPlacement {\r\n\tindex: number;\r\n\titem: AssembledTestCase;\r\n}\r\n\r\nexport class ChildProcessAdapter implements RuntimeAdapter {\r\n\tprivate idleInterventions: number = 0;\r\n\tprivate failing: boolean = false;\r\n\tprivate onFinish: (success: boolean) => void = success => {\r\n\t\treturn success;\r\n\t};\r\n\tprivate todo: Array<AssembledTestCase> = [];\r\n\tprivate readonly inProgress: Record<string, AssembledTestCase> = {};\r\n\tprivate readonly workers: Record<string, ManagedWorker> = {};\r\n\r\n\tconstructor(\r\n\t\tprivate readonly environment: IRunEnvironment,\r\n\t\tprivate readonly logger: ILogger,\r\n\t\tprivate readonly eventBroadcaster: EventEmitter,\r\n\t\tprivate readonly options: IRunOptionsRuntime,\r\n\t\tprivate readonly supportCodeLibrary: SupportCodeLibrary\r\n\t) {}\r\n\r\n\tparseWorkerMessage(worker: ManagedWorker, message: WorkerToCoordinatorEvent): void {\r\n\t\tswitch (message.type) {\r\n\t\t\tcase 'READY':\r\n\t\t\t\tworker.state = WorkerState.idle;\r\n\t\t\t\tthis.awakenWorkers(worker);\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'ENVELOPE':\r\n\t\t\t\tthis.eventBroadcaster.emit('envelope', message.envelope);\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'FINISHED':\r\n\t\t\t\tif (!message.success) {\r\n\t\t\t\t\tthis.failing = true;\r\n\t\t\t\t}\r\n\t\t\t\tdelete this.inProgress[worker.id];\r\n\t\t\t\tworker.state = WorkerState.idle;\r\n\t\t\t\tthis.awakenWorkers(worker);\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tthrow new Error(`Unexpected message from worker: ${JSON.stringify(message)}`);\r\n\t\t}\r\n\t}\r\n\r\n\tawakenWorkers(triggeringWorker: ManagedWorker): void {\r\n\t\tObject.values(this.workers).forEach(worker => {\r\n\t\t\tif (worker.state === WorkerState.idle) {\r\n\t\t\t\tthis.giveWork(worker);\r\n\t\t\t}\r\n\t\t\treturn worker.state !== WorkerState.idle;\r\n\t\t});\r\n\r\n\t\tif (Object.keys(this.inProgress).length == 0 && this.todo.length > 0) {\r\n\t\t\tthis.giveWork(triggeringWorker, true);\r\n\t\t\tthis.idleInterventions++;\r\n\t\t}\r\n\t}\r\n\r\n\tstartWorker(id: string, total: number): void {\r\n\t\tconst workerProcess = fork(runWorkerPath, [], {\r\n\t\t\tcwd: this.environment.cwd,\r\n\t\t\tenv: {\r\n\t\t\t\t...this.environment.env,\r\n\t\t\t\tCUCUMBER_PARALLEL: 'true',\r\n\t\t\t\tCUCUMBER_TOTAL_WORKERS: total.toString(),\r\n\t\t\t\tCUCUMBER_WORKER_ID: id\r\n\t\t\t},\r\n\t\t\tstdio: ['inherit', 'inherit', 'inherit', 'ipc']\r\n\t\t});\r\n\t\tconst worker = { state: WorkerState.new, process: workerProcess, id };\r\n\t\tthis.workers[id] = worker;\r\n\t\tworker.process.on('message', (message: WorkerToCoordinatorEvent) => {\r\n\t\t\tthis.parseWorkerMessage(worker, message);\r\n\t\t});\r\n\t\tworker.process.on('close', exitCode => {\r\n\t\t\tworker.state = WorkerState.closed;\r\n\t\t\tthis.onWorkerProcessClose(exitCode!);\r\n\t\t});\r\n\r\n\t\tconst collector = global.messageCollector;\r\n\r\n\t\tworker.process.send({\r\n\t\t\ttype: 'INITIALIZE',\r\n\t\t\tsupportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,\r\n\t\t\tsupportCodeIds: {\r\n\t\t\t\tstepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(s => s.id),\r\n\t\t\t\tbeforeTestCaseHookDefinitionIds: this.supportCodeLibrary.beforeTestCaseHookDefinitions.map(h => h.id),\r\n\t\t\t\tafterTestCaseHookDefinitionIds: this.supportCodeLibrary.afterTestCaseHookDefinitions.map(h => h.id)\r\n\t\t\t},\r\n\t\t\toptions: this.options,\r\n\t\t\tcollectorData: collector.getMessageData()\r\n\t\t} satisfies InitializeTsflowCommand);\r\n\t}\r\n\r\n\tonWorkerProcessClose(exitCode: number): void {\r\n\t\tif (exitCode !== 0) {\r\n\t\t\tthis.failing = true;\r\n\t\t}\r\n\r\n\t\tif (Object.values(this.workers).every(x => x.state === WorkerState.closed)) {\r\n\t\t\tthis.onFinish(!this.failing);\r\n\t\t}\r\n\t}\r\n\r\n\tasync run(assembledTestCases: ReadonlyArray<AssembledTestCase>): Promise<boolean> {\r\n\t\tthis.todo = Array.from(assembledTestCases);\r\n\t\treturn await new Promise<boolean>(resolve => {\r\n\t\t\tfor (let i = 0; i < this.options.parallel; i++) {\r\n\t\t\t\tthis.startWorker(i.toString(), this.options.parallel);\r\n\t\t\t}\r\n\t\t\tthis.onFinish = status => {\r\n\t\t\t\tif (this.idleInterventions > 0) {\r\n\t\t\t\t\tthis.logger.warn(\r\n\t\t\t\t\t\t`WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tresolve(status);\r\n\t\t\t};\r\n\t\t});\r\n\t}\r\n\r\n\tnextWorkPlacement(): WorkPlacement | null {\r\n\t\tfor (let index = 0; index < this.todo.length; index++) {\r\n\t\t\tconst placement = this.placementAt(index);\r\n\t\t\tif (\r\n\t\t\t\tthis.supportCodeLibrary.parallelCanAssign(\r\n\t\t\t\t\tplacement.item.pickle,\r\n\t\t\t\t\tObject.values(this.inProgress).map(({ pickle }) => pickle)\r\n\t\t\t\t)\r\n\t\t\t) {\r\n\t\t\t\treturn placement;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tplacementAt(index: number): WorkPlacement {\r\n\t\treturn {\r\n\t\t\tindex,\r\n\t\t\titem: this.todo[index]\r\n\t\t};\r\n\t}\r\n\r\n\tgiveWork(worker: ManagedWorker, force: boolean = false): void {\r\n\t\tif (this.todo.length < 1) {\r\n\t\t\tworker.state = WorkerState.running;\r\n\t\t\tworker.process.send({ type: 'FINALIZE' } satisfies FinalizeCommand);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst workPlacement = force ? this.placementAt(0) : this.nextWorkPlacement();\r\n\r\n\t\tif (workPlacement === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst { index: nextIndex, item } = workPlacement;\r\n\r\n\t\tthis.todo.splice(nextIndex, 1);\r\n\t\tthis.inProgress[worker.id] = item;\r\n\t\tworker.state = WorkerState.running;\r\n\t\tworker.process.send({\r\n\t\t\ttype: 'RUN',\r\n\t\t\tassembledTestCase: item,\r\n\t\t\tfailing: this.failing\r\n\t\t} satisfies RunCommand);\r\n\t}\r\n}\r\n"]}
@@ -1 +0,0 @@
1
- import 'polyfill-symbol-metadata';
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const value_checker_1 = require("@cucumber/cucumber/lib/value_checker");
4
- const worker_1 = require("./worker");
5
- require("polyfill-symbol-metadata");
6
- function run() {
7
- const exit = (exitCode, error, message) => {
8
- if ((0, value_checker_1.doesHaveValue)(error)) {
9
- console.error(new Error(message, { cause: error })); // eslint-disable-line no-console
10
- }
11
- process.exit(exitCode);
12
- };
13
- const worker = new worker_1.ChildProcessWorker({
14
- id: process.env.CUCUMBER_WORKER_ID,
15
- sendMessage: (message) => process.send(message),
16
- cwd: process.cwd(),
17
- exit
18
- });
19
- process.on('message', (m) => {
20
- worker.receiveMessage(m).catch((error) => exit(1, error, 'Unexpected error on worker.receiveMessage'));
21
- });
22
- }
23
- run();
24
- //# sourceMappingURL=run-worker.js.map