Skip to content

Commit d357150

Browse files
authored
Consolidate serial and parallel runtimes (#2422)
1 parent aa3ce7b commit d357150

31 files changed

+731
-759
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
Please see [CONTRIBUTING.md](./CONTRIBUTING.md) on how to contribute to Cucumber.
99

1010
## [Unreleased]
11+
### Changed
12+
- Major refactor of runtime code for both serial and parallel modes ([#2422](https://github.com/cucumber/cucumber-js/pull/2422))
13+
1114
### Removed
1215
- BREAKING CHANGE: Remove previously-deprecated `parseGherkinMessageStream` ([#2420](https://github.com/cucumber/cucumber-js/pull/2420))
1316
- BREAKING CHANGE: Remove previously-deprecated `PickleFilter` ([#2420](https://github.com/cucumber/cucumber-js/pull/2420))

src/api/run_cucumber.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import { emitMetaMessage, emitSupportCodeMessages } from '../cli/helpers'
55
import { resolvePaths } from '../paths'
66
import { SupportCodeLibrary } from '../support_code_library_builder/types'
77
import { version } from '../version'
8+
import { IFilterablePickle } from '../filter'
9+
import { makeRuntime } from '../runtime'
810
import { IRunOptions, IRunEnvironment, IRunResult } from './types'
9-
import { makeRuntime } from './runtime'
1011
import { initializeFormatters } from './formatters'
1112
import { getSupportCodeLibrary } from './support'
1213
import { mergeEnvironment } from './environment'
@@ -105,7 +106,7 @@ Running from: ${__dirname}
105106
})
106107
await emitMetaMessage(eventBroadcaster, env)
107108

108-
let pickleIds: string[] = []
109+
let filteredPickles: ReadonlyArray<IFilterablePickle> = []
109110
let parseErrors: ParseError[] = []
110111
if (sourcePaths.length > 0) {
111112
const gherkinResult = await getPicklesAndErrors({
@@ -115,15 +116,14 @@ Running from: ${__dirname}
115116
coordinates: options.sources,
116117
onEnvelope: (envelope) => eventBroadcaster.emit('envelope', envelope),
117118
})
118-
const filteredPickles = await pluginManager.transform(
119+
filteredPickles = await pluginManager.transform(
119120
'pickles:filter',
120121
gherkinResult.filterablePickles
121122
)
122-
const orderedPickles = await pluginManager.transform(
123+
filteredPickles = await pluginManager.transform(
123124
'pickles:order',
124125
filteredPickles
125126
)
126-
pickleIds = orderedPickles.map(({ pickle }) => pickle.id)
127127
parseErrors = gherkinResult.parseErrors
128128
}
129129
if (parseErrors.length) {
@@ -146,17 +146,16 @@ Running from: ${__dirname}
146146
newId,
147147
})
148148

149-
const runtime = makeRuntime({
150-
cwd,
149+
const runtime = await makeRuntime({
150+
environment,
151151
logger,
152152
eventBroadcaster,
153-
eventDataCollector,
154-
pickleIds,
153+
sourcedPickles: filteredPickles,
155154
newId,
156155
supportCodeLibrary,
157156
options: options.runtime,
158157
})
159-
const success = await runtime.start()
158+
const success = await runtime.run()
160159
await pluginManager.cleanup()
161160
await cleanupFormatters()
162161

src/api/runtime.ts

-50
This file was deleted.

src/runtime/assemble_test_cases.ts src/assemble/assemble_test_cases.ts

+36-32
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,61 @@
11
import { EventEmitter } from 'node:events'
2-
import * as messages from '@cucumber/messages'
3-
import { IdGenerator } from '@cucumber/messages'
2+
import {
3+
Envelope,
4+
IdGenerator,
5+
Pickle,
6+
TestCase,
7+
TestStep,
8+
Group as MessagesGroup,
9+
} from '@cucumber/messages'
410
import { Group } from '@cucumber/cucumber-expressions'
511
import { SupportCodeLibrary } from '../support_code_library_builder/types'
612
import { doesHaveValue } from '../value_checker'
7-
8-
export declare type IAssembledTestCases = Record<string, messages.TestCase>
9-
10-
export interface IAssembleTestCasesOptions {
11-
eventBroadcaster: EventEmitter
12-
newId: IdGenerator.NewId
13-
pickles: messages.Pickle[]
14-
supportCodeLibrary: SupportCodeLibrary
15-
}
13+
import { AssembledTestCase, SourcedPickle } from './types'
1614

1715
export async function assembleTestCases({
1816
eventBroadcaster,
1917
newId,
20-
pickles,
18+
sourcedPickles,
2119
supportCodeLibrary,
22-
}: IAssembleTestCasesOptions): Promise<IAssembledTestCases> {
23-
const result: IAssembledTestCases = {}
24-
for (const pickle of pickles) {
25-
const { id: pickleId } = pickle
20+
}: {
21+
eventBroadcaster: EventEmitter
22+
newId: IdGenerator.NewId
23+
sourcedPickles: ReadonlyArray<SourcedPickle>
24+
supportCodeLibrary: SupportCodeLibrary
25+
}): Promise<ReadonlyArray<AssembledTestCase>> {
26+
return sourcedPickles.map(({ gherkinDocument, pickle }) => {
2627
const testCaseId = newId()
27-
const fromBeforeHooks: messages.TestStep[] = makeBeforeHookSteps({
28+
const fromBeforeHooks: TestStep[] = makeBeforeHookSteps({
2829
supportCodeLibrary,
2930
pickle,
3031
newId,
3132
})
32-
const fromStepDefinitions: messages.TestStep[] = makeSteps({
33+
const fromStepDefinitions: TestStep[] = makeSteps({
3334
pickle,
3435
supportCodeLibrary,
3536
newId,
3637
})
37-
const fromAfterHooks: messages.TestStep[] = makeAfterHookSteps({
38+
const fromAfterHooks: TestStep[] = makeAfterHookSteps({
3839
supportCodeLibrary,
3940
pickle,
4041
newId,
4142
})
42-
const testCase: messages.TestCase = {
43-
pickleId,
43+
const testCase: TestCase = {
44+
pickleId: pickle.id,
4445
id: testCaseId,
4546
testSteps: [
4647
...fromBeforeHooks,
4748
...fromStepDefinitions,
4849
...fromAfterHooks,
4950
],
5051
}
51-
eventBroadcaster.emit('envelope', { testCase })
52-
result[pickleId] = testCase
53-
}
54-
return result
52+
eventBroadcaster.emit('envelope', { testCase } satisfies Envelope)
53+
return {
54+
gherkinDocument,
55+
pickle,
56+
testCase,
57+
}
58+
})
5559
}
5660

5761
function makeAfterHookSteps({
@@ -60,9 +64,9 @@ function makeAfterHookSteps({
6064
newId,
6165
}: {
6266
supportCodeLibrary: SupportCodeLibrary
63-
pickle: messages.Pickle
67+
pickle: Pickle
6468
newId: IdGenerator.NewId
65-
}): messages.TestStep[] {
69+
}): TestStep[] {
6670
return supportCodeLibrary.afterTestCaseHookDefinitions
6771
.slice(0)
6872
.reverse()
@@ -79,9 +83,9 @@ function makeBeforeHookSteps({
7983
newId,
8084
}: {
8185
supportCodeLibrary: SupportCodeLibrary
82-
pickle: messages.Pickle
86+
pickle: Pickle
8387
newId: IdGenerator.NewId
84-
}): messages.TestStep[] {
88+
}): TestStep[] {
8589
return supportCodeLibrary.beforeTestCaseHookDefinitions
8690
.filter((hookDefinition) => hookDefinition.appliesToTestCase(pickle))
8791
.map((hookDefinition) => ({
@@ -95,10 +99,10 @@ function makeSteps({
9599
supportCodeLibrary,
96100
newId,
97101
}: {
98-
pickle: messages.Pickle
102+
pickle: Pickle
99103
supportCodeLibrary: SupportCodeLibrary
100104
newId: () => string
101-
}): messages.TestStep[] {
105+
}): TestStep[] {
102106
return pickle.steps.map((pickleStep) => {
103107
const stepDefinitions = supportCodeLibrary.stepDefinitions.filter(
104108
(stepDefinition) => stepDefinition.matchesStepName(pickleStep.text)
@@ -124,7 +128,7 @@ function makeSteps({
124128
})
125129
}
126130

127-
function mapArgumentGroup(group: Group): messages.Group {
131+
function mapArgumentGroup(group: Group): MessagesGroup {
128132
return {
129133
start: group.start,
130134
value: group.value,

src/runtime/assemble_test_cases_spec.ts src/assemble/assemble_test_cases_spec.ts

+39-23
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
11
import { EventEmitter } from 'node:events'
2-
import { IdGenerator } from '@cucumber/messages'
3-
import * as messages from '@cucumber/messages'
2+
import {
3+
Envelope,
4+
GherkinDocument,
5+
IdGenerator,
6+
Pickle,
7+
TestCase,
8+
} from '@cucumber/messages'
49
import { afterEach, beforeEach, describe, it } from 'mocha'
510
import FakeTimers, { InstalledClock } from '@sinonjs/fake-timers'
611
import { expect } from 'chai'
712
import timeMethods from '../time'
813
import { buildSupportCodeLibrary } from '../../test/runtime_helpers'
914
import { parse } from '../../test/gherkin_helpers'
1015
import { SupportCodeLibrary } from '../support_code_library_builder/types'
11-
import { assembleTestCases, IAssembledTestCases } from './assemble_test_cases'
16+
import { assembleTestCases } from './assemble_test_cases'
17+
import { AssembledTestCase } from './types'
1218

13-
interface IRequest {
14-
gherkinDocument: messages.GherkinDocument
15-
pickles: messages.Pickle[]
19+
async function testAssembleTestCases({
20+
gherkinDocument,
21+
pickles,
22+
supportCodeLibrary,
23+
}: {
24+
gherkinDocument: GherkinDocument
25+
pickles: Pickle[]
1626
supportCodeLibrary: SupportCodeLibrary
17-
}
18-
19-
interface IResponse {
20-
envelopes: messages.Envelope[]
21-
result: IAssembledTestCases
22-
}
23-
24-
async function testAssembleTestCases(options: IRequest): Promise<IResponse> {
25-
const envelopes: messages.Envelope[] = []
27+
}): Promise<{
28+
envelopes: Envelope[]
29+
result: ReadonlyArray<AssembledTestCase>
30+
}> {
31+
const envelopes: Envelope[] = []
2632
const eventBroadcaster = new EventEmitter()
2733
eventBroadcaster.on('envelope', (e) => envelopes.push(e))
2834
const result = await assembleTestCases({
2935
eventBroadcaster,
3036
newId: IdGenerator.incrementing(),
31-
pickles: options.pickles,
32-
supportCodeLibrary: options.supportCodeLibrary,
37+
sourcedPickles: pickles.map((pickle) => ({ gherkinDocument, pickle })),
38+
supportCodeLibrary,
3339
})
3440
return { envelopes, result }
3541
}
@@ -71,7 +77,7 @@ describe('assembleTestCases', () => {
7177
supportCodeLibrary,
7278
})
7379

74-
const testCase1: messages.TestCase = {
80+
const testCase0: TestCase = {
7581
id: '0',
7682
pickleId: pickles[0].id,
7783
testSteps: [
@@ -88,7 +94,7 @@ describe('assembleTestCases', () => {
8894
],
8995
}
9096

91-
const testCase2: messages.TestCase = {
97+
const testCase1: TestCase = {
9298
id: '2',
9399
pickleId: pickles[1].id,
94100
testSteps: [
@@ -108,15 +114,25 @@ describe('assembleTestCases', () => {
108114
// Assert
109115
expect(envelopes).to.eql([
110116
{
111-
testCase: testCase1,
117+
testCase: testCase0,
112118
},
113119
{
114-
testCase: testCase2,
120+
testCase: testCase1,
115121
},
116122
])
117123

118-
expect(Object.keys(result)).to.eql([pickles[0].id, pickles[1].id])
119-
expect(Object.values(result)).to.eql([testCase1, testCase2])
124+
expect(result).to.eql([
125+
{
126+
gherkinDocument,
127+
pickle: pickles[0],
128+
testCase: testCase0,
129+
},
130+
{
131+
gherkinDocument,
132+
pickle: pickles[1],
133+
testCase: testCase1,
134+
},
135+
])
120136
})
121137

122138
describe('with a parameterised step', () => {

src/assemble/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './assemble_test_cases'
2+
export * from './types'

src/assemble/types.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { GherkinDocument, Pickle, TestCase } from '@cucumber/messages'
2+
3+
export interface SourcedPickle {
4+
gherkinDocument: GherkinDocument
5+
pickle: Pickle
6+
}
7+
8+
export interface AssembledTestCase {
9+
gherkinDocument: GherkinDocument
10+
pickle: Pickle
11+
testCase: TestCase
12+
}

src/formatter/helpers/summary_helpers_spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import { getTestCaseAttempts } from '../../../test/formatter_helpers'
88
import { getBaseSupportCodeLibrary } from '../../../test/fixtures/steps'
99
import timeMethods, { durationBetweenTimestamps } from '../../time'
1010
import { buildSupportCodeLibrary } from '../../../test/runtime_helpers'
11-
import { IRuntimeOptions } from '../../runtime'
11+
import { RuntimeOptions } from '../../runtime'
1212
import { SupportCodeLibrary } from '../../support_code_library_builder/types'
1313
import { doesNotHaveValue } from '../../value_checker'
1414
import { formatSummary } from './summary_helpers'
1515

1616
interface ITestFormatSummaryOptions {
17-
runtimeOptions?: Partial<IRuntimeOptions>
17+
runtimeOptions?: Partial<RuntimeOptions>
1818
sourceData: string
1919
supportCodeLibrary?: SupportCodeLibrary
2020
testRunStarted?: messages.TestRunStarted

0 commit comments

Comments
 (0)