Skip to content

Commit

Permalink
Consolidate serial and parallel runtimes (#2422)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidjgoss authored Aug 25, 2024
1 parent aa3ce7b commit d357150
Show file tree
Hide file tree
Showing 31 changed files with 731 additions and 759 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Please see [CONTRIBUTING.md](./CONTRIBUTING.md) on how to contribute to Cucumber.

## [Unreleased]
### Changed
- Major refactor of runtime code for both serial and parallel modes ([#2422](https://github.com/cucumber/cucumber-js/pull/2422))

### Removed
- BREAKING CHANGE: Remove previously-deprecated `parseGherkinMessageStream` ([#2420](https://github.com/cucumber/cucumber-js/pull/2420))
- BREAKING CHANGE: Remove previously-deprecated `PickleFilter` ([#2420](https://github.com/cucumber/cucumber-js/pull/2420))
Expand Down
19 changes: 9 additions & 10 deletions src/api/run_cucumber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { emitMetaMessage, emitSupportCodeMessages } from '../cli/helpers'
import { resolvePaths } from '../paths'
import { SupportCodeLibrary } from '../support_code_library_builder/types'
import { version } from '../version'
import { IFilterablePickle } from '../filter'
import { makeRuntime } from '../runtime'
import { IRunOptions, IRunEnvironment, IRunResult } from './types'
import { makeRuntime } from './runtime'
import { initializeFormatters } from './formatters'
import { getSupportCodeLibrary } from './support'
import { mergeEnvironment } from './environment'
Expand Down Expand Up @@ -105,7 +106,7 @@ Running from: ${__dirname}
})
await emitMetaMessage(eventBroadcaster, env)

let pickleIds: string[] = []
let filteredPickles: ReadonlyArray<IFilterablePickle> = []
let parseErrors: ParseError[] = []
if (sourcePaths.length > 0) {
const gherkinResult = await getPicklesAndErrors({
Expand All @@ -115,15 +116,14 @@ Running from: ${__dirname}
coordinates: options.sources,
onEnvelope: (envelope) => eventBroadcaster.emit('envelope', envelope),
})
const filteredPickles = await pluginManager.transform(
filteredPickles = await pluginManager.transform(
'pickles:filter',
gherkinResult.filterablePickles
)
const orderedPickles = await pluginManager.transform(
filteredPickles = await pluginManager.transform(
'pickles:order',
filteredPickles
)
pickleIds = orderedPickles.map(({ pickle }) => pickle.id)
parseErrors = gherkinResult.parseErrors
}
if (parseErrors.length) {
Expand All @@ -146,17 +146,16 @@ Running from: ${__dirname}
newId,
})

const runtime = makeRuntime({
cwd,
const runtime = await makeRuntime({
environment,
logger,
eventBroadcaster,
eventDataCollector,
pickleIds,
sourcedPickles: filteredPickles,
newId,
supportCodeLibrary,
options: options.runtime,
})
const success = await runtime.start()
const success = await runtime.run()
await pluginManager.cleanup()
await cleanupFormatters()

Expand Down
50 changes: 0 additions & 50 deletions src/api/runtime.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,57 +1,61 @@
import { EventEmitter } from 'node:events'
import * as messages from '@cucumber/messages'
import { IdGenerator } from '@cucumber/messages'
import {
Envelope,
IdGenerator,
Pickle,
TestCase,
TestStep,
Group as MessagesGroup,
} from '@cucumber/messages'
import { Group } from '@cucumber/cucumber-expressions'
import { SupportCodeLibrary } from '../support_code_library_builder/types'
import { doesHaveValue } from '../value_checker'

export declare type IAssembledTestCases = Record<string, messages.TestCase>

export interface IAssembleTestCasesOptions {
eventBroadcaster: EventEmitter
newId: IdGenerator.NewId
pickles: messages.Pickle[]
supportCodeLibrary: SupportCodeLibrary
}
import { AssembledTestCase, SourcedPickle } from './types'

export async function assembleTestCases({
eventBroadcaster,
newId,
pickles,
sourcedPickles,
supportCodeLibrary,
}: IAssembleTestCasesOptions): Promise<IAssembledTestCases> {
const result: IAssembledTestCases = {}
for (const pickle of pickles) {
const { id: pickleId } = pickle
}: {
eventBroadcaster: EventEmitter
newId: IdGenerator.NewId
sourcedPickles: ReadonlyArray<SourcedPickle>
supportCodeLibrary: SupportCodeLibrary
}): Promise<ReadonlyArray<AssembledTestCase>> {
return sourcedPickles.map(({ gherkinDocument, pickle }) => {
const testCaseId = newId()
const fromBeforeHooks: messages.TestStep[] = makeBeforeHookSteps({
const fromBeforeHooks: TestStep[] = makeBeforeHookSteps({
supportCodeLibrary,
pickle,
newId,
})
const fromStepDefinitions: messages.TestStep[] = makeSteps({
const fromStepDefinitions: TestStep[] = makeSteps({
pickle,
supportCodeLibrary,
newId,
})
const fromAfterHooks: messages.TestStep[] = makeAfterHookSteps({
const fromAfterHooks: TestStep[] = makeAfterHookSteps({
supportCodeLibrary,
pickle,
newId,
})
const testCase: messages.TestCase = {
pickleId,
const testCase: TestCase = {
pickleId: pickle.id,
id: testCaseId,
testSteps: [
...fromBeforeHooks,
...fromStepDefinitions,
...fromAfterHooks,
],
}
eventBroadcaster.emit('envelope', { testCase })
result[pickleId] = testCase
}
return result
eventBroadcaster.emit('envelope', { testCase } satisfies Envelope)
return {
gherkinDocument,
pickle,
testCase,
}
})
}

function makeAfterHookSteps({
Expand All @@ -60,9 +64,9 @@ function makeAfterHookSteps({
newId,
}: {
supportCodeLibrary: SupportCodeLibrary
pickle: messages.Pickle
pickle: Pickle
newId: IdGenerator.NewId
}): messages.TestStep[] {
}): TestStep[] {
return supportCodeLibrary.afterTestCaseHookDefinitions
.slice(0)
.reverse()
Expand All @@ -79,9 +83,9 @@ function makeBeforeHookSteps({
newId,
}: {
supportCodeLibrary: SupportCodeLibrary
pickle: messages.Pickle
pickle: Pickle
newId: IdGenerator.NewId
}): messages.TestStep[] {
}): TestStep[] {
return supportCodeLibrary.beforeTestCaseHookDefinitions
.filter((hookDefinition) => hookDefinition.appliesToTestCase(pickle))
.map((hookDefinition) => ({
Expand All @@ -95,10 +99,10 @@ function makeSteps({
supportCodeLibrary,
newId,
}: {
pickle: messages.Pickle
pickle: Pickle
supportCodeLibrary: SupportCodeLibrary
newId: () => string
}): messages.TestStep[] {
}): TestStep[] {
return pickle.steps.map((pickleStep) => {
const stepDefinitions = supportCodeLibrary.stepDefinitions.filter(
(stepDefinition) => stepDefinition.matchesStepName(pickleStep.text)
Expand All @@ -124,7 +128,7 @@ function makeSteps({
})
}

function mapArgumentGroup(group: Group): messages.Group {
function mapArgumentGroup(group: Group): MessagesGroup {
return {
start: group.start,
value: group.value,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
import { EventEmitter } from 'node:events'
import { IdGenerator } from '@cucumber/messages'
import * as messages from '@cucumber/messages'
import {
Envelope,
GherkinDocument,
IdGenerator,
Pickle,
TestCase,
} from '@cucumber/messages'
import { afterEach, beforeEach, describe, it } from 'mocha'
import FakeTimers, { InstalledClock } from '@sinonjs/fake-timers'
import { expect } from 'chai'
import timeMethods from '../time'
import { buildSupportCodeLibrary } from '../../test/runtime_helpers'
import { parse } from '../../test/gherkin_helpers'
import { SupportCodeLibrary } from '../support_code_library_builder/types'
import { assembleTestCases, IAssembledTestCases } from './assemble_test_cases'
import { assembleTestCases } from './assemble_test_cases'
import { AssembledTestCase } from './types'

interface IRequest {
gherkinDocument: messages.GherkinDocument
pickles: messages.Pickle[]
async function testAssembleTestCases({
gherkinDocument,
pickles,
supportCodeLibrary,
}: {
gherkinDocument: GherkinDocument
pickles: Pickle[]
supportCodeLibrary: SupportCodeLibrary
}

interface IResponse {
envelopes: messages.Envelope[]
result: IAssembledTestCases
}

async function testAssembleTestCases(options: IRequest): Promise<IResponse> {
const envelopes: messages.Envelope[] = []
}): Promise<{
envelopes: Envelope[]
result: ReadonlyArray<AssembledTestCase>
}> {
const envelopes: Envelope[] = []
const eventBroadcaster = new EventEmitter()
eventBroadcaster.on('envelope', (e) => envelopes.push(e))
const result = await assembleTestCases({
eventBroadcaster,
newId: IdGenerator.incrementing(),
pickles: options.pickles,
supportCodeLibrary: options.supportCodeLibrary,
sourcedPickles: pickles.map((pickle) => ({ gherkinDocument, pickle })),
supportCodeLibrary,
})
return { envelopes, result }
}
Expand Down Expand Up @@ -71,7 +77,7 @@ describe('assembleTestCases', () => {
supportCodeLibrary,
})

const testCase1: messages.TestCase = {
const testCase0: TestCase = {
id: '0',
pickleId: pickles[0].id,
testSteps: [
Expand All @@ -88,7 +94,7 @@ describe('assembleTestCases', () => {
],
}

const testCase2: messages.TestCase = {
const testCase1: TestCase = {
id: '2',
pickleId: pickles[1].id,
testSteps: [
Expand All @@ -108,15 +114,25 @@ describe('assembleTestCases', () => {
// Assert
expect(envelopes).to.eql([
{
testCase: testCase1,
testCase: testCase0,
},
{
testCase: testCase2,
testCase: testCase1,
},
])

expect(Object.keys(result)).to.eql([pickles[0].id, pickles[1].id])
expect(Object.values(result)).to.eql([testCase1, testCase2])
expect(result).to.eql([
{
gherkinDocument,
pickle: pickles[0],
testCase: testCase0,
},
{
gherkinDocument,
pickle: pickles[1],
testCase: testCase1,
},
])
})

describe('with a parameterised step', () => {
Expand Down
2 changes: 2 additions & 0 deletions src/assemble/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './assemble_test_cases'
export * from './types'
12 changes: 12 additions & 0 deletions src/assemble/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { GherkinDocument, Pickle, TestCase } from '@cucumber/messages'

export interface SourcedPickle {
gherkinDocument: GherkinDocument
pickle: Pickle
}

export interface AssembledTestCase {
gherkinDocument: GherkinDocument
pickle: Pickle
testCase: TestCase
}
4 changes: 2 additions & 2 deletions src/formatter/helpers/summary_helpers_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { getTestCaseAttempts } from '../../../test/formatter_helpers'
import { getBaseSupportCodeLibrary } from '../../../test/fixtures/steps'
import timeMethods, { durationBetweenTimestamps } from '../../time'
import { buildSupportCodeLibrary } from '../../../test/runtime_helpers'
import { IRuntimeOptions } from '../../runtime'
import { RuntimeOptions } from '../../runtime'
import { SupportCodeLibrary } from '../../support_code_library_builder/types'
import { doesNotHaveValue } from '../../value_checker'
import { formatSummary } from './summary_helpers'

interface ITestFormatSummaryOptions {
runtimeOptions?: Partial<IRuntimeOptions>
runtimeOptions?: Partial<RuntimeOptions>
sourceData: string
supportCodeLibrary?: SupportCodeLibrary
testRunStarted?: messages.TestRunStarted
Expand Down
Loading

0 comments on commit d357150

Please sign in to comment.