@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.
- package/README.md +2 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +7 -5
- package/lib/cli/load-configuration.d.ts +0 -21
- package/lib/cli/load-configuration.js +0 -124
- package/lib/cli/load-configuration.js.map +0 -1
- package/lib/cucumber/coordinator.d.ts +0 -15
- package/lib/cucumber/coordinator.js +0 -40
- package/lib/cucumber/coordinator.js.map +0 -1
- package/lib/cucumber/make-runtime.d.ts +0 -21
- package/lib/cucumber/make-runtime.js +0 -17
- package/lib/cucumber/make-runtime.js.map +0 -1
- package/lib/cucumber/managed-scenario-context.d.ts +0 -52
- package/lib/cucumber/managed-scenario-context.js +0 -149
- package/lib/cucumber/managed-scenario-context.js.map +0 -1
- package/lib/cucumber/message-collector.d.ts +0 -87
- package/lib/cucumber/message-collector.js +0 -280
- package/lib/cucumber/message-collector.js.map +0 -1
- package/lib/cucumber/parallel/adapter.d.ts +0 -46
- package/lib/cucumber/parallel/adapter.js +0 -156
- package/lib/cucumber/parallel/adapter.js.map +0 -1
- package/lib/cucumber/parallel/run-worker.d.ts +0 -1
- package/lib/cucumber/parallel/run-worker.js +0 -24
- package/lib/cucumber/parallel/run-worker.js.map +0 -1
- package/lib/cucumber/parallel/worker.d.ts +0 -26
- package/lib/cucumber/parallel/worker.js +0 -95
- package/lib/cucumber/parallel/worker.js.map +0 -1
- package/lib/cucumber/run-cucumber.d.ts +0 -16
- package/lib/cucumber/run-cucumber.js +0 -139
- package/lib/cucumber/run-cucumber.js.map +0 -1
- package/lib/cucumber/serial/adapter.d.ts +0 -12
- package/lib/cucumber/serial/adapter.js +0 -24
- package/lib/cucumber/serial/adapter.js.map +0 -1
- package/lib/cucumber/test-case-info.d.ts +0 -23
- package/lib/cucumber/test-case-info.js +0 -3
- package/lib/cucumber/test-case-info.js.map +0 -1
- package/lib/cucumber/test-case-runner.d.ts +0 -48
- package/lib/cucumber/test-case-runner.js +0 -359
- package/lib/cucumber/test-case-runner.js.map +0 -1
- package/lib/cucumber/utils.d.ts +0 -16
- package/lib/cucumber/utils.js +0 -78
- package/lib/cucumber/utils.js.map +0 -1
- package/lib/cucumber/worker.d.ts +0 -17
- package/lib/cucumber/worker.js +0 -57
- package/lib/cucumber/worker.js.map +0 -1
- package/lib/formatters/behave-json-formatter.d.ts +0 -49
- package/lib/formatters/behave-json-formatter.js +0 -85
- package/lib/formatters/behave-json-formatter.js.map +0 -1
- package/lib/formatters/junit-bamboo-formatter.d.ts +0 -17
- package/lib/formatters/junit-bamboo-formatter.js +0 -175
- package/lib/formatters/junit-bamboo-formatter.js.map +0 -1
- package/lib/formatters/tsflow-snippet-syntax.d.ts +0 -9
- package/lib/formatters/tsflow-snippet-syntax.js +0 -89
- package/lib/formatters/tsflow-snippet-syntax.js.map +0 -1
- package/lib/types/parallel.d.ts +0 -11
- package/lib/types/parallel.js +0 -3
- package/lib/types/parallel.js.map +0 -1
- package/lib/types/scenario-context.d.ts +0 -16
- package/lib/types/scenario-context.js +0 -18
- package/lib/types/scenario-context.js.map +0 -1
- package/lib/types/scenario-info.d.ts +0 -16
- package/lib/types/scenario-info.js +0 -23
- package/lib/types/scenario-info.js.map +0 -1
- package/lib/types/step-binding-flags.d.ts +0 -53
- package/lib/types/step-binding-flags.js +0 -59
- package/lib/types/step-binding-flags.js.map +0 -1
- package/lib/types/step-binding.d.ts +0 -60
- package/lib/types/step-binding.js +0 -18
- package/lib/types/step-binding.js.map +0 -1
- package/lib/types/types.d.ts +0 -22
- package/lib/types/types.js +0 -3
- 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
|