@cucumber/cucumber 10.5.1 → 10.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/convert_configuration.js +1 -0
- package/lib/api/convert_configuration.js.map +1 -1
- package/lib/api/formatters.d.ts +3 -1
- package/lib/api/formatters.js +36 -45
- package/lib/api/formatters.js.map +1 -1
- package/lib/api/load_support.js +9 -2
- package/lib/api/load_support.js.map +1 -1
- package/lib/api/plugins.js +3 -3
- package/lib/api/plugins.js.map +1 -1
- package/lib/api/run_cucumber.js +10 -6
- package/lib/api/run_cucumber.js.map +1 -1
- package/lib/api/runtime.d.ts +1 -4
- package/lib/api/runtime.js +1 -4
- package/lib/api/runtime.js.map +1 -1
- package/lib/api/support.d.ts +2 -1
- package/lib/api/support.js +7 -1
- package/lib/api/support.js.map +1 -1
- package/lib/api/types.d.ts +7 -3
- package/lib/api/types.js.map +1 -1
- package/lib/configuration/argv_parser.js +3 -2
- package/lib/configuration/argv_parser.js.map +1 -1
- package/lib/configuration/default_configuration.js +1 -0
- package/lib/configuration/default_configuration.js.map +1 -1
- package/lib/configuration/merge_configurations.js +1 -0
- package/lib/configuration/merge_configurations.js.map +1 -1
- package/lib/configuration/types.d.ts +5 -0
- package/lib/configuration/types.js.map +1 -1
- package/lib/configuration/validate_configuration.js +3 -0
- package/lib/configuration/validate_configuration.js.map +1 -1
- package/lib/formatter/builder.d.ts +1 -1
- package/lib/formatter/builder.js +6 -13
- package/lib/formatter/builder.js.map +1 -1
- package/lib/formatter/builtin/html.d.ts +6 -0
- package/lib/formatter/builtin/html.js +25 -0
- package/lib/formatter/builtin/html.js.map +1 -0
- package/lib/formatter/builtin/index.d.ts +3 -0
- package/lib/formatter/builtin/index.js +33 -0
- package/lib/formatter/builtin/index.js.map +1 -0
- package/lib/formatter/builtin/message.d.ts +6 -0
- package/lib/formatter/builtin/message.js +10 -0
- package/lib/formatter/builtin/message.js.map +1 -0
- package/lib/formatter/create_stream.d.ts +4 -0
- package/lib/formatter/create_stream.js +28 -0
- package/lib/formatter/create_stream.js.map +1 -0
- package/lib/formatter/find_class_or_plugin.d.ts +1 -0
- package/lib/formatter/find_class_or_plugin.js +25 -0
- package/lib/formatter/find_class_or_plugin.js.map +1 -0
- package/lib/formatter/helpers/formatters.d.ts +0 -1
- package/lib/formatter/helpers/formatters.js +0 -12
- package/lib/formatter/helpers/formatters.js.map +1 -1
- package/lib/formatter/import_code.d.ts +1 -0
- package/lib/formatter/import_code.js +27 -0
- package/lib/formatter/import_code.js.map +1 -0
- package/lib/formatter/index.d.ts +2 -0
- package/lib/formatter/index.js.map +1 -1
- package/lib/formatter/resolve_implementation.d.ts +2 -0
- package/lib/formatter/resolve_implementation.js +24 -0
- package/lib/formatter/resolve_implementation.js.map +1 -0
- package/lib/paths/paths.js +1 -0
- package/lib/paths/paths.js.map +1 -1
- package/lib/plugin/plugin_manager.d.ts +3 -2
- package/lib/plugin/plugin_manager.js +12 -2
- package/lib/plugin/plugin_manager.js.map +1 -1
- package/lib/plugin/types.d.ts +11 -0
- package/lib/plugin/types.js.map +1 -1
- package/lib/runtime/parallel/command_types.d.ts +4 -5
- package/lib/runtime/parallel/command_types.js.map +1 -1
- package/lib/runtime/parallel/coordinator.d.ts +2 -8
- package/lib/runtime/parallel/coordinator.js +10 -42
- package/lib/runtime/parallel/coordinator.js.map +1 -1
- package/lib/runtime/parallel/worker.d.ts +1 -1
- package/lib/runtime/parallel/worker.js +12 -15
- package/lib/runtime/parallel/worker.js.map +1 -1
- package/lib/runtime/test_case_runner.d.ts +3 -1
- package/lib/runtime/test_case_runner.js +6 -1
- package/lib/runtime/test_case_runner.js.map +1 -1
- package/lib/support_code_library_builder/index.js +1 -0
- package/lib/support_code_library_builder/index.js.map +1 -1
- package/lib/support_code_library_builder/types.d.ts +1 -0
- package/lib/support_code_library_builder/types.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +3 -2
- package/lib/formatter/html_formatter.d.ts +0 -7
- package/lib/formatter/html_formatter.js +0 -31
- package/lib/formatter/html_formatter.js.map +0 -1
- package/lib/formatter/message_formatter.d.ts +0 -5
- package/lib/formatter/message_formatter.js +0 -15
- package/lib/formatter/message_formatter.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve_implementation.js","sourceRoot":"","sources":["../../src/formatter/resolve_implementation.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA+B;AAC/B,+CAA0C;AAC1C,iEAA0D;AAGnD,KAAK,UAAU,qBAAqB,CACzC,SAAiB,EACjB,GAAW;IAEX,IAAI,iBAAO,CAAC,SAAS,CAAC,EAAE;QACtB,OAAO,iBAAO,CAAC,SAAS,CAAC,CAAA;KAC1B;SAAM;QACL,MAAM,QAAQ,GAAG,MAAM,IAAA,wBAAU,EAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACjD,MAAM,KAAK,GAAG,IAAA,wCAAiB,EAAC,QAAQ,CAAC,CAAA;QACzC,IAAI,CAAC,KAAK,EAAE;YACV,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,mCAAmC,CAAC,CAAA;SACjE;QACD,OAAO,KAAK,CAAA;KACb;AACH,CAAC;AAdD,sDAcC","sourcesContent":["import builtin from './builtin'\nimport { importCode } from './import_code'\nimport { findClassOrPlugin } from './find_class_or_plugin'\nimport { FormatterImplementation } from './index'\n\nexport async function resolveImplementation(\n specifier: string,\n cwd: string\n): Promise<FormatterImplementation> {\n if (builtin[specifier]) {\n return builtin[specifier]\n } else {\n const imported = await importCode(specifier, cwd)\n const found = findClassOrPlugin(imported)\n if (!found) {\n throw new Error(`${specifier} does not export a function/class`)\n }\n return found\n }\n}\n"]}
|
package/lib/paths/paths.js
CHANGED
|
@@ -11,6 +11,7 @@ async function resolvePaths(logger, cwd, sources, support = {
|
|
|
11
11
|
requireModules: [],
|
|
12
12
|
requirePaths: [],
|
|
13
13
|
importPaths: [],
|
|
14
|
+
loaders: [],
|
|
14
15
|
}) {
|
|
15
16
|
const unexpandedSourcePaths = await getUnexpandedSourcePaths(cwd, sources.paths);
|
|
16
17
|
const sourcePaths = await expandSourcePaths(cwd, unexpandedSourcePaths);
|
package/lib/paths/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths/paths.ts"],"names":[],"mappings":";;;;;;AAAA,0DAA4B;AAC5B,+BAA2B;AAC3B,+CAAsB;AAKf,KAAK,UAAU,YAAY,CAChC,MAAe,EACf,GAAW,EACX,OAA2C,EAC3C,UAAmC;IACjC,cAAc,EAAE,EAAE;IAClB,YAAY,EAAE,EAAE;IAChB,WAAW,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths/paths.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path'\nimport { glob } from 'glob'\nimport fs from 'mz/fs'\nimport { ILogger } from '../logger'\nimport { ISourcesCoordinates, ISupportCodeCoordinates } from '../api'\nimport { IResolvedPaths } from './types'\n\nexport async function resolvePaths(\n logger: ILogger,\n cwd: string,\n sources: Pick<ISourcesCoordinates, 'paths'>,\n support: ISupportCodeCoordinates = {\n requireModules: [],\n requirePaths: [],\n importPaths: [],\n loaders: [],\n }\n): Promise<IResolvedPaths> {\n const unexpandedSourcePaths = await getUnexpandedSourcePaths(\n cwd,\n sources.paths\n )\n const sourcePaths: string[] = await expandSourcePaths(\n cwd,\n unexpandedSourcePaths\n )\n logger.debug('Found source files based on configuration:', sourcePaths)\n const { requirePaths, importPaths } = await deriveSupportPaths(\n cwd,\n sourcePaths,\n support.requirePaths,\n support.importPaths\n )\n logger.debug(\n 'Found support files to load via `require` based on configuration:',\n requirePaths\n )\n logger.debug(\n 'Found support files to load via `import` based on configuration:',\n importPaths\n )\n return {\n unexpandedSourcePaths: unexpandedSourcePaths,\n sourcePaths: sourcePaths,\n requirePaths,\n importPaths,\n }\n}\n\nasync function expandPaths(\n cwd: string,\n unexpandedPaths: string[],\n defaultExtension: string\n): Promise<string[]> {\n const expandedPaths = await Promise.all(\n unexpandedPaths.map(async (unexpandedPath) => {\n const matches = await glob(unexpandedPath, {\n absolute: true,\n windowsPathsNoEscape: true,\n cwd,\n })\n const expanded = await Promise.all(\n matches.map(async (match) => {\n if (path.extname(match) === '') {\n return glob(`${match}/**/*${defaultExtension}`, {\n windowsPathsNoEscape: true,\n })\n }\n return [match]\n })\n )\n return expanded.flat().sort()\n })\n )\n const normalized = expandedPaths.flat().map((x) => path.normalize(x))\n return [...new Set(normalized)]\n}\n\nasync function getUnexpandedSourcePaths(\n cwd: string,\n args: string[]\n): Promise<string[]> {\n if (args.length > 0) {\n const nestedFeaturePaths = await Promise.all(\n args.map(async (arg) => {\n const filename = path.basename(arg)\n if (filename[0] === '@') {\n const filePath = path.join(cwd, arg)\n const content = await fs.readFile(filePath, 'utf8')\n return content.split('\\n').map((x) => x.trim())\n }\n return [arg]\n })\n )\n const featurePaths = nestedFeaturePaths.flat()\n if (featurePaths.length > 0) {\n return featurePaths.filter((x) => x !== '')\n }\n }\n return ['features/**/*.{feature,feature.md}']\n}\n\nfunction getFeatureDirectoryPaths(\n cwd: string,\n featurePaths: string[]\n): string[] {\n const featureDirs = featurePaths.map((featurePath) => {\n let featureDir = path.dirname(featurePath)\n let childDir: string\n let parentDir = featureDir\n while (childDir !== parentDir) {\n childDir = parentDir\n parentDir = path.dirname(childDir)\n if (path.basename(parentDir) === 'features') {\n featureDir = parentDir\n break\n }\n }\n return path.relative(cwd, featureDir)\n })\n return [...new Set(featureDirs)]\n}\n\nasync function expandSourcePaths(\n cwd: string,\n featurePaths: string[]\n): Promise<string[]> {\n featurePaths = featurePaths.map((p) => p.replace(/(:\\d+)*$/g, '')) // Strip line numbers\n return await expandPaths(cwd, featurePaths, '.feature')\n}\n\nasync function deriveSupportPaths(\n cwd: string,\n featurePaths: string[],\n unexpandedRequirePaths: string[],\n unexpandedImportPaths: string[]\n): Promise<{\n requirePaths: string[]\n importPaths: string[]\n}> {\n if (\n unexpandedRequirePaths.length === 0 &&\n unexpandedImportPaths.length === 0\n ) {\n const defaultPaths = getFeatureDirectoryPaths(cwd, featurePaths)\n const importPaths = await expandPaths(cwd, defaultPaths, '.@(js|cjs|mjs)')\n return { requirePaths: [], importPaths }\n }\n const requirePaths =\n unexpandedRequirePaths.length > 0\n ? await expandPaths(cwd, unexpandedRequirePaths, '.js')\n : []\n const importPaths =\n unexpandedImportPaths.length > 0\n ? await expandPaths(cwd, unexpandedImportPaths, '.@(js|cjs|mjs)')\n : []\n return { requirePaths, importPaths }\n}\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { IRunEnvironment } from '../api';
|
|
2
2
|
import { ILogger } from '../logger';
|
|
3
|
-
import { InternalPlugin, CoordinatorPluginEventValues, CoordinatorPluginEventKey, CoordinatorPluginTransformEventKey, Operation } from './types';
|
|
3
|
+
import { InternalPlugin, CoordinatorPluginEventValues, CoordinatorPluginEventKey, CoordinatorPluginTransformEventKey, Operation, FormatterPlugin } from './types';
|
|
4
4
|
export declare class PluginManager {
|
|
5
5
|
private handlers;
|
|
6
6
|
private cleanupFns;
|
|
7
7
|
private register;
|
|
8
|
-
|
|
8
|
+
initFormatter<OptionsType>(plugin: FormatterPlugin<OptionsType>, options: OptionsType, write: (buffer: string | Uint8Array) => void): Promise<void>;
|
|
9
|
+
initCoordinator<OptionsType>(operation: Operation, plugin: InternalPlugin<OptionsType>, options: OptionsType, logger: ILogger, environment: Required<IRunEnvironment>): Promise<void>;
|
|
9
10
|
emit<K extends CoordinatorPluginEventKey>(event: K, value: CoordinatorPluginEventValues[K]): void;
|
|
10
11
|
transform<K extends CoordinatorPluginTransformEventKey>(event: K, value: CoordinatorPluginEventValues[K]): Promise<CoordinatorPluginEventValues[K]>;
|
|
11
12
|
cleanup(): Promise<void>;
|
|
@@ -10,9 +10,19 @@ class PluginManager {
|
|
|
10
10
|
};
|
|
11
11
|
cleanupFns = [];
|
|
12
12
|
async register(event, handler) {
|
|
13
|
-
this.handlers[event]
|
|
13
|
+
this.handlers[event]?.push(handler);
|
|
14
14
|
}
|
|
15
|
-
async
|
|
15
|
+
async initFormatter(plugin, options, write) {
|
|
16
|
+
const cleanupFn = await plugin.formatter({
|
|
17
|
+
on: (key, handler) => this.register(key, handler),
|
|
18
|
+
options,
|
|
19
|
+
write,
|
|
20
|
+
});
|
|
21
|
+
if (typeof cleanupFn === 'function') {
|
|
22
|
+
this.cleanupFns.push(cleanupFn);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async initCoordinator(operation, plugin, options, logger, environment) {
|
|
16
26
|
const cleanupFn = await plugin.coordinator({
|
|
17
27
|
operation,
|
|
18
28
|
on: this.register.bind(this),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin_manager.js","sourceRoot":"","sources":["../../src/plugin/plugin_manager.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"plugin_manager.js","sourceRoot":"","sources":["../../src/plugin/plugin_manager.ts"],"names":[],"mappings":";;;AAiBA,MAAa,aAAa;IAChB,QAAQ,GAAoB;QAClC,OAAO,EAAE,EAAE;QACX,eAAe,EAAE,EAAE;QACnB,gBAAgB,EAAE,EAAE;QACpB,eAAe,EAAE,EAAE;KACpB,CAAA;IACO,UAAU,GAAoB,EAAE,CAAA;IAEhC,KAAK,CAAC,QAAQ,CACpB,KAAQ,EACR,OAAyC;QAEzC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IACrC,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,MAAoC,EACpC,OAAoB,EACpB,KAA4C;QAE5C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC;YACvC,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;YACjD,OAAO;YACP,KAAK;SACN,CAAC,CAAA;QACF,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE;YACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;SAChC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,SAAoB,EACpB,MAAmC,EACnC,OAAoB,EACpB,MAAe,EACf,WAAsC;QAEtC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACzC,SAAS;YACT,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAC5B,OAAO;YACP,MAAM;YACN,WAAW;SACZ,CAAC,CAAA;QACF,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE;YACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;SAChC;IACH,CAAC;IAED,IAAI,CACF,KAAQ,EACR,KAAsC;QAEtC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAC3D,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAQ,EACR,KAAsC;QAEtC,IAAI,WAAW,GAAG,KAAK,CAAA;QACvB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;YAC3C,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE;gBACnC,WAAW,GAAG,QAAQ,CAAA;aACvB;SACF;QACD,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE;YACvC,MAAM,SAAS,EAAE,CAAA;SAClB;IACH,CAAC;CACF;AA5ED,sCA4EC","sourcesContent":["import { IRunEnvironment } from '../api'\nimport { ILogger } from '../logger'\nimport {\n CoordinatorPluginEventHandler,\n InternalPlugin,\n PluginCleanup,\n CoordinatorPluginEventValues,\n CoordinatorPluginEventKey,\n CoordinatorPluginTransformEventKey,\n Operation,\n FormatterPlugin,\n} from './types'\n\ntype HandlerRegistry = {\n [K in CoordinatorPluginEventKey]: Array<CoordinatorPluginEventHandler<K>>\n}\n\nexport class PluginManager {\n private handlers: HandlerRegistry = {\n message: [],\n 'paths:resolve': [],\n 'pickles:filter': [],\n 'pickles:order': [],\n }\n private cleanupFns: PluginCleanup[] = []\n\n private async register<K extends CoordinatorPluginEventKey>(\n event: K,\n handler: CoordinatorPluginEventHandler<K>\n ) {\n this.handlers[event]?.push(handler)\n }\n\n async initFormatter<OptionsType>(\n plugin: FormatterPlugin<OptionsType>,\n options: OptionsType,\n write: (buffer: string | Uint8Array) => void\n ) {\n const cleanupFn = await plugin.formatter({\n on: (key, handler) => this.register(key, handler),\n options,\n write,\n })\n if (typeof cleanupFn === 'function') {\n this.cleanupFns.push(cleanupFn)\n }\n }\n\n async initCoordinator<OptionsType>(\n operation: Operation,\n plugin: InternalPlugin<OptionsType>,\n options: OptionsType,\n logger: ILogger,\n environment: Required<IRunEnvironment>\n ) {\n const cleanupFn = await plugin.coordinator({\n operation,\n on: this.register.bind(this),\n options,\n logger,\n environment,\n })\n if (typeof cleanupFn === 'function') {\n this.cleanupFns.push(cleanupFn)\n }\n }\n\n emit<K extends CoordinatorPluginEventKey>(\n event: K,\n value: CoordinatorPluginEventValues[K]\n ): void {\n this.handlers[event].forEach((handler) => handler(value))\n }\n\n async transform<K extends CoordinatorPluginTransformEventKey>(\n event: K,\n value: CoordinatorPluginEventValues[K]\n ): Promise<CoordinatorPluginEventValues[K]> {\n let transformed = value\n for (const handler of this.handlers[event]) {\n const returned = await handler(transformed)\n if (typeof returned !== 'undefined') {\n transformed = returned\n }\n }\n return transformed\n }\n\n async cleanup(): Promise<void> {\n for (const cleanupFn of this.cleanupFns) {\n await cleanupFn()\n }\n }\n}\n"]}
|
package/lib/plugin/types.d.ts
CHANGED
|
@@ -36,3 +36,14 @@ export interface InternalPlugin<OptionsType = any> {
|
|
|
36
36
|
type: 'plugin';
|
|
37
37
|
coordinator: CoordinatorPluginFunction<OptionsType>;
|
|
38
38
|
}
|
|
39
|
+
export interface FormatterPluginContext<OptionsType> {
|
|
40
|
+
on: (key: 'message', handler: (value: Envelope) => void) => void;
|
|
41
|
+
options: OptionsType;
|
|
42
|
+
write: (buffer: string | Uint8Array) => void;
|
|
43
|
+
}
|
|
44
|
+
export type FormatterPluginFunction<OptionsType> = (context: FormatterPluginContext<OptionsType>) => Promisable<PluginCleanup | void>;
|
|
45
|
+
export interface FormatterPlugin<OptionsType = any> {
|
|
46
|
+
type: 'formatter';
|
|
47
|
+
formatter: FormatterPluginFunction<OptionsType>;
|
|
48
|
+
documentation: string;
|
|
49
|
+
}
|
package/lib/plugin/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"","sourcesContent":["import { Envelope } from '@cucumber/messages'\nimport { ArrayValues, Promisable } from 'type-fest'\nimport { IRunEnvironment } from '../api'\nimport { ILogger } from '../logger'\nimport { IFilterablePickle } from '../filter'\nimport { IResolvedPaths } from '../paths'\nimport { coordinatorTransformKeys, coordinatorVoidKeys } from './events'\n\nexport type Operation = 'loadSources' | 'loadSupport' | 'runCucumber'\n\nexport type CoordinatorPluginVoidEventKey = ArrayValues<\n typeof coordinatorVoidKeys\n>\nexport type CoordinatorPluginTransformEventKey = ArrayValues<\n typeof coordinatorTransformKeys\n>\nexport type CoordinatorPluginEventKey =\n | CoordinatorPluginVoidEventKey\n | CoordinatorPluginTransformEventKey\n\nexport type CoordinatorPluginEventValues = {\n // void\n message: Readonly<Envelope>\n 'paths:resolve': Readonly<IResolvedPaths>\n // transform\n 'pickles:filter': Readonly<Array<IFilterablePickle>>\n 'pickles:order': Readonly<Array<IFilterablePickle>>\n}\n\nexport type CoordinatorPluginEventHandler<K extends CoordinatorPluginEventKey> =\n (\n value: CoordinatorPluginEventValues[K]\n ) => K extends CoordinatorPluginTransformEventKey\n ? Promisable<CoordinatorPluginEventValues[K]>\n : void\n\nexport interface CoordinatorPluginContext<OptionsType> {\n operation: Operation\n on: <EventKey extends CoordinatorPluginEventKey>(\n event: EventKey,\n handler: CoordinatorPluginEventHandler<EventKey>\n ) => void\n options: OptionsType\n logger: ILogger\n environment: Required<IRunEnvironment>\n}\n\nexport type CoordinatorPluginFunction<OptionsType> = (\n context: CoordinatorPluginContext<OptionsType>\n) => Promisable<PluginCleanup | void>\n\nexport type PluginCleanup = () => Promisable<void>\n\n/**\n * A plugin to implement Cucumber built-in functionality.\n *\n * Uses the same events and mechanisms as user-authored plugins, but is free to require configuration and context from\n * inside of Cucumber as its `options`, whereas user-authored plugins will be limited to `pluginOptions` from the\n * project configuration.\n */\nexport interface InternalPlugin<OptionsType = any> {\n type: 'plugin'\n coordinator: CoordinatorPluginFunction<OptionsType>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"","sourcesContent":["import { Envelope } from '@cucumber/messages'\nimport { ArrayValues, Promisable } from 'type-fest'\nimport { IRunEnvironment } from '../api'\nimport { ILogger } from '../logger'\nimport { IFilterablePickle } from '../filter'\nimport { IResolvedPaths } from '../paths'\nimport { coordinatorTransformKeys, coordinatorVoidKeys } from './events'\n\nexport type Operation = 'loadSources' | 'loadSupport' | 'runCucumber'\n\nexport type CoordinatorPluginVoidEventKey = ArrayValues<\n typeof coordinatorVoidKeys\n>\nexport type CoordinatorPluginTransformEventKey = ArrayValues<\n typeof coordinatorTransformKeys\n>\nexport type CoordinatorPluginEventKey =\n | CoordinatorPluginVoidEventKey\n | CoordinatorPluginTransformEventKey\n\nexport type CoordinatorPluginEventValues = {\n // void\n message: Readonly<Envelope>\n 'paths:resolve': Readonly<IResolvedPaths>\n // transform\n 'pickles:filter': Readonly<Array<IFilterablePickle>>\n 'pickles:order': Readonly<Array<IFilterablePickle>>\n}\n\nexport type CoordinatorPluginEventHandler<K extends CoordinatorPluginEventKey> =\n (\n value: CoordinatorPluginEventValues[K]\n ) => K extends CoordinatorPluginTransformEventKey\n ? Promisable<CoordinatorPluginEventValues[K]>\n : void\n\nexport interface CoordinatorPluginContext<OptionsType> {\n operation: Operation\n on: <EventKey extends CoordinatorPluginEventKey>(\n event: EventKey,\n handler: CoordinatorPluginEventHandler<EventKey>\n ) => void\n options: OptionsType\n logger: ILogger\n environment: Required<IRunEnvironment>\n}\n\nexport type CoordinatorPluginFunction<OptionsType> = (\n context: CoordinatorPluginContext<OptionsType>\n) => Promisable<PluginCleanup | void>\n\nexport type PluginCleanup = () => Promisable<void>\n\n/**\n * A plugin to implement Cucumber built-in functionality.\n *\n * Uses the same events and mechanisms as user-authored plugins, but is free to require configuration and context from\n * inside of Cucumber as its `options`, whereas user-authored plugins will be limited to `pluginOptions` from the\n * project configuration.\n */\nexport interface InternalPlugin<OptionsType = any> {\n type: 'plugin'\n coordinator: CoordinatorPluginFunction<OptionsType>\n}\n\nexport interface FormatterPluginContext<OptionsType> {\n on: (key: 'message', handler: (value: Envelope) => void) => void\n options: OptionsType\n write: (buffer: string | Uint8Array) => void\n}\n\nexport type FormatterPluginFunction<OptionsType> = (\n context: FormatterPluginContext<OptionsType>\n) => Promisable<PluginCleanup | void>\n\nexport interface FormatterPlugin<OptionsType = any> {\n type: 'formatter'\n formatter: FormatterPluginFunction<OptionsType>\n documentation: string\n}\n"]}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import * as messages from '@cucumber/messages';
|
|
2
|
+
import { Envelope } from '@cucumber/messages';
|
|
2
3
|
import { IRuntimeOptions } from '../index';
|
|
4
|
+
import { ISupportCodeCoordinates } from '../../api';
|
|
3
5
|
export interface IWorkerCommand {
|
|
4
6
|
initialize?: IWorkerCommandInitialize;
|
|
5
7
|
run?: IWorkerCommandRun;
|
|
6
8
|
finalize?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export interface IWorkerCommandInitialize {
|
|
9
|
-
|
|
10
|
-
requireModules: string[];
|
|
11
|
-
requirePaths: string[];
|
|
12
|
-
importPaths: string[];
|
|
11
|
+
supportCodeCoordinates: ISupportCodeCoordinates;
|
|
13
12
|
supportCodeIds?: ICanonicalSupportCodeIds;
|
|
14
13
|
options: IRuntimeOptions;
|
|
15
14
|
}
|
|
@@ -27,6 +26,6 @@ export interface IWorkerCommandRun {
|
|
|
27
26
|
gherkinDocument: messages.GherkinDocument;
|
|
28
27
|
}
|
|
29
28
|
export interface ICoordinatorReport {
|
|
30
|
-
jsonEnvelope?:
|
|
29
|
+
jsonEnvelope?: Envelope;
|
|
31
30
|
ready?: boolean;
|
|
32
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command_types.js","sourceRoot":"","sources":["../../../src/runtime/parallel/command_types.ts"],"names":[],"mappings":"","sourcesContent":["import * as messages from '@cucumber/messages'\nimport { IRuntimeOptions } from '../index'\n\n// Messages from Coordinator to Worker\n\nexport interface IWorkerCommand {\n initialize?: IWorkerCommandInitialize\n run?: IWorkerCommandRun\n finalize?: boolean\n}\n\nexport interface IWorkerCommandInitialize {\n
|
|
1
|
+
{"version":3,"file":"command_types.js","sourceRoot":"","sources":["../../../src/runtime/parallel/command_types.ts"],"names":[],"mappings":"","sourcesContent":["import * as messages from '@cucumber/messages'\nimport { Envelope } from '@cucumber/messages'\nimport { IRuntimeOptions } from '../index'\nimport { ISupportCodeCoordinates } from '../../api'\n\n// Messages from Coordinator to Worker\n\nexport interface IWorkerCommand {\n initialize?: IWorkerCommandInitialize\n run?: IWorkerCommandRun\n finalize?: boolean\n}\n\nexport interface IWorkerCommandInitialize {\n supportCodeCoordinates: ISupportCodeCoordinates\n supportCodeIds?: ICanonicalSupportCodeIds\n options: IRuntimeOptions\n}\n\nexport interface ICanonicalSupportCodeIds {\n stepDefinitionIds: string[]\n beforeTestCaseHookDefinitionIds: string[]\n afterTestCaseHookDefinitionIds: string[]\n}\n\nexport interface IWorkerCommandRun {\n retries: number\n skip: boolean\n elapsed: messages.Duration\n pickle: messages.Pickle\n testCase: messages.TestCase\n gherkinDocument: messages.GherkinDocument\n}\n\n// Messages from Worker to Coordinator\n\nexport interface ICoordinatorReport {\n jsonEnvelope?: Envelope\n ready?: boolean\n}\n"]}
|
|
@@ -18,9 +18,6 @@ export interface INewCoordinatorOptions {
|
|
|
18
18
|
newId: IdGenerator.NewId;
|
|
19
19
|
pickleIds: string[];
|
|
20
20
|
supportCodeLibrary: SupportCodeLibrary;
|
|
21
|
-
requireModules: string[];
|
|
22
|
-
requirePaths: string[];
|
|
23
|
-
importPaths: string[];
|
|
24
21
|
numberOfWorkers: number;
|
|
25
22
|
}
|
|
26
23
|
declare const enum WorkerState {
|
|
@@ -51,19 +48,16 @@ export default class Coordinator implements IRuntime {
|
|
|
51
48
|
private readonly inProgressPickles;
|
|
52
49
|
private readonly workers;
|
|
53
50
|
private readonly supportCodeLibrary;
|
|
54
|
-
private readonly requireModules;
|
|
55
|
-
private readonly requirePaths;
|
|
56
|
-
private readonly importPaths;
|
|
57
51
|
private readonly numberOfWorkers;
|
|
58
52
|
private readonly logger;
|
|
59
53
|
private success;
|
|
60
54
|
private idleInterventions;
|
|
61
|
-
constructor({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, options, newId, supportCodeLibrary,
|
|
55
|
+
constructor({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, options, newId, supportCodeLibrary, numberOfWorkers, }: INewCoordinatorOptions);
|
|
62
56
|
parseWorkerMessage(worker: IWorker, message: ICoordinatorReport): void;
|
|
63
57
|
awakenWorkers(triggeringWorker: IWorker): void;
|
|
64
58
|
startWorker(id: string, total: number): void;
|
|
65
59
|
onWorkerProcessClose(exitCode: number): void;
|
|
66
|
-
parseTestCaseResult(testCaseFinished: messages.TestCaseFinished): void;
|
|
60
|
+
parseTestCaseResult(testCaseFinished: messages.TestCaseFinished, workerId: string): void;
|
|
67
61
|
start(): Promise<boolean>;
|
|
68
62
|
nextPicklePlacement(): IPicklePlacement;
|
|
69
63
|
placementAt(index: number): IPicklePlacement;
|
|
@@ -1,34 +1,10 @@
|
|
|
1
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 (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
28
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
6
|
const node_child_process_1 = require("node:child_process");
|
|
30
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
31
|
-
const messages = __importStar(require("@cucumber/messages"));
|
|
32
8
|
const helpers_1 = require("../helpers");
|
|
33
9
|
const value_checker_1 = require("../../value_checker");
|
|
34
10
|
const stopwatch_1 = require("../stopwatch");
|
|
@@ -47,14 +23,11 @@ class Coordinator {
|
|
|
47
23
|
inProgressPickles;
|
|
48
24
|
workers;
|
|
49
25
|
supportCodeLibrary;
|
|
50
|
-
requireModules;
|
|
51
|
-
requirePaths;
|
|
52
|
-
importPaths;
|
|
53
26
|
numberOfWorkers;
|
|
54
27
|
logger;
|
|
55
28
|
success;
|
|
56
29
|
idleInterventions;
|
|
57
|
-
constructor({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, options, newId, supportCodeLibrary,
|
|
30
|
+
constructor({ cwd, logger, eventBroadcaster, eventDataCollector, pickleIds, options, newId, supportCodeLibrary, numberOfWorkers, }) {
|
|
58
31
|
this.cwd = cwd;
|
|
59
32
|
this.logger = logger;
|
|
60
33
|
this.eventBroadcaster = eventBroadcaster;
|
|
@@ -63,9 +36,6 @@ class Coordinator {
|
|
|
63
36
|
this.options = options;
|
|
64
37
|
this.newId = newId;
|
|
65
38
|
this.supportCodeLibrary = supportCodeLibrary;
|
|
66
|
-
this.requireModules = requireModules;
|
|
67
|
-
this.requirePaths = requirePaths;
|
|
68
|
-
this.importPaths = importPaths;
|
|
69
39
|
this.pickleIds = Array.from(pickleIds);
|
|
70
40
|
this.numberOfWorkers = numberOfWorkers;
|
|
71
41
|
this.success = true;
|
|
@@ -79,11 +49,10 @@ class Coordinator {
|
|
|
79
49
|
this.awakenWorkers(worker);
|
|
80
50
|
}
|
|
81
51
|
else if ((0, value_checker_1.doesHaveValue)(message.jsonEnvelope)) {
|
|
82
|
-
const envelope =
|
|
52
|
+
const envelope = message.jsonEnvelope;
|
|
83
53
|
this.eventBroadcaster.emit('envelope', envelope);
|
|
84
54
|
if ((0, value_checker_1.doesHaveValue)(envelope.testCaseFinished)) {
|
|
85
|
-
|
|
86
|
-
this.parseTestCaseResult(envelope.testCaseFinished);
|
|
55
|
+
this.parseTestCaseResult(envelope.testCaseFinished, worker.id);
|
|
87
56
|
}
|
|
88
57
|
}
|
|
89
58
|
else {
|
|
@@ -125,10 +94,7 @@ class Coordinator {
|
|
|
125
94
|
});
|
|
126
95
|
const initializeCommand = {
|
|
127
96
|
initialize: {
|
|
128
|
-
|
|
129
|
-
requireModules: this.requireModules,
|
|
130
|
-
requirePaths: this.requirePaths,
|
|
131
|
-
importPaths: this.importPaths,
|
|
97
|
+
supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,
|
|
132
98
|
supportCodeIds: {
|
|
133
99
|
stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map((s) => s.id),
|
|
134
100
|
beforeTestCaseHookDefinitionIds: this.supportCodeLibrary.beforeTestCaseHookDefinitions.map((h) => h.id),
|
|
@@ -155,11 +121,13 @@ class Coordinator {
|
|
|
155
121
|
this.onFinish(this.success);
|
|
156
122
|
}
|
|
157
123
|
}
|
|
158
|
-
parseTestCaseResult(testCaseFinished) {
|
|
124
|
+
parseTestCaseResult(testCaseFinished, workerId) {
|
|
159
125
|
const { worstTestStepResult } = this.eventDataCollector.getTestCaseAttempt(testCaseFinished.testCaseStartedId);
|
|
160
|
-
if (!testCaseFinished.willBeRetried
|
|
161
|
-
|
|
162
|
-
this.
|
|
126
|
+
if (!testCaseFinished.willBeRetried) {
|
|
127
|
+
delete this.inProgressPickles[workerId];
|
|
128
|
+
if ((0, helpers_1.shouldCauseFailure)(worstTestStepResult.status, this.options)) {
|
|
129
|
+
this.success = false;
|
|
130
|
+
}
|
|
163
131
|
}
|
|
164
132
|
}
|
|
165
133
|
async start() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../../src/runtime/parallel/coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChildProcess, fork } from 'node:child_process'\nimport path from 'node:path'\nimport { EventEmitter } from 'node:events'\nimport * as messages from '@cucumber/messages'\nimport { IdGenerator } from '@cucumber/messages'\nimport { retriesForPickle, shouldCauseFailure } from '../helpers'\nimport { EventDataCollector } from '../../formatter/helpers'\nimport { IRuntime, IRuntimeOptions } from '..'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\nimport { doesHaveValue } from '../../value_checker'\nimport { IStopwatch, create } from '../stopwatch'\nimport { assembleTestCases, IAssembledTestCases } from '../assemble_test_cases'\nimport { ILogger } from '../../logger'\nimport { ICoordinatorReport, IWorkerCommand } from './command_types'\n\nconst runWorkerPath = path.resolve(__dirname, 'run_worker.js')\n\nexport interface INewCoordinatorOptions {\n cwd: string\n logger: ILogger\n eventBroadcaster: EventEmitter\n eventDataCollector: EventDataCollector\n options: IRuntimeOptions\n newId: IdGenerator.NewId\n pickleIds: string[]\n supportCodeLibrary: SupportCodeLibrary\n requireModules: string[]\n requirePaths: string[]\n importPaths: string[]\n numberOfWorkers: number\n}\n\nconst enum WorkerState {\n 'idle',\n 'closed',\n 'running',\n 'new',\n}\n\ninterface IWorker {\n state: WorkerState\n process: ChildProcess\n id: string\n}\n\ninterface IPicklePlacement {\n index: number\n pickle: messages.Pickle\n}\n\nexport default class Coordinator implements IRuntime {\n private readonly cwd: string\n private readonly eventBroadcaster: EventEmitter\n private readonly eventDataCollector: EventDataCollector\n private readonly stopwatch: IStopwatch\n private onFinish: (success: boolean) => void\n private readonly options: IRuntimeOptions\n private readonly newId: IdGenerator.NewId\n private readonly pickleIds: string[]\n private assembledTestCases: IAssembledTestCases\n private readonly inProgressPickles: Record<string, messages.Pickle>\n private readonly workers: Record<string, IWorker>\n private readonly supportCodeLibrary: SupportCodeLibrary\n private readonly requireModules: string[]\n private readonly requirePaths: string[]\n private readonly importPaths: string[]\n private readonly numberOfWorkers: number\n private readonly logger: ILogger\n private success: boolean\n private idleInterventions: number\n\n constructor({\n cwd,\n logger,\n eventBroadcaster,\n eventDataCollector,\n pickleIds,\n options,\n newId,\n supportCodeLibrary,\n requireModules,\n requirePaths,\n importPaths,\n numberOfWorkers,\n }: INewCoordinatorOptions) {\n this.cwd = cwd\n this.logger = logger\n this.eventBroadcaster = eventBroadcaster\n this.eventDataCollector = eventDataCollector\n this.stopwatch = create()\n this.options = options\n this.newId = newId\n this.supportCodeLibrary = supportCodeLibrary\n this.requireModules = requireModules\n this.requirePaths = requirePaths\n this.importPaths = importPaths\n this.pickleIds = Array.from(pickleIds)\n this.numberOfWorkers = numberOfWorkers\n this.success = true\n this.workers = {}\n this.inProgressPickles = {}\n this.idleInterventions = 0\n }\n\n parseWorkerMessage(worker: IWorker, message: ICoordinatorReport): void {\n if (message.ready) {\n worker.state = WorkerState.idle\n this.awakenWorkers(worker)\n } else if (doesHaveValue(message.jsonEnvelope)) {\n const envelope = messages.parseEnvelope(message.jsonEnvelope)\n this.eventBroadcaster.emit('envelope', envelope)\n if (doesHaveValue(envelope.testCaseFinished)) {\n delete this.inProgressPickles[worker.id]\n this.parseTestCaseResult(envelope.testCaseFinished)\n }\n } else {\n throw new Error(\n `Unexpected message from worker: ${JSON.stringify(message)}`\n )\n }\n }\n\n awakenWorkers(triggeringWorker: IWorker): void {\n Object.values(this.workers).forEach((worker) => {\n if (worker.state === WorkerState.idle) {\n this.giveWork(worker)\n }\n return worker.state !== WorkerState.idle\n })\n\n if (\n Object.keys(this.inProgressPickles).length == 0 &&\n this.pickleIds.length > 0\n ) {\n this.giveWork(triggeringWorker, true)\n this.idleInterventions++\n }\n }\n\n startWorker(id: string, total: number): void {\n const workerProcess = fork(runWorkerPath, [], {\n cwd: this.cwd,\n env: {\n ...process.env,\n CUCUMBER_PARALLEL: 'true',\n CUCUMBER_TOTAL_WORKERS: total.toString(),\n CUCUMBER_WORKER_ID: id,\n },\n stdio: ['inherit', 'inherit', 'inherit', 'ipc'],\n })\n const worker = { state: WorkerState.new, process: workerProcess, id }\n this.workers[id] = worker\n worker.process.on('message', (message: ICoordinatorReport) => {\n this.parseWorkerMessage(worker, message)\n })\n worker.process.on('close', (exitCode) => {\n worker.state = WorkerState.closed\n this.onWorkerProcessClose(exitCode)\n })\n const initializeCommand: IWorkerCommand = {\n initialize: {\n filterStacktraces: this.options.filterStacktraces,\n requireModules: this.requireModules,\n requirePaths: this.requirePaths,\n importPaths: this.importPaths,\n supportCodeIds: {\n stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(\n (s) => s.id\n ),\n beforeTestCaseHookDefinitionIds:\n this.supportCodeLibrary.beforeTestCaseHookDefinitions.map(\n (h) => h.id\n ),\n afterTestCaseHookDefinitionIds:\n this.supportCodeLibrary.afterTestCaseHookDefinitions.map(\n (h) => h.id\n ),\n },\n options: this.options,\n },\n }\n worker.process.send(initializeCommand)\n }\n\n onWorkerProcessClose(exitCode: number): void {\n const success = exitCode === 0\n if (!success) {\n this.success = false\n }\n\n if (\n Object.values(this.workers).every((x) => x.state === WorkerState.closed)\n ) {\n const envelope: messages.Envelope = {\n testRunFinished: {\n timestamp: this.stopwatch.timestamp(),\n success,\n },\n }\n this.eventBroadcaster.emit('envelope', envelope)\n this.onFinish(this.success)\n }\n }\n\n parseTestCaseResult(testCaseFinished: messages.TestCaseFinished): void {\n const { worstTestStepResult } = this.eventDataCollector.getTestCaseAttempt(\n testCaseFinished.testCaseStartedId\n )\n if (\n !testCaseFinished.willBeRetried &&\n shouldCauseFailure(worstTestStepResult.status, this.options)\n ) {\n this.success = false\n }\n }\n\n async start(): Promise<boolean> {\n const envelope: messages.Envelope = {\n testRunStarted: {\n timestamp: this.stopwatch.timestamp(),\n },\n }\n this.eventBroadcaster.emit('envelope', envelope)\n this.stopwatch.start()\n this.assembledTestCases = await assembleTestCases({\n eventBroadcaster: this.eventBroadcaster,\n newId: this.newId,\n pickles: this.pickleIds.map((pickleId) =>\n this.eventDataCollector.getPickle(pickleId)\n ),\n supportCodeLibrary: this.supportCodeLibrary,\n })\n return await new Promise<boolean>((resolve) => {\n for (let i = 0; i < this.numberOfWorkers; i++) {\n this.startWorker(i.toString(), this.numberOfWorkers)\n }\n this.onFinish = (status) => {\n if (this.idleInterventions > 0) {\n this.logger.warn(\n `WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`\n )\n }\n\n resolve(status)\n }\n })\n }\n\n nextPicklePlacement(): IPicklePlacement {\n for (let index = 0; index < this.pickleIds.length; index++) {\n const placement = this.placementAt(index)\n if (\n this.supportCodeLibrary.parallelCanAssign(\n placement.pickle,\n Object.values(this.inProgressPickles)\n )\n ) {\n return placement\n }\n }\n\n return null\n }\n\n placementAt(index: number): IPicklePlacement {\n return {\n index,\n pickle: this.eventDataCollector.getPickle(this.pickleIds[index]),\n }\n }\n\n giveWork(worker: IWorker, force: boolean = false): void {\n if (this.pickleIds.length < 1) {\n const finalizeCommand: IWorkerCommand = { finalize: true }\n worker.state = WorkerState.running\n worker.process.send(finalizeCommand)\n return\n }\n\n const picklePlacement = force\n ? this.placementAt(0)\n : this.nextPicklePlacement()\n\n if (picklePlacement === null) {\n return\n }\n\n const { index: nextPickleIndex, pickle } = picklePlacement\n\n this.pickleIds.splice(nextPickleIndex, 1)\n this.inProgressPickles[worker.id] = pickle\n const testCase = this.assembledTestCases[pickle.id]\n const gherkinDocument = this.eventDataCollector.getGherkinDocument(\n pickle.uri\n )\n const retries = retriesForPickle(pickle, this.options)\n const skip = this.options.dryRun || (this.options.failFast && !this.success)\n const runCommand: IWorkerCommand = {\n run: {\n retries,\n skip,\n elapsed: this.stopwatch.duration(),\n pickle,\n testCase,\n gherkinDocument,\n },\n }\n worker.state = WorkerState.running\n worker.process.send(runCommand)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../../src/runtime/parallel/coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChildProcess, fork } from 'node:child_process'\nimport path from 'node:path'\nimport { EventEmitter } from 'node:events'\nimport * as messages from '@cucumber/messages'\nimport { IdGenerator } from '@cucumber/messages'\nimport { retriesForPickle, shouldCauseFailure } from '../helpers'\nimport { EventDataCollector } from '../../formatter/helpers'\nimport { IRuntime, IRuntimeOptions } from '..'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\nimport { doesHaveValue } from '../../value_checker'\nimport { IStopwatch, create } from '../stopwatch'\nimport { assembleTestCases, IAssembledTestCases } from '../assemble_test_cases'\nimport { ILogger } from '../../logger'\nimport { ICoordinatorReport, IWorkerCommand } from './command_types'\n\nconst runWorkerPath = path.resolve(__dirname, 'run_worker.js')\n\nexport interface INewCoordinatorOptions {\n cwd: string\n logger: ILogger\n eventBroadcaster: EventEmitter\n eventDataCollector: EventDataCollector\n options: IRuntimeOptions\n newId: IdGenerator.NewId\n pickleIds: string[]\n supportCodeLibrary: SupportCodeLibrary\n numberOfWorkers: number\n}\n\nconst enum WorkerState {\n 'idle',\n 'closed',\n 'running',\n 'new',\n}\n\ninterface IWorker {\n state: WorkerState\n process: ChildProcess\n id: string\n}\n\ninterface IPicklePlacement {\n index: number\n pickle: messages.Pickle\n}\n\nexport default class Coordinator implements IRuntime {\n private readonly cwd: string\n private readonly eventBroadcaster: EventEmitter\n private readonly eventDataCollector: EventDataCollector\n private readonly stopwatch: IStopwatch\n private onFinish: (success: boolean) => void\n private readonly options: IRuntimeOptions\n private readonly newId: IdGenerator.NewId\n private readonly pickleIds: string[]\n private assembledTestCases: IAssembledTestCases\n private readonly inProgressPickles: Record<string, messages.Pickle>\n private readonly workers: Record<string, IWorker>\n private readonly supportCodeLibrary: SupportCodeLibrary\n private readonly numberOfWorkers: number\n private readonly logger: ILogger\n private success: boolean\n private idleInterventions: number\n\n constructor({\n cwd,\n logger,\n eventBroadcaster,\n eventDataCollector,\n pickleIds,\n options,\n newId,\n supportCodeLibrary,\n numberOfWorkers,\n }: INewCoordinatorOptions) {\n this.cwd = cwd\n this.logger = logger\n this.eventBroadcaster = eventBroadcaster\n this.eventDataCollector = eventDataCollector\n this.stopwatch = create()\n this.options = options\n this.newId = newId\n this.supportCodeLibrary = supportCodeLibrary\n this.pickleIds = Array.from(pickleIds)\n this.numberOfWorkers = numberOfWorkers\n this.success = true\n this.workers = {}\n this.inProgressPickles = {}\n this.idleInterventions = 0\n }\n\n parseWorkerMessage(worker: IWorker, message: ICoordinatorReport): void {\n if (message.ready) {\n worker.state = WorkerState.idle\n this.awakenWorkers(worker)\n } else if (doesHaveValue(message.jsonEnvelope)) {\n const envelope = message.jsonEnvelope\n this.eventBroadcaster.emit('envelope', envelope)\n if (doesHaveValue(envelope.testCaseFinished)) {\n this.parseTestCaseResult(envelope.testCaseFinished, worker.id)\n }\n } else {\n throw new Error(\n `Unexpected message from worker: ${JSON.stringify(message)}`\n )\n }\n }\n\n awakenWorkers(triggeringWorker: IWorker): void {\n Object.values(this.workers).forEach((worker) => {\n if (worker.state === WorkerState.idle) {\n this.giveWork(worker)\n }\n return worker.state !== WorkerState.idle\n })\n\n if (\n Object.keys(this.inProgressPickles).length == 0 &&\n this.pickleIds.length > 0\n ) {\n this.giveWork(triggeringWorker, true)\n this.idleInterventions++\n }\n }\n\n startWorker(id: string, total: number): void {\n const workerProcess = fork(runWorkerPath, [], {\n cwd: this.cwd,\n env: {\n ...process.env,\n CUCUMBER_PARALLEL: 'true',\n CUCUMBER_TOTAL_WORKERS: total.toString(),\n CUCUMBER_WORKER_ID: id,\n },\n stdio: ['inherit', 'inherit', 'inherit', 'ipc'],\n })\n const worker = { state: WorkerState.new, process: workerProcess, id }\n this.workers[id] = worker\n worker.process.on('message', (message: ICoordinatorReport) => {\n this.parseWorkerMessage(worker, message)\n })\n worker.process.on('close', (exitCode) => {\n worker.state = WorkerState.closed\n this.onWorkerProcessClose(exitCode)\n })\n const initializeCommand: IWorkerCommand = {\n initialize: {\n supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,\n supportCodeIds: {\n stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(\n (s) => s.id\n ),\n beforeTestCaseHookDefinitionIds:\n this.supportCodeLibrary.beforeTestCaseHookDefinitions.map(\n (h) => h.id\n ),\n afterTestCaseHookDefinitionIds:\n this.supportCodeLibrary.afterTestCaseHookDefinitions.map(\n (h) => h.id\n ),\n },\n options: this.options,\n },\n }\n worker.process.send(initializeCommand)\n }\n\n onWorkerProcessClose(exitCode: number): void {\n const success = exitCode === 0\n if (!success) {\n this.success = false\n }\n\n if (\n Object.values(this.workers).every((x) => x.state === WorkerState.closed)\n ) {\n const envelope: messages.Envelope = {\n testRunFinished: {\n timestamp: this.stopwatch.timestamp(),\n success,\n },\n }\n this.eventBroadcaster.emit('envelope', envelope)\n this.onFinish(this.success)\n }\n }\n\n parseTestCaseResult(\n testCaseFinished: messages.TestCaseFinished,\n workerId: string\n ): void {\n const { worstTestStepResult } = this.eventDataCollector.getTestCaseAttempt(\n testCaseFinished.testCaseStartedId\n )\n if (!testCaseFinished.willBeRetried) {\n delete this.inProgressPickles[workerId]\n\n if (shouldCauseFailure(worstTestStepResult.status, this.options)) {\n this.success = false\n }\n }\n }\n\n async start(): Promise<boolean> {\n const envelope: messages.Envelope = {\n testRunStarted: {\n timestamp: this.stopwatch.timestamp(),\n },\n }\n this.eventBroadcaster.emit('envelope', envelope)\n this.stopwatch.start()\n this.assembledTestCases = await assembleTestCases({\n eventBroadcaster: this.eventBroadcaster,\n newId: this.newId,\n pickles: this.pickleIds.map((pickleId) =>\n this.eventDataCollector.getPickle(pickleId)\n ),\n supportCodeLibrary: this.supportCodeLibrary,\n })\n return await new Promise<boolean>((resolve) => {\n for (let i = 0; i < this.numberOfWorkers; i++) {\n this.startWorker(i.toString(), this.numberOfWorkers)\n }\n this.onFinish = (status) => {\n if (this.idleInterventions > 0) {\n this.logger.warn(\n `WARNING: All workers went idle ${this.idleInterventions} time(s). Consider revising handler passed to setParallelCanAssign.`\n )\n }\n\n resolve(status)\n }\n })\n }\n\n nextPicklePlacement(): IPicklePlacement {\n for (let index = 0; index < this.pickleIds.length; index++) {\n const placement = this.placementAt(index)\n if (\n this.supportCodeLibrary.parallelCanAssign(\n placement.pickle,\n Object.values(this.inProgressPickles)\n )\n ) {\n return placement\n }\n }\n\n return null\n }\n\n placementAt(index: number): IPicklePlacement {\n return {\n index,\n pickle: this.eventDataCollector.getPickle(this.pickleIds[index]),\n }\n }\n\n giveWork(worker: IWorker, force: boolean = false): void {\n if (this.pickleIds.length < 1) {\n const finalizeCommand: IWorkerCommand = { finalize: true }\n worker.state = WorkerState.running\n worker.process.send(finalizeCommand)\n return\n }\n\n const picklePlacement = force\n ? this.placementAt(0)\n : this.nextPicklePlacement()\n\n if (picklePlacement === null) {\n return\n }\n\n const { index: nextPickleIndex, pickle } = picklePlacement\n\n this.pickleIds.splice(nextPickleIndex, 1)\n this.inProgressPickles[worker.id] = pickle\n const testCase = this.assembledTestCases[pickle.id]\n const gherkinDocument = this.eventDataCollector.getGherkinDocument(\n pickle.uri\n )\n const retries = retriesForPickle(pickle, this.options)\n const skip = this.options.dryRun || (this.options.failFast && !this.success)\n const runCommand: IWorkerCommand = {\n run: {\n retries,\n skip,\n elapsed: this.stopwatch.duration(),\n pickle,\n testCase,\n gherkinDocument,\n },\n }\n worker.state = WorkerState.running\n worker.process.send(runCommand)\n }\n}\n"]}
|
|
@@ -18,7 +18,7 @@ export default class Worker {
|
|
|
18
18
|
id: string;
|
|
19
19
|
sendMessage: IMessageSender;
|
|
20
20
|
});
|
|
21
|
-
initialize({
|
|
21
|
+
initialize({ supportCodeCoordinates, supportCodeIds, options, }: IWorkerCommandInitialize): Promise<void>;
|
|
22
22
|
finalize(): Promise<void>;
|
|
23
23
|
receiveMessage(message: IWorkerCommand): Promise<void>;
|
|
24
24
|
runTestCase({ gherkinDocument, pickle, testCase, elapsed, retries, skip, }: IWorkerCommandRun): Promise<void>;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const node_events_1 = require("node:events");
|
|
7
7
|
const node_url_1 = require("node:url");
|
|
8
|
+
const node_module_1 = require("node:module");
|
|
8
9
|
const messages_1 = require("@cucumber/messages");
|
|
9
10
|
const support_code_library_builder_1 = __importDefault(require("../../support_code_library_builder"));
|
|
10
11
|
const value_checker_1 = require("../../value_checker");
|
|
@@ -32,27 +33,22 @@ class Worker {
|
|
|
32
33
|
this.sendMessage = sendMessage;
|
|
33
34
|
this.eventBroadcaster = new node_events_1.EventEmitter();
|
|
34
35
|
this.eventBroadcaster.on('envelope', (envelope) => {
|
|
35
|
-
|
|
36
|
-
if (envelope.testCaseStarted) {
|
|
37
|
-
envelope.testCaseStarted.workerId = this.id;
|
|
38
|
-
}
|
|
39
|
-
this.sendMessage({ jsonEnvelope: JSON.stringify(envelope) });
|
|
36
|
+
this.sendMessage({ jsonEnvelope: envelope });
|
|
40
37
|
});
|
|
41
38
|
}
|
|
42
|
-
async initialize({
|
|
43
|
-
support_code_library_builder_1.default.reset(this.cwd, this.newId,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
for (const path of importPaths) {
|
|
39
|
+
async initialize({ supportCodeCoordinates, supportCodeIds, options, }) {
|
|
40
|
+
support_code_library_builder_1.default.reset(this.cwd, this.newId, supportCodeCoordinates);
|
|
41
|
+
supportCodeCoordinates.requireModules.map((module) => (0, try_require_1.default)(module));
|
|
42
|
+
supportCodeCoordinates.requirePaths.map((module) => (0, try_require_1.default)(module));
|
|
43
|
+
for (const specifier of supportCodeCoordinates.loaders) {
|
|
44
|
+
(0, node_module_1.register)(specifier, (0, node_url_1.pathToFileURL)('./'));
|
|
45
|
+
}
|
|
46
|
+
for (const path of supportCodeCoordinates.importPaths) {
|
|
51
47
|
await import((0, node_url_1.pathToFileURL)(path).toString());
|
|
52
48
|
}
|
|
53
49
|
this.supportCodeLibrary = support_code_library_builder_1.default.finalize(supportCodeIds);
|
|
54
50
|
this.worldParameters = options.worldParameters;
|
|
55
|
-
this.filterStacktraces = filterStacktraces;
|
|
51
|
+
this.filterStacktraces = options.filterStacktraces;
|
|
56
52
|
this.runTestRunHooks = (0, run_test_run_hooks_1.makeRunTestRunHooks)(options.dryRun, this.supportCodeLibrary.defaultTimeout, this.worldParameters, (name, location) => `${name} hook errored on worker ${this.id}, process exiting: ${location}`);
|
|
57
53
|
await this.runTestRunHooks(this.supportCodeLibrary.beforeTestRunHookDefinitions, 'a BeforeAll');
|
|
58
54
|
this.sendMessage({ ready: true });
|
|
@@ -75,6 +71,7 @@ class Worker {
|
|
|
75
71
|
async runTestCase({ gherkinDocument, pickle, testCase, elapsed, retries, skip, }) {
|
|
76
72
|
const stopwatch = (0, stopwatch_1.create)(elapsed);
|
|
77
73
|
const testCaseRunner = new test_case_runner_1.default({
|
|
74
|
+
workerId: this.id,
|
|
78
75
|
eventBroadcaster: this.eventBroadcaster,
|
|
79
76
|
stopwatch,
|
|
80
77
|
gherkinDocument,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/worker.ts"],"names":[],"mappings":";;;;;AAAA,6CAA0C;AAC1C,uCAAwC;
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/runtime/parallel/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from 'node:events'\nimport { pathToFileURL } from 'node:url'\nimport { register } from 'node:module'\nimport * as messages from '@cucumber/messages'\nimport { IdGenerator } from '@cucumber/messages'\nimport { JsonObject } from 'type-fest'\nimport supportCodeLibraryBuilder from '../../support_code_library_builder'\nimport { SupportCodeLibrary } from '../../support_code_library_builder/types'\nimport { doesHaveValue } from '../../value_checker'\nimport { makeRunTestRunHooks, RunsTestRunHooks } from '../run_test_run_hooks'\nimport { create } from '../stopwatch'\nimport TestCaseRunner from '../test_case_runner'\nimport tryRequire from '../../try_require'\nimport {\n ICoordinatorReport,\n IWorkerCommand,\n IWorkerCommandInitialize,\n IWorkerCommandRun,\n} from './command_types'\n\nconst { uuid } = IdGenerator\n\ntype IExitFunction = (exitCode: number, error?: Error, message?: string) => void\ntype IMessageSender = (command: ICoordinatorReport) => void\n\nexport default class Worker {\n private readonly cwd: string\n private readonly exit: IExitFunction\n\n private readonly id: string\n private readonly eventBroadcaster: EventEmitter\n private filterStacktraces: boolean\n private readonly newId: IdGenerator.NewId\n private readonly sendMessage: IMessageSender\n private supportCodeLibrary: SupportCodeLibrary\n private worldParameters: JsonObject\n private runTestRunHooks: RunsTestRunHooks\n\n constructor({\n cwd,\n exit,\n id,\n sendMessage,\n }: {\n cwd: string\n exit: IExitFunction\n id: string\n sendMessage: IMessageSender\n }) {\n this.id = id\n this.newId = uuid()\n this.cwd = cwd\n this.exit = exit\n this.sendMessage = sendMessage\n this.eventBroadcaster = new EventEmitter()\n this.eventBroadcaster.on('envelope', (envelope: messages.Envelope) => {\n this.sendMessage({ jsonEnvelope: envelope })\n })\n }\n\n async initialize({\n supportCodeCoordinates,\n supportCodeIds,\n options,\n }: IWorkerCommandInitialize): Promise<void> {\n supportCodeLibraryBuilder.reset(\n this.cwd,\n this.newId,\n supportCodeCoordinates\n )\n supportCodeCoordinates.requireModules.map((module) => tryRequire(module))\n supportCodeCoordinates.requirePaths.map((module) => tryRequire(module))\n for (const specifier of supportCodeCoordinates.loaders) {\n register(specifier, pathToFileURL('./'))\n }\n for (const path of supportCodeCoordinates.importPaths) {\n await import(pathToFileURL(path).toString())\n }\n this.supportCodeLibrary = supportCodeLibraryBuilder.finalize(supportCodeIds)\n\n this.worldParameters = options.worldParameters\n this.filterStacktraces = options.filterStacktraces\n this.runTestRunHooks = makeRunTestRunHooks(\n options.dryRun,\n this.supportCodeLibrary.defaultTimeout,\n this.worldParameters,\n (name, location) =>\n `${name} hook errored on worker ${this.id}, process exiting: ${location}`\n )\n await this.runTestRunHooks(\n this.supportCodeLibrary.beforeTestRunHookDefinitions,\n 'a BeforeAll'\n )\n this.sendMessage({ ready: true })\n }\n\n async finalize(): Promise<void> {\n await this.runTestRunHooks(\n this.supportCodeLibrary.afterTestRunHookDefinitions,\n 'an AfterAll'\n )\n this.exit(0)\n }\n\n async receiveMessage(message: IWorkerCommand): Promise<void> {\n if (doesHaveValue(message.initialize)) {\n await this.initialize(message.initialize)\n } else if (message.finalize) {\n await this.finalize()\n } else if (doesHaveValue(message.run)) {\n await this.runTestCase(message.run)\n }\n }\n\n async runTestCase({\n gherkinDocument,\n pickle,\n testCase,\n elapsed,\n retries,\n skip,\n }: IWorkerCommandRun): Promise<void> {\n const stopwatch = create(elapsed)\n const testCaseRunner = new TestCaseRunner({\n workerId: this.id,\n eventBroadcaster: this.eventBroadcaster,\n stopwatch,\n gherkinDocument,\n newId: this.newId,\n pickle,\n testCase,\n retries,\n skip,\n filterStackTraces: this.filterStacktraces,\n supportCodeLibrary: this.supportCodeLibrary,\n worldParameters: this.worldParameters,\n })\n await testCaseRunner.run()\n this.sendMessage({ ready: true })\n }\n}\n"]}
|
|
@@ -9,6 +9,7 @@ import TestStepHookDefinition from '../models/test_step_hook_definition';
|
|
|
9
9
|
import { IDefinition } from '../models/definition';
|
|
10
10
|
import { IStopwatch } from './stopwatch';
|
|
11
11
|
export interface INewTestCaseRunnerOptions {
|
|
12
|
+
workerId?: string;
|
|
12
13
|
eventBroadcaster: EventEmitter;
|
|
13
14
|
stopwatch: IStopwatch;
|
|
14
15
|
gherkinDocument: messages.GherkinDocument;
|
|
@@ -22,6 +23,7 @@ export interface INewTestCaseRunnerOptions {
|
|
|
22
23
|
worldParameters: JsonObject;
|
|
23
24
|
}
|
|
24
25
|
export default class TestCaseRunner {
|
|
26
|
+
private readonly workerId;
|
|
25
27
|
private readonly attachmentManager;
|
|
26
28
|
private currentTestCaseStartedId;
|
|
27
29
|
private currentTestStepId;
|
|
@@ -38,7 +40,7 @@ export default class TestCaseRunner {
|
|
|
38
40
|
private testStepResults;
|
|
39
41
|
private world;
|
|
40
42
|
private readonly worldParameters;
|
|
41
|
-
constructor({ eventBroadcaster, stopwatch, gherkinDocument, newId, pickle, testCase, retries, skip, filterStackTraces, supportCodeLibrary, worldParameters, }: INewTestCaseRunnerOptions);
|
|
43
|
+
constructor({ workerId, eventBroadcaster, stopwatch, gherkinDocument, newId, pickle, testCase, retries, skip, filterStackTraces, supportCodeLibrary, worldParameters, }: INewTestCaseRunnerOptions);
|
|
42
44
|
resetTestProgressData(): void;
|
|
43
45
|
getBeforeStepHookDefinitions(): TestStepHookDefinition[];
|
|
44
46
|
getAfterStepHookDefinitions(): TestStepHookDefinition[];
|
|
@@ -33,6 +33,7 @@ const step_runner_1 = __importDefault(require("./step_runner"));
|
|
|
33
33
|
const attachment_manager_1 = __importDefault(require("./attachment_manager"));
|
|
34
34
|
const helpers_1 = require("./helpers");
|
|
35
35
|
class TestCaseRunner {
|
|
36
|
+
workerId;
|
|
36
37
|
attachmentManager;
|
|
37
38
|
currentTestCaseStartedId;
|
|
38
39
|
currentTestStepId;
|
|
@@ -49,7 +50,8 @@ class TestCaseRunner {
|
|
|
49
50
|
testStepResults;
|
|
50
51
|
world;
|
|
51
52
|
worldParameters;
|
|
52
|
-
constructor({ eventBroadcaster, stopwatch, gherkinDocument, newId, pickle, testCase, retries = 0, skip, filterStackTraces, supportCodeLibrary, worldParameters, }) {
|
|
53
|
+
constructor({ workerId, eventBroadcaster, stopwatch, gherkinDocument, newId, pickle, testCase, retries = 0, skip, filterStackTraces, supportCodeLibrary, worldParameters, }) {
|
|
54
|
+
this.workerId = workerId;
|
|
53
55
|
this.attachmentManager = new attachment_manager_1.default(({ data, media, fileName }) => {
|
|
54
56
|
if ((0, value_checker_1.doesNotHaveValue)(this.currentTestStepId)) {
|
|
55
57
|
throw new Error('Cannot attach when a step/hook is not running. Ensure your step/hook waits for the attach to finish.');
|
|
@@ -167,6 +169,9 @@ class TestCaseRunner {
|
|
|
167
169
|
timestamp: this.stopwatch.timestamp(),
|
|
168
170
|
},
|
|
169
171
|
};
|
|
172
|
+
if (this.workerId) {
|
|
173
|
+
testCaseStarted.testCaseStarted.workerId = this.workerId;
|
|
174
|
+
}
|
|
170
175
|
this.eventBroadcaster.emit('envelope', testCaseStarted);
|
|
171
176
|
// used to determine whether a hook is a Before or After
|
|
172
177
|
let didWeRunStepsYet = false;
|