@lynxwall/cucumber-tsflow 6.5.7 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +20 -10
  2. package/api/index.d.ts +6 -0
  3. package/bin/cucumber-tsflow +3 -3
  4. package/bin/cucumber-tsflow.js +3 -0
  5. package/lib/api/index.d.ts +17 -0
  6. package/lib/api/index.js +30 -0
  7. package/lib/api/index.js.map +1 -0
  8. package/lib/api/load-configuration.d.ts +21 -0
  9. package/lib/api/load-configuration.js +127 -0
  10. package/lib/api/load-configuration.js.map +1 -0
  11. package/lib/api/load-support.d.ts +10 -0
  12. package/lib/api/load-support.js +48 -0
  13. package/lib/api/load-support.js.map +1 -0
  14. package/lib/api/run-cucumber.d.ts +16 -0
  15. package/lib/api/run-cucumber.js +151 -0
  16. package/lib/api/run-cucumber.js.map +1 -0
  17. package/lib/api/wrapper.mjs +6 -0
  18. package/lib/behave.js +18 -8
  19. package/lib/behave.js.map +1 -0
  20. package/lib/bindings/binding-context.d.ts +17 -0
  21. package/lib/bindings/binding-context.js +36 -0
  22. package/lib/bindings/binding-context.js.map +1 -0
  23. package/lib/{cucumber → bindings}/binding-decorator.d.ts +2 -2
  24. package/lib/bindings/binding-decorator.js +201 -0
  25. package/lib/bindings/binding-decorator.js.map +1 -0
  26. package/lib/{cucumber → bindings}/binding-registry.d.ts +8 -8
  27. package/lib/bindings/binding-registry.js +232 -0
  28. package/lib/bindings/binding-registry.js.map +1 -0
  29. package/lib/{cucumber → bindings}/hook-decorators.d.ts +6 -6
  30. package/lib/{cucumber → bindings}/hook-decorators.js +17 -15
  31. package/lib/bindings/hook-decorators.js.map +1 -0
  32. package/lib/{cucumber/step-definition-decorators.d.ts → bindings/step-decorators.d.ts} +3 -3
  33. package/lib/bindings/step-decorators.js +97 -0
  34. package/lib/bindings/step-decorators.js.map +1 -0
  35. package/lib/cli/argv-parser.js +3 -3
  36. package/lib/cli/argv-parser.js.map +1 -0
  37. package/lib/cli/index.d.ts +1 -2
  38. package/lib/cli/index.js +12 -40
  39. package/lib/cli/index.js.map +1 -0
  40. package/lib/cli/load-configuration.d.ts +2 -1
  41. package/lib/cli/load-configuration.js +12 -10
  42. package/lib/cli/load-configuration.js.map +1 -0
  43. package/lib/cli/run.js +5 -7
  44. package/lib/cli/run.js.map +1 -0
  45. package/lib/cucumber/coordinator.d.ts +15 -0
  46. package/lib/cucumber/coordinator.js +40 -0
  47. package/lib/cucumber/coordinator.js.map +1 -0
  48. package/lib/cucumber/make-runtime.d.ts +12 -16
  49. package/lib/cucumber/make-runtime.js +10 -33
  50. package/lib/cucumber/make-runtime.js.map +1 -0
  51. package/lib/cucumber/managed-scenario-context.d.ts +3 -3
  52. package/lib/cucumber/managed-scenario-context.js +24 -24
  53. package/lib/cucumber/managed-scenario-context.js.map +1 -0
  54. package/lib/cucumber/message-collector.d.ts +3 -0
  55. package/lib/cucumber/message-collector.js +38 -16
  56. package/lib/cucumber/message-collector.js.map +1 -0
  57. package/lib/cucumber/parallel/adapter.d.ts +46 -0
  58. package/lib/cucumber/parallel/adapter.js +156 -0
  59. package/lib/cucumber/parallel/adapter.js.map +1 -0
  60. package/lib/cucumber/parallel/run-worker.d.ts +1 -1
  61. package/lib/cucumber/parallel/run-worker.js +8 -16
  62. package/lib/cucumber/parallel/run-worker.js.map +1 -0
  63. package/lib/cucumber/parallel/worker.d.ts +10 -14
  64. package/lib/cucumber/parallel/worker.js +59 -68
  65. package/lib/cucumber/parallel/worker.js.map +1 -0
  66. package/lib/cucumber/run-cucumber.d.ts +5 -3
  67. package/lib/cucumber/run-cucumber.js +59 -38
  68. package/lib/cucumber/run-cucumber.js.map +1 -0
  69. package/lib/cucumber/serial/adapter.d.ts +12 -0
  70. package/lib/cucumber/serial/adapter.js +24 -0
  71. package/lib/cucumber/serial/adapter.js.map +1 -0
  72. package/lib/cucumber/test-case-info.js +1 -1
  73. package/lib/cucumber/test-case-info.js.map +1 -0
  74. package/lib/cucumber/test-case-runner.d.ts +2 -2
  75. package/lib/cucumber/test-case-runner.js +47 -19
  76. package/lib/cucumber/test-case-runner.js.map +1 -0
  77. package/lib/cucumber/utils.js +1 -1
  78. package/lib/cucumber/utils.js.map +1 -0
  79. package/lib/cucumber/worker.d.ts +17 -0
  80. package/lib/cucumber/worker.js +57 -0
  81. package/lib/cucumber/worker.js.map +1 -0
  82. package/lib/esnode.d.ts +1 -0
  83. package/lib/esnode.js +5 -7
  84. package/lib/esnode.js.map +1 -0
  85. package/lib/esvue.js +3 -6
  86. package/lib/esvue.js.map +1 -0
  87. package/lib/formatters/behave-json-formatter.js +18 -8
  88. package/lib/formatters/behave-json-formatter.js.map +1 -0
  89. package/lib/formatters/junit-bamboo-formatter.js +2 -2
  90. package/lib/formatters/junit-bamboo-formatter.js.map +1 -0
  91. package/lib/formatters/tsflow-snippet-syntax.js +2 -3
  92. package/lib/formatters/tsflow-snippet-syntax.js.map +1 -0
  93. package/lib/gherkin/configuration.d.ts +4 -4
  94. package/lib/gherkin/configuration.js +1 -1
  95. package/lib/gherkin/configuration.js.map +1 -0
  96. package/lib/gherkin/gherkin-feature.js +18 -8
  97. package/lib/gherkin/gherkin-feature.js.map +1 -0
  98. package/lib/gherkin/gherkin-manager.js +2 -2
  99. package/lib/gherkin/gherkin-manager.js.map +1 -0
  100. package/lib/gherkin/models.d.ts +1 -1
  101. package/lib/gherkin/models.js +1 -1
  102. package/lib/gherkin/models.js.map +1 -0
  103. package/lib/index.d.ts +6 -4
  104. package/lib/index.js +30 -18
  105. package/lib/index.js.map +1 -0
  106. package/lib/junitbamboo.js +18 -8
  107. package/lib/junitbamboo.js.map +1 -0
  108. package/lib/runtime/coordinator.d.ts +15 -0
  109. package/lib/runtime/coordinator.js +40 -0
  110. package/lib/runtime/coordinator.js.map +1 -0
  111. package/lib/runtime/make-runtime.d.ts +22 -0
  112. package/lib/runtime/make-runtime.js +17 -0
  113. package/lib/runtime/make-runtime.js.map +1 -0
  114. package/lib/runtime/managed-scenario-context.d.ts +52 -0
  115. package/lib/runtime/managed-scenario-context.js +149 -0
  116. package/lib/runtime/managed-scenario-context.js.map +1 -0
  117. package/lib/runtime/message-collector.d.ts +98 -0
  118. package/lib/runtime/message-collector.js +284 -0
  119. package/lib/runtime/message-collector.js.map +1 -0
  120. package/lib/runtime/parallel/adapter.d.ts +47 -0
  121. package/lib/runtime/parallel/adapter.js +159 -0
  122. package/lib/runtime/parallel/adapter.js.map +1 -0
  123. package/lib/runtime/parallel/run-worker.d.ts +1 -0
  124. package/lib/runtime/parallel/run-worker.js +24 -0
  125. package/lib/runtime/parallel/run-worker.js.map +1 -0
  126. package/lib/runtime/parallel/types.d.ts +13 -0
  127. package/lib/runtime/parallel/types.js +3 -0
  128. package/lib/runtime/parallel/types.js.map +1 -0
  129. package/lib/runtime/parallel/worker.d.ts +44 -0
  130. package/lib/runtime/parallel/worker.js +118 -0
  131. package/lib/runtime/parallel/worker.js.map +1 -0
  132. package/lib/runtime/serial/adapter.d.ts +12 -0
  133. package/lib/runtime/serial/adapter.js +24 -0
  134. package/lib/runtime/serial/adapter.js.map +1 -0
  135. package/lib/runtime/test-case-info.d.ts +23 -0
  136. package/lib/runtime/test-case-info.js +3 -0
  137. package/lib/runtime/test-case-info.js.map +1 -0
  138. package/lib/runtime/test-case-runner.d.ts +48 -0
  139. package/lib/runtime/test-case-runner.js +359 -0
  140. package/lib/runtime/test-case-runner.js.map +1 -0
  141. package/lib/runtime/utils.d.ts +16 -0
  142. package/lib/runtime/utils.js +78 -0
  143. package/lib/runtime/utils.js.map +1 -0
  144. package/lib/runtime/worker.d.ts +17 -0
  145. package/lib/runtime/worker.js +57 -0
  146. package/lib/runtime/worker.js.map +1 -0
  147. package/lib/snippet.js +20 -10
  148. package/lib/snippet.js.map +1 -0
  149. package/lib/transpilers/esbuild-transpiler.d.ts +1 -1
  150. package/lib/transpilers/esbuild-transpiler.js +1 -1
  151. package/lib/transpilers/esbuild-transpiler.js.map +1 -0
  152. package/lib/transpilers/esbuild.js +4 -4
  153. package/lib/transpilers/esbuild.js.map +1 -0
  154. package/lib/transpilers/vue-sfc/compiler.js +1 -1
  155. package/lib/transpilers/vue-sfc/compiler.js.map +1 -0
  156. package/lib/transpilers/vue-sfc/index.d.ts +4 -4
  157. package/lib/transpilers/vue-sfc/index.js +1 -2
  158. package/lib/transpilers/vue-sfc/index.js.map +1 -0
  159. package/lib/transpilers/vue-sfc/main.d.ts +1 -1
  160. package/lib/transpilers/vue-sfc/main.js +1 -1
  161. package/lib/transpilers/vue-sfc/main.js.map +1 -0
  162. package/lib/transpilers/vue-sfc/script.js +1 -2
  163. package/lib/transpilers/vue-sfc/script.js.map +1 -0
  164. package/lib/transpilers/vue-sfc/template.d.ts +1 -1
  165. package/lib/transpilers/vue-sfc/template.js +2 -3
  166. package/lib/transpilers/vue-sfc/template.js.map +1 -0
  167. package/lib/transpilers/vue-sfc/types.d.ts +2 -2
  168. package/lib/transpilers/vue-sfc/types.js +1 -1
  169. package/lib/transpilers/vue-sfc/types.js.map +1 -0
  170. package/lib/transpilers/vue-sfc/utils/descriptorCache.js +1 -1
  171. package/lib/transpilers/vue-sfc/utils/descriptorCache.js.map +1 -0
  172. package/lib/transpilers/vue-sfc/utils/error.js +1 -1
  173. package/lib/transpilers/vue-sfc/utils/error.js.map +1 -0
  174. package/lib/transpilers/vue-sfc/utils/query.js +1 -1
  175. package/lib/transpilers/vue-sfc/utils/query.js.map +1 -0
  176. package/lib/tsconfig.node.tsbuildinfo +1 -0
  177. package/lib/tsnode.d.ts +1 -0
  178. package/lib/tsnode.js +4 -6
  179. package/lib/tsnode.js.map +1 -0
  180. package/lib/tsvue.js +3 -6
  181. package/lib/tsvue.js.map +1 -0
  182. package/lib/types/parallel.d.ts +11 -0
  183. package/lib/types/parallel.js +3 -0
  184. package/lib/types/parallel.js.map +1 -0
  185. package/lib/types/scenario-context.js +1 -1
  186. package/lib/types/scenario-context.js.map +1 -0
  187. package/lib/types/scenario-info.js +1 -1
  188. package/lib/types/scenario-info.js.map +1 -0
  189. package/lib/types/step-binding-flags.js +1 -1
  190. package/lib/types/step-binding-flags.js.map +1 -0
  191. package/lib/types/step-binding.d.ts +30 -20
  192. package/lib/types/step-binding.js +1 -1
  193. package/lib/types/step-binding.js.map +1 -0
  194. package/lib/types/types.js +1 -1
  195. package/lib/types/types.js.map +1 -0
  196. package/lib/utils/helpers.js +1 -1
  197. package/lib/utils/helpers.js.map +1 -0
  198. package/lib/utils/logger.d.ts +2 -2
  199. package/lib/utils/logger.js +7 -26
  200. package/lib/utils/logger.js.map +1 -0
  201. package/lib/utils/our-callsite.js +18 -8
  202. package/lib/utils/our-callsite.js.map +1 -0
  203. package/lib/version.d.ts +1 -1
  204. package/lib/version.js +2 -2
  205. package/lib/version.js.map +1 -0
  206. package/lib/wrapper.mjs +21 -0
  207. package/package.json +68 -27
  208. package/lib/cucumber/binding-decorator.js +0 -181
  209. package/lib/cucumber/binding-registry.js +0 -231
  210. package/lib/cucumber/parallel/coordinator.d.ts +0 -79
  211. package/lib/cucumber/parallel/coordinator.js +0 -247
  212. package/lib/cucumber/runtime.d.ts +0 -40
  213. package/lib/cucumber/runtime.js +0 -85
  214. package/lib/cucumber/step-definition-decorators.js +0 -92
@@ -0,0 +1,284 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const messages = __importStar(require("@cucumber/messages"));
37
+ const value_checker_1 = require("@cucumber/cucumber/lib/value_checker");
38
+ const managed_scenario_context_1 = require("./managed-scenario-context");
39
+ const utils_1 = require("./utils");
40
+ const helpers_1 = require("../utils/helpers");
41
+ const messages_1 = require("@cucumber/messages");
42
+ /**
43
+ * Custom implementation of the EventDataCollector from cucumber.js
44
+ *
45
+ * This implements all of the functions from the original EventDataCollector along
46
+ * with new functions to support binding to tsFlow tests.
47
+ *
48
+ * By extending the original version we're also reducing the amount of data stored
49
+ * during test runs because the original MessageCollector was capturing the same
50
+ * pickle and testCase data that the EventDataCollector does.
51
+ */
52
+ class MessageCollector {
53
+ gherkinDocumentMap = {};
54
+ pickleMap = {};
55
+ testCaseMap = {};
56
+ testCaseAttemptDataMap = {};
57
+ undefinedParameterTypes = [];
58
+ testCaseRunningMap = {};
59
+ constructor(eventBroadcaster) {
60
+ eventBroadcaster.on('envelope', this.parseEnvelope.bind(this));
61
+ }
62
+ /**
63
+ * Reset this message collector for a new parallel test run.
64
+ * @param messageData Gerkin information from initial load
65
+ */
66
+ reset(messageData) {
67
+ this.gherkinDocumentMap = messageData.gherkinDocumentMap;
68
+ this.pickleMap = messageData.pickleMap;
69
+ this.testCaseMap = messageData.testCaseMap;
70
+ this.testCaseAttemptDataMap = {};
71
+ this.undefinedParameterTypes = [];
72
+ this.testCaseRunningMap = {};
73
+ }
74
+ /**
75
+ * Get Gerkin message data for parallel runs
76
+ * @returns Gerkin informaion loaded during startup
77
+ */
78
+ getMessageData() {
79
+ const data = {};
80
+ data.gherkinDocumentMap = this.gherkinDocumentMap;
81
+ data.pickleMap = this.pickleMap;
82
+ data.testCaseMap = this.testCaseMap;
83
+ return data;
84
+ }
85
+ /**
86
+ * Check for failures in a test run
87
+ * @returns true if there are failures in the last test case attempt
88
+ */
89
+ hasFailures() {
90
+ for (const caseKey in this.testCaseAttemptDataMap) {
91
+ const stepResults = this.testCaseAttemptDataMap[caseKey].stepResults;
92
+ for (const key in stepResults) {
93
+ if (stepResults[key].status === messages_1.TestStepResultStatus.FAILED) {
94
+ return true;
95
+ }
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+ getGherkinDocument(uri) {
101
+ return this.gherkinDocumentMap[uri];
102
+ }
103
+ getPickle(pickleId) {
104
+ return this.pickleMap[pickleId];
105
+ }
106
+ getTestCaseAttempts() {
107
+ return Object.keys(this.testCaseAttemptDataMap).map(testCaseStartedId => {
108
+ return this.getTestCaseAttempt(testCaseStartedId);
109
+ });
110
+ }
111
+ getTestCaseAttempt(testCaseStartedId) {
112
+ const testCaseAttemptData = this.testCaseAttemptDataMap[testCaseStartedId];
113
+ const testCase = this.testCaseMap[testCaseAttemptData.testCaseId];
114
+ const pickle = this.pickleMap[testCase.pickleId];
115
+ return {
116
+ gherkinDocument: this.gherkinDocumentMap[pickle.uri],
117
+ pickle,
118
+ testCase,
119
+ attempt: testCaseAttemptData.attempt,
120
+ willBeRetried: testCaseAttemptData.willBeRetried,
121
+ stepAttachments: testCaseAttemptData.stepAttachments,
122
+ stepResults: testCaseAttemptData.stepResults,
123
+ worstTestStepResult: testCaseAttemptData.worstTestStepResult
124
+ };
125
+ }
126
+ parseEnvelope(envelope) {
127
+ if ((0, value_checker_1.doesHaveValue)(envelope.gherkinDocument)) {
128
+ this.gherkinDocumentMap[envelope.gherkinDocument.uri] = envelope.gherkinDocument;
129
+ }
130
+ else if ((0, value_checker_1.doesHaveValue)(envelope.pickle)) {
131
+ this.pickleMap[envelope.pickle.id] = envelope.pickle;
132
+ }
133
+ else if ((0, value_checker_1.doesHaveValue)(envelope.undefinedParameterType)) {
134
+ this.undefinedParameterTypes.push(envelope.undefinedParameterType);
135
+ }
136
+ else if ((0, value_checker_1.doesHaveValue)(envelope.testCase)) {
137
+ this.testCaseMap[envelope.testCase.id] = envelope.testCase;
138
+ }
139
+ else if ((0, value_checker_1.doesHaveValue)(envelope.testCaseStarted)) {
140
+ this.initTestCaseAttempt(envelope.testCaseStarted);
141
+ this.startTestCase(envelope.testCaseStarted);
142
+ }
143
+ else if ((0, value_checker_1.doesHaveValue)(envelope.attachment)) {
144
+ this.storeAttachment(envelope.attachment);
145
+ }
146
+ else if ((0, value_checker_1.doesHaveValue)(envelope.testStepFinished)) {
147
+ this.storeTestStepResult(envelope.testStepFinished);
148
+ }
149
+ else if ((0, value_checker_1.doesHaveValue)(envelope.testCaseFinished)) {
150
+ this.storeTestCaseResult(envelope.testCaseFinished);
151
+ }
152
+ }
153
+ initTestCaseAttempt(testCaseStarted) {
154
+ this.testCaseAttemptDataMap[testCaseStarted.id] = {
155
+ attempt: testCaseStarted.attempt,
156
+ willBeRetried: false,
157
+ testCaseId: testCaseStarted.testCaseId,
158
+ stepAttachments: {},
159
+ stepResults: {},
160
+ worstTestStepResult: {
161
+ duration: { seconds: 0, nanos: 0 },
162
+ status: messages.TestStepResultStatus.UNKNOWN
163
+ }
164
+ };
165
+ }
166
+ storeAttachment(attachment) {
167
+ const { testCaseStartedId, testStepId } = attachment;
168
+ if (testCaseStartedId && testStepId) {
169
+ const { stepAttachments } = this.testCaseAttemptDataMap[testCaseStartedId];
170
+ if ((0, value_checker_1.doesNotHaveValue)(stepAttachments[testStepId])) {
171
+ stepAttachments[testStepId] = [];
172
+ }
173
+ stepAttachments[testStepId].push(attachment);
174
+ }
175
+ }
176
+ storeTestStepResult({ testCaseStartedId, testStepId, testStepResult }) {
177
+ this.testCaseAttemptDataMap[testCaseStartedId].stepResults[testStepId] = testStepResult;
178
+ }
179
+ storeTestCaseResult({ testCaseStartedId, willBeRetried }) {
180
+ const stepResults = Object.values(this.testCaseAttemptDataMap[testCaseStartedId].stepResults);
181
+ this.testCaseAttemptDataMap[testCaseStartedId].worstTestStepResult = messages.getWorstTestStepResult(stepResults);
182
+ this.testCaseAttemptDataMap[testCaseStartedId].willBeRetried = willBeRetried;
183
+ }
184
+ /**
185
+ * Gets the Pickle from hook parameters passed in from Cucumber
186
+ * to find a matching Pickle (scenario) and return the scenario Context
187
+ * @param hookParam
188
+ * @returns
189
+ */
190
+ getHookScenarioContext(hookParam) {
191
+ let scenarioContext;
192
+ if (hookParam) {
193
+ const pickle = hookParam.pickle;
194
+ const scenario = this.pickleMap[pickle.id];
195
+ if (scenario && scenario.scenarioContext) {
196
+ scenarioContext = scenario.scenarioContext;
197
+ }
198
+ }
199
+ return scenarioContext;
200
+ }
201
+ /**
202
+ * Uses StepPattern information to find a matching scenario
203
+ * and return the ScenarioContext
204
+ * @param stepBinding
205
+ * @returns
206
+ */
207
+ getStepScenarioContext(stepBinding) {
208
+ let scenarioContext;
209
+ for (const [, pickle] of Object.entries(this.pickleMap)) {
210
+ const scenario = pickle;
211
+ for (const step of scenario.steps) {
212
+ if ((0, utils_1.hasMatchingStep)(stepBinding.stepPattern.toString(), step.text)) {
213
+ // if we have tags on the step binding check to see if it matches one in the
214
+ // current scenario, which also includes tags associated with the feature
215
+ if (stepBinding.tags && this.stepHasTags(stepBinding.tags)) {
216
+ if (scenario.tags.length > 0 &&
217
+ (0, utils_1.hasMatchingTags)(stepBinding.tags, scenario.tags.map(x => x.name))) {
218
+ scenarioContext = scenario.scenarioContext;
219
+ }
220
+ }
221
+ else {
222
+ scenarioContext = scenario.scenarioContext;
223
+ }
224
+ }
225
+ if (scenarioContext)
226
+ break;
227
+ }
228
+ if (scenarioContext)
229
+ break;
230
+ }
231
+ return scenarioContext;
232
+ }
233
+ /**
234
+ * Called when a test case (scenario) starts. Intercepting
235
+ * this message to initialize a new ScenarioContext
236
+ * @param testCaseStarted
237
+ */
238
+ startTestCase(testCaseStarted) {
239
+ this.testCaseRunningMap[testCaseStarted.id] = testCaseStarted;
240
+ const scenario = this.getScenarioForTest(testCaseStarted.testCaseId);
241
+ if (scenario) {
242
+ const tags = scenario.tags.map(t => t.name);
243
+ scenario.scenarioContext = new managed_scenario_context_1.ManagedScenarioContext(scenario.name, tags);
244
+ }
245
+ }
246
+ /**
247
+ * Called when a test case (scenario) ends. Intercepting
248
+ * this message to dispose and clear the ScenarioContext
249
+ * @param testCaseFinished
250
+ */
251
+ async endTestCase(endTestCase) {
252
+ const testCase = this.testCaseRunningMap[endTestCase.testCaseStartedId];
253
+ if (testCase) {
254
+ const scenario = this.getScenarioForTest(testCase.testCaseId);
255
+ if (scenario && scenario.scenarioContext) {
256
+ await scenario.scenarioContext.dispose(endTestCase);
257
+ scenario.scenarioContext = undefined;
258
+ }
259
+ }
260
+ }
261
+ /**
262
+ * Uses the testCaleId passed in to find the associated Pickle (scenario)
263
+ * @param testCaseId
264
+ * @returns
265
+ */
266
+ getScenarioForTest(testCaseId) {
267
+ const testCase = this.testCaseMap[testCaseId];
268
+ if (testCase) {
269
+ return this.pickleMap[testCase.pickleId];
270
+ }
271
+ return undefined;
272
+ }
273
+ /**
274
+ * StepBinding tags are initialized with an astrick when empty.
275
+ * Need to make sure tags has a value and not an astrick
276
+ * @param tags
277
+ * @returns
278
+ */
279
+ stepHasTags(tags) {
280
+ return (0, helpers_1.hasStringValue)(tags) && !tags?.includes('*');
281
+ }
282
+ }
283
+ exports.default = MessageCollector;
284
+ //# sourceMappingURL=message-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-collector.js","sourceRoot":"","sources":["../../src/runtime/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 './parallel/types';\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\tprivate undefinedParameterTypes: messages.UndefinedParameterType[] = [];\r\n\tprivate testCaseRunningMap: Record<string, messages.TestCaseStarted> = {};\r\n\r\n\tconstructor(eventBroadcaster: EventEmitter) {\r\n\t\teventBroadcaster.on('envelope', this.parseEnvelope.bind(this));\r\n\t}\r\n\r\n\t/**\r\n\t * Reset this message collector for a new parallel test run.\r\n\t * @param messageData Gerkin information from initial load\r\n\t */\r\n\treset(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\tthis.testCaseAttemptDataMap = {};\r\n\t\tthis.undefinedParameterTypes = [];\r\n\t\tthis.testCaseRunningMap = {};\r\n\t}\r\n\r\n\t/**\r\n\t * Get Gerkin message data for parallel runs\r\n\t * @returns Gerkin informaion loaded during startup\r\n\t */\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/**\r\n\t * Check for failures in a test run\r\n\t * @returns true if there are failures in the last test case attempt\r\n\t */\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"]}
@@ -0,0 +1,47 @@
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, ISourcesCoordinates } 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 readonly coordinates;
31
+ private idleInterventions;
32
+ private failing;
33
+ private onFinish;
34
+ private todo;
35
+ private readonly inProgress;
36
+ private readonly workers;
37
+ constructor(environment: IRunEnvironment, logger: ILogger, eventBroadcaster: EventEmitter, options: IRunOptionsRuntime, supportCodeLibrary: SupportCodeLibrary, coordinates: ISourcesCoordinates);
38
+ parseWorkerMessage(worker: ManagedWorker, message: WorkerToCoordinatorEvent): void;
39
+ awakenWorkers(triggeringWorker: ManagedWorker): void;
40
+ startWorker(id: string, total: number): void;
41
+ onWorkerProcessClose(exitCode: number): void;
42
+ run(assembledTestCases: ReadonlyArray<AssembledTestCase>): Promise<boolean>;
43
+ nextWorkPlacement(): WorkPlacement | null;
44
+ placementAt(index: number): WorkPlacement;
45
+ giveWork(worker: ManagedWorker, force?: boolean): void;
46
+ }
47
+ export {};
@@ -0,0 +1,159 @@
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
+ coordinates;
17
+ idleInterventions = 0;
18
+ failing = false;
19
+ onFinish = success => {
20
+ return success;
21
+ };
22
+ todo = [];
23
+ inProgress = {};
24
+ workers = {};
25
+ constructor(environment, logger, eventBroadcaster, options, supportCodeLibrary, coordinates) {
26
+ this.environment = environment;
27
+ this.logger = logger;
28
+ this.eventBroadcaster = eventBroadcaster;
29
+ this.options = options;
30
+ this.supportCodeLibrary = supportCodeLibrary;
31
+ this.coordinates = coordinates;
32
+ }
33
+ parseWorkerMessage(worker, message) {
34
+ switch (message.type) {
35
+ case 'READY':
36
+ worker.state = 0 /* WorkerState.idle */;
37
+ this.awakenWorkers(worker);
38
+ break;
39
+ case 'ENVELOPE':
40
+ this.eventBroadcaster.emit('envelope', message.envelope);
41
+ break;
42
+ case 'FINISHED':
43
+ if (!message.success) {
44
+ this.failing = true;
45
+ }
46
+ delete this.inProgress[worker.id];
47
+ worker.state = 0 /* WorkerState.idle */;
48
+ this.awakenWorkers(worker);
49
+ break;
50
+ default:
51
+ throw new Error(`Unexpected message from worker: ${JSON.stringify(message)}`);
52
+ }
53
+ }
54
+ awakenWorkers(triggeringWorker) {
55
+ Object.values(this.workers).forEach(worker => {
56
+ if (worker.state === 0 /* WorkerState.idle */) {
57
+ this.giveWork(worker);
58
+ }
59
+ return worker.state !== 0 /* WorkerState.idle */;
60
+ });
61
+ if (Object.keys(this.inProgress).length == 0 && this.todo.length > 0) {
62
+ this.giveWork(triggeringWorker, true);
63
+ this.idleInterventions++;
64
+ }
65
+ }
66
+ startWorker(id, total) {
67
+ const workerProcess = (0, node_child_process_1.fork)(runWorkerPath, [], {
68
+ cwd: this.environment.cwd,
69
+ env: {
70
+ ...this.environment.env,
71
+ CUCUMBER_PARALLEL: 'true',
72
+ CUCUMBER_TOTAL_WORKERS: total.toString(),
73
+ CUCUMBER_WORKER_ID: id
74
+ },
75
+ stdio: ['inherit', 'inherit', 'inherit', 'ipc']
76
+ });
77
+ const worker = { state: 3 /* WorkerState.new */, process: workerProcess, id };
78
+ this.workers[id] = worker;
79
+ worker.process.on('message', (message) => {
80
+ this.parseWorkerMessage(worker, message);
81
+ });
82
+ worker.process.on('close', exitCode => {
83
+ worker.state = 1 /* WorkerState.closed */;
84
+ this.onWorkerProcessClose(exitCode);
85
+ });
86
+ const messageData = global.messageCollector.getMessageData();
87
+ messageData.coordinates = this.coordinates;
88
+ worker.process.send({
89
+ type: 'INITIALIZE',
90
+ supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,
91
+ supportCodeIds: {
92
+ stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(s => s.id),
93
+ beforeTestCaseHookDefinitionIds: this.supportCodeLibrary.beforeTestCaseHookDefinitions.map(h => h.id),
94
+ afterTestCaseHookDefinitionIds: this.supportCodeLibrary.afterTestCaseHookDefinitions.map(h => h.id)
95
+ },
96
+ options: this.options,
97
+ messageData: messageData
98
+ });
99
+ }
100
+ onWorkerProcessClose(exitCode) {
101
+ if (exitCode !== 0) {
102
+ this.failing = true;
103
+ }
104
+ if (Object.values(this.workers).every(x => x.state === 1 /* WorkerState.closed */)) {
105
+ this.onFinish(!this.failing);
106
+ }
107
+ }
108
+ async run(assembledTestCases) {
109
+ this.todo = Array.from(assembledTestCases);
110
+ return await new Promise(resolve => {
111
+ for (let i = 0; i < this.options.parallel; i++) {
112
+ this.startWorker(i.toString(), this.options.parallel);
113
+ }
114
+ this.onFinish = status => {
115
+ if (this.idleInterventions > 0) {
116
+ this.logger.warn(`WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`);
117
+ }
118
+ resolve(status);
119
+ };
120
+ });
121
+ }
122
+ nextWorkPlacement() {
123
+ for (let index = 0; index < this.todo.length; index++) {
124
+ const placement = this.placementAt(index);
125
+ if (this.supportCodeLibrary.parallelCanAssign(placement.item.pickle, Object.values(this.inProgress).map(({ pickle }) => pickle))) {
126
+ return placement;
127
+ }
128
+ }
129
+ return null;
130
+ }
131
+ placementAt(index) {
132
+ return {
133
+ index,
134
+ item: this.todo[index]
135
+ };
136
+ }
137
+ giveWork(worker, force = false) {
138
+ if (this.todo.length < 1) {
139
+ worker.state = 2 /* WorkerState.running */;
140
+ worker.process.send({ type: 'FINALIZE' });
141
+ return;
142
+ }
143
+ const workPlacement = force ? this.placementAt(0) : this.nextWorkPlacement();
144
+ if (workPlacement === null) {
145
+ return;
146
+ }
147
+ const { index: nextIndex, item } = workPlacement;
148
+ this.todo.splice(nextIndex, 1);
149
+ this.inProgress[worker.id] = item;
150
+ worker.state = 2 /* WorkerState.running */;
151
+ worker.process.send({
152
+ type: 'RUN',
153
+ assembledTestCase: item,
154
+ failing: this.failing
155
+ });
156
+ }
157
+ }
158
+ exports.ChildProcessAdapter = ChildProcessAdapter;
159
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/runtime/parallel/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChildProcess, fork } from 'node:child_process';\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, ISourcesCoordinates } from '@cucumber/cucumber/lib/api/index';\r\nimport { FinalizeCommand, RunCommand, WorkerToCoordinatorEvent } from '@cucumber/cucumber/lib/runtime/parallel/types';\r\nimport { InitializeTsflowCommand } from './types';\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\tprivate readonly coordinates: ISourcesCoordinates\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 messageData = global.messageCollector.getMessageData();\r\n\t\tmessageData.coordinates = this.coordinates;\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\tmessageData: messageData\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"]}
@@ -0,0 +1 @@
1
+ import 'polyfill-symbol-metadata';
@@ -0,0 +1,24 @@
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 }));
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/run-worker.ts"],"names":[],"mappings":";;AAAA,wEAAqE;AACrE,qCAA8C;AAC9C,oCAAkC;AAElC,SAAS,GAAG;IACX,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAE,KAAa,EAAE,OAAgB,EAAQ,EAAE;QACxE,IAAI,IAAA,6BAAa,EAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,2BAAkB,CAAC;QACrC,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAmB;QACnC,WAAW,EAAE,CAAC,OAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAK,CAAC,OAAO,CAAC;QACrD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI;KACJ,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAM,EAAQ,EAAE;QACtC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,2CAA2C,CAAC,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,GAAG,EAAE,CAAC","sourcesContent":["import { doesHaveValue } from '@cucumber/cucumber/lib/value_checker';\r\nimport { ChildProcessWorker } from './worker';\r\nimport 'polyfill-symbol-metadata';\r\n\r\nfunction run(): void {\r\n\tconst exit = (exitCode: number, error?: Error, message?: string): void => {\r\n\t\tif (doesHaveValue(error)) {\r\n\t\t\tconsole.error(new Error(message, { cause: error }));\r\n\t\t}\r\n\t\tprocess.exit(exitCode);\r\n\t};\r\n\tconst worker = new ChildProcessWorker({\r\n\t\tid: process.env.CUCUMBER_WORKER_ID!,\r\n\t\tsendMessage: (message: any) => process.send!(message),\r\n\t\tcwd: process.cwd(),\r\n\t\texit\r\n\t});\r\n\tprocess.on('message', (m: any): void => {\r\n\t\tworker.receiveMessage(m).catch((error: Error) => exit(1, error, 'Unexpected error on worker.receiveMessage'));\r\n\t});\r\n}\r\n\r\nrun();\r\n"]}
@@ -0,0 +1,13 @@
1
+ import * as messages from '@cucumber/messages';
2
+ import { FinalizeCommand, InitializeCommand, RunCommand } from '@cucumber/cucumber/lib/runtime/parallel/types';
3
+ import { ISourcesCoordinates } from '@cucumber/cucumber/api';
4
+ export interface IMessageData {
5
+ gherkinDocumentMap: Record<string, messages.GherkinDocument>;
6
+ pickleMap: Record<string, messages.Pickle>;
7
+ testCaseMap: Record<string, messages.TestCase>;
8
+ coordinates: ISourcesCoordinates;
9
+ }
10
+ export interface InitializeTsflowCommand extends InitializeCommand {
11
+ messageData: IMessageData;
12
+ }
13
+ export type CoordinatorToWorkerCommand = InitializeTsflowCommand | RunCommand | FinalizeCommand;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/runtime/parallel/types.ts"],"names":[],"mappings":"","sourcesContent":["import * as messages from '@cucumber/messages';\r\nimport { FinalizeCommand, InitializeCommand, RunCommand } from '@cucumber/cucumber/lib/runtime/parallel/types';\r\nimport { ISourcesCoordinates } from '@cucumber/cucumber/api';\r\n\r\nexport interface IMessageData {\r\n\tgherkinDocumentMap: Record<string, messages.GherkinDocument>;\r\n\tpickleMap: Record<string, messages.Pickle>;\r\n\ttestCaseMap: Record<string, messages.TestCase>;\r\n\tcoordinates: ISourcesCoordinates;\r\n}\r\n\r\nexport interface InitializeTsflowCommand extends InitializeCommand {\r\n\tmessageData: IMessageData;\r\n}\r\n\r\nexport type CoordinatorToWorkerCommand = InitializeTsflowCommand | RunCommand | FinalizeCommand;\r\n"]}