Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

format: report total steps correctly in progress bar #1669

Merged
merged 27 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f996c38
make cck fail: remove reordering of testCase messages
davidjgoss Mar 14, 2021
457d8f0
add new function to deal with testCase
davidjgoss Mar 14, 2021
594c326
dont emit testCase from PickleRunner
davidjgoss Mar 14, 2021
4eaf49f
include in result
davidjgoss Mar 30, 2021
68aaffe
fix up some tests
davidjgoss Mar 30, 2021
b688236
move tests to right places
davidjgoss Mar 30, 2021
b4b9ab5
Merge remote-tracking branch 'origin/main' into prog-bar-counts
davidjgoss May 8, 2021
62fb8ec
emit test cases from serial runtime
davidjgoss May 9, 2021
8c422d6
scrappy impl to get serial working
davidjgoss May 9, 2021
70bc318
remove unused field
davidjgoss May 9, 2021
549f26a
refactor structures, fix tests
davidjgoss May 9, 2021
f6a22be
make coordinator api more promisey
davidjgoss May 9, 2021
470e722
start to hook up parallel
davidjgoss May 9, 2021
e569423
merge main
davidjgoss May 29, 2021
1dcd586
assemble test cases without ITestStep
davidjgoss May 29, 2021
ab6d763
remove unused function
davidjgoss May 29, 2021
753becf
TestCase is source of truth
davidjgoss May 29, 2021
31be160
TestCaseRunner is more accurate than PickleRunner?
davidjgoss May 29, 2021
1c8228b
make parallel runtime work with this
davidjgoss May 29, 2021
e8fe377
Merge remote-tracking branch 'origin/main' into prog-bar-counts
davidjgoss May 29, 2021
b79d082
add explanatory comment
davidjgoss May 29, 2021
a63e184
fix progress bar formatter counts
davidjgoss May 29, 2021
9d5bc68
changelog
davidjgoss May 29, 2021
e5104db
remove temp tag
davidjgoss May 31, 2021
7a9893c
clarify changelog entry audience
davidjgoss May 31, 2021
ecb0631
cleanup
davidjgoss May 31, 2021
d9d6a51
Merge branch 'main' into prog-bar-counts
aurelien-reeves Jun 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO

### Changed

* All `testCase` messages now emitted upfront at the start of the run (relevant for formatter authors) ([#1408](https://github.com/cucumber/cucumber-js/issues/1408)
[#1669](https://github.com/cucumber/cucumber-js/pull/1669))
* Clarify that the JSON formatter will not be removed any time soon

### Deprecated
Expand All @@ -24,6 +26,8 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO

### Fixed

* Progress bar formatter now reports total step count correctly ([#1579](https://github.com/cucumber/cucumber-js/issues/1579)
[#1669](https://github.com/cucumber/cucumber-js/pull/1669))
* All messages now emitted with project-relative `uri`s
([#1534](https://github.com/cucumber/cucumber-js/issues/1534)
[#1672](https://github.com/cucumber/cucumber-js/pull/1672))
Expand Down
14 changes: 1 addition & 13 deletions compatibility/cck_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import path from 'path'
import { PassThrough, pipeline, Writable } from 'stream'
import { Cli } from '../src'
import toString from 'stream-to-string'
import { doesHaveValue, doesNotHaveValue } from '../src/value_checker'
import { normalizeMessageOutput } from '../features/support/formatter_output_helpers'
import * as messages from '@cucumber/messages'
import * as messageStreams from '@cucumber/message-streams'
Expand Down Expand Up @@ -103,16 +102,5 @@ function normalize(messages: any[]): any[] {
messages,
path.join(PROJECT_PATH, 'compatibility')
)
const testCases: any[] = messages.filter((message) =>
doesHaveValue(message.testCase)
)
const everythingElse: any[] = messages.filter((message) =>
doesNotHaveValue(message.testCase)
)
const testRunStarted = everythingElse.findIndex((message) =>
doesHaveValue(message.testRunStarted)
)
// move all `testCase` messages to just after `testRunStarted`
everythingElse.splice(testRunStarted + 1, 0, ...testCases)
return everythingElse
return messages
}
8 changes: 2 additions & 6 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,17 +228,13 @@ export default class Cli {
eventBroadcaster,
eventDataCollector,
options: configuration.runtimeOptions,
newId,
pickleIds,
supportCodeLibrary,
supportCodePaths: configuration.supportCodePaths,
supportCodeRequiredModules: configuration.supportCodeRequiredModules,
})
await new Promise<void>((resolve) => {
parallelRuntimeCoordinator.run(configuration.parallel, (s) => {
success = s
resolve()
})
})
success = await parallelRuntimeCoordinator.run(configuration.parallel)
} else {
const runtime = new Runtime({
eventBroadcaster,
Expand Down
4 changes: 2 additions & 2 deletions src/formatter/progress_bar_formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ export default class ProgressBarFormatter extends Formatter {
parseEnvelope(envelope: messages.Envelope): void {
if (doesHaveValue(envelope.undefinedParameterType)) {
this.logUndefinedParametertype(envelope.undefinedParameterType)
} else if (doesHaveValue(envelope.pickle)) {
this.incrementStepCount(envelope.pickle.id)
} else if (doesHaveValue(envelope.testCase)) {
this.incrementStepCount(envelope.testCase.pickleId)
} else if (doesHaveValue(envelope.testStepStarted)) {
this.initializeProgressBar()
} else if (doesHaveValue(envelope.testStepFinished)) {
Expand Down
29 changes: 29 additions & 0 deletions src/formatter/progress_bar_formatter_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface ITestProgressBarFormatterOptions {
shouldStopFn: (envelope: messages.Envelope) => boolean
sources?: ITestSource[]
supportCodeLibrary?: ISupportCodeLibrary
pickleFilter?: (pickle: messages.Pickle) => boolean
}

interface ITestProgressBarFormatterOutput {
Expand All @@ -39,6 +40,7 @@ async function testProgressBarFormatter({
shouldStopFn,
sources,
supportCodeLibrary,
pickleFilter = () => true,
}: ITestProgressBarFormatterOptions): Promise<ITestProgressBarFormatterOutput> {
if (doesNotHaveValue(supportCodeLibrary)) {
supportCodeLibrary = buildSupportCodeLibrary()
Expand All @@ -48,6 +50,7 @@ async function testProgressBarFormatter({
runtimeOptions,
sources,
supportCodeLibrary,
pickleFilter,
})

let output = ''
Expand Down Expand Up @@ -137,6 +140,32 @@ describe('ProgressBarFormatter', () => {
// Assert
expect(progressBarFormatter.progressBar.total).to.eql(5)
})

it('initializes a progress bar with the total number of steps when some pickles filtered out', async () => {
// Arrange
const sources = [
{
data: '@yep\nFeature: a\nScenario: b\nGiven a step\nThen a step',
uri: 'a.feature',
},
{
data:
'Feature: a\nScenario: b\nGiven a step\nWhen a step\nThen a step',
uri: 'b.feature',
},
]

// Act
const { progressBarFormatter } = await testProgressBarFormatter({
shouldStopFn: (envelope) => doesHaveValue(envelope.testStepStarted),
sources,
pickleFilter: (pickle) =>
pickle.tags.some((tag) => tag.name === '@yep'),
})

// Assert
expect(progressBarFormatter.progressBar.total).to.eql(2)
})
})

describe('testStepFinished', () => {
Expand Down
135 changes: 135 additions & 0 deletions src/runtime/assemble_test_cases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { EventEmitter } from 'events'
import * as messages from '@cucumber/messages'
import { IdGenerator } from '@cucumber/messages'
import { ISupportCodeLibrary } from '../support_code_library_builder/types'
import { Group } from '@cucumber/cucumber-expressions'
import { doesHaveValue } from '../value_checker'
import { clone } from 'lodash'

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

export interface IAssembleTestCasesOptions {
eventBroadcaster: EventEmitter
newId: IdGenerator.NewId
pickles: messages.Pickle[]
supportCodeLibrary: ISupportCodeLibrary
}

export async function assembleTestCases({
eventBroadcaster,
newId,
pickles,
supportCodeLibrary,
}: IAssembleTestCasesOptions): Promise<IAssembledTestCases> {
const result: IAssembledTestCases = {}
for (const pickle of pickles) {
const { id: pickleId } = pickle
const testCaseId = newId()
const fromBeforeHooks: messages.TestStep[] = makeBeforeHookSteps({
supportCodeLibrary,
pickle,
newId,
})
const fromStepDefinitions: messages.TestStep[] = makeSteps({
pickle,
supportCodeLibrary,
newId,
})
const fromAfterHooks: messages.TestStep[] = makeAfterHookSteps({
supportCodeLibrary,
pickle,
newId,
})
const testCase: messages.TestCase = {
pickleId,
id: testCaseId,
testSteps: [
...fromBeforeHooks,
...fromStepDefinitions,
...fromAfterHooks,
],
}
eventBroadcaster.emit('envelope', { testCase })
result[pickleId] = testCase
}
return result
}

function makeAfterHookSteps({
supportCodeLibrary,
pickle,
newId,
}: {
supportCodeLibrary: ISupportCodeLibrary
pickle: messages.Pickle
newId: IdGenerator.NewId
}): messages.TestStep[] {
return clone(supportCodeLibrary.afterTestCaseHookDefinitions)
.reverse()
.filter((hookDefinition) => hookDefinition.appliesToTestCase(pickle))
.map((hookDefinition) => ({
id: newId(),
hookId: hookDefinition.id,
}))
}

function makeBeforeHookSteps({
supportCodeLibrary,
pickle,
newId,
}: {
supportCodeLibrary: ISupportCodeLibrary
pickle: messages.Pickle
newId: IdGenerator.NewId
}): messages.TestStep[] {
return supportCodeLibrary.beforeTestCaseHookDefinitions
.filter((hookDefinition) => hookDefinition.appliesToTestCase(pickle))
.map((hookDefinition) => ({
id: newId(),
hookId: hookDefinition.id,
}))
}

function makeSteps({
pickle,
supportCodeLibrary,
newId,
}: {
pickle: messages.Pickle
supportCodeLibrary: ISupportCodeLibrary
newId: () => string
}): messages.TestStep[] {
return pickle.steps.map((pickleStep) => {
const stepDefinitions = supportCodeLibrary.stepDefinitions.filter(
(stepDefinition) => stepDefinition.matchesStepName(pickleStep.text)
)
return {
id: newId(),
pickleStepId: pickleStep.id,
stepDefinitionIds: stepDefinitions.map(
(stepDefinition) => stepDefinition.id
),
stepMatchArgumentsLists: stepDefinitions.map((stepDefinition) => {
const result = stepDefinition.expression.match(pickleStep.text)
return {
stepMatchArguments: result.map((arg) => {
return {
group: mapArgumentGroup(arg.group),
parameterTypeName: arg.parameterType.name,
}
}),
}
}),
}
})
}

function mapArgumentGroup(group: Group): messages.Group {
return {
start: group.start,
value: group.value,
children: doesHaveValue(group.children)
? group.children.map((child) => mapArgumentGroup(child))
: undefined,
}
}
Loading