Skip to content

Commit 4c33d8b

Browse files
committed
output steps
1 parent 7981c70 commit 4c33d8b

File tree

6 files changed

+150
-19
lines changed

6 files changed

+150
-19
lines changed

javascript/package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

javascript/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"dependencies": {
2323
"@cucumber/gherkin-utils": "^9.0.0",
2424
"@cucumber/query": "^12.2.0",
25+
"@teppeis/multimaps": "^3.0.0",
2526
"xmlbuilder": "^15.1.1"
2627
},
2728
"devDependencies": {

javascript/src/ExtendedQuery.ts

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,56 @@ import * as assert from 'node:assert'
22

33
import {
44
Envelope,
5+
Feature,
56
getWorstTestStepResult,
7+
GherkinDocument,
68
Pickle,
9+
PickleStep,
10+
Step,
711
TestCase,
812
TestCaseFinished,
913
TestCaseStarted,
1014
TestRunFinished,
1115
TestRunStarted,
16+
TestStep,
17+
TestStepFinished,
1218
TestStepResultStatus,
1319
TimeConversion,
1420
} from '@cucumber/messages'
15-
import { Query as CucumberQuery } from '@cucumber/query'
21+
import { ArrayMultimap } from '@teppeis/multimaps'
1622

17-
export class ExtendedQuery extends CucumberQuery {
23+
export class ExtendedQuery {
1824
private testRunStarted: TestRunStarted
1925
private testRunFinished: TestRunFinished
2026
private testCaseStarted: Array<TestCaseStarted> = []
27+
private readonly stepById: Map<string, Step> = new Map()
2128
private readonly pickleById: Map<string, Pickle> = new Map()
29+
private readonly pickleStepById: Map<string, PickleStep> = new Map()
2230
private readonly testCaseById: Map<string, TestCase> = new Map()
31+
private readonly testStepById: Map<string, TestStep> = new Map()
2332
private readonly testCaseFinishedByTestCaseStartedId: Map<string, TestCaseFinished> = new Map()
33+
private readonly testStepFinishedByTestCaseStartedId: ArrayMultimap<string, TestStepFinished> =
34+
new ArrayMultimap()
2435

2536
update(envelope: Envelope) {
26-
super.update(envelope)
27-
37+
if (envelope.gherkinDocument) {
38+
this.updateGherkinDocument(envelope.gherkinDocument)
39+
}
2840
if (envelope.pickle) {
29-
this.pickleById.set(envelope.pickle.id, envelope.pickle)
41+
this.updatePickle(envelope.pickle)
3042
}
3143
if (envelope.testRunStarted) {
3244
this.testRunStarted = envelope.testRunStarted
3345
}
3446
if (envelope.testCase) {
35-
this.testCaseById.set(envelope.testCase.id, envelope.testCase)
47+
this.updateTestCase(envelope.testCase)
3648
}
3749
if (envelope.testCaseStarted) {
3850
this.updateTestCaseStarted(envelope.testCaseStarted)
3951
}
52+
if (envelope.testStepFinished) {
53+
this.updateTestStepFinished(envelope.testStepFinished)
54+
}
4055
if (envelope.testCaseFinished) {
4156
this.updateTestCaseFinished(envelope.testCaseFinished)
4257
}
@@ -45,6 +60,47 @@ export class ExtendedQuery extends CucumberQuery {
4560
}
4661
}
4762

63+
private updateGherkinDocument(gherkinDocument: GherkinDocument) {
64+
if (gherkinDocument.feature) {
65+
this.updateFeature(gherkinDocument.feature)
66+
}
67+
}
68+
69+
private updateFeature(feature: Feature) {
70+
feature.children.forEach((featureChild) => {
71+
if (featureChild.background) {
72+
this.updateSteps(featureChild.background.steps)
73+
}
74+
if (featureChild.scenario) {
75+
this.updateSteps(featureChild.scenario.steps)
76+
}
77+
if (featureChild.rule) {
78+
featureChild.rule.children.forEach((ruleChild) => {
79+
if (ruleChild.background) {
80+
this.updateSteps(ruleChild.background.steps)
81+
}
82+
if (ruleChild.scenario) {
83+
this.updateSteps(ruleChild.scenario.steps)
84+
}
85+
})
86+
}
87+
})
88+
}
89+
90+
private updateSteps(steps: ReadonlyArray<Step>) {
91+
steps.forEach((step) => this.stepById.set(step.id, step))
92+
}
93+
94+
private updatePickle(pickle: Pickle) {
95+
this.pickleById.set(pickle.id, pickle)
96+
pickle.steps.forEach((pickleStep) => this.pickleStepById.set(pickleStep.id, pickleStep))
97+
}
98+
99+
private updateTestCase(testCase: TestCase) {
100+
this.testCaseById.set(testCase.id, testCase)
101+
testCase.testSteps.forEach((testStep) => this.testStepById.set(testStep.id, testStep))
102+
}
103+
48104
private updateTestCaseStarted(testCaseStarted: TestCaseStarted) {
49105
// ensure this replaces any previous attempt for the same test case
50106
this.testCaseStarted = [
@@ -55,13 +111,26 @@ export class ExtendedQuery extends CucumberQuery {
55111
]
56112
}
57113

114+
private updateTestStepFinished(testStepFinished: TestStepFinished) {
115+
this.testStepFinishedByTestCaseStartedId.put(
116+
testStepFinished.testCaseStartedId,
117+
testStepFinished
118+
)
119+
}
120+
58121
private updateTestCaseFinished(testCaseFinished: TestCaseFinished) {
59122
this.testCaseFinishedByTestCaseStartedId.set(
60123
testCaseFinished.testCaseStartedId,
61124
testCaseFinished
62125
)
63126
}
64127

128+
findStepBy(pickleStep: PickleStep) {
129+
const [astNodeId] = pickleStep.astNodeIds
130+
assert.ok('Expected PickleStep to have an astNodeId')
131+
return this.stepById.get(astNodeId)
132+
}
133+
65134
findPickleBy(testCaseStarted: TestCaseStarted) {
66135
const testCase = this.findTestCaseBy(testCaseStarted)
67136
if (!testCase) {
@@ -70,6 +139,11 @@ export class ExtendedQuery extends CucumberQuery {
70139
return this.pickleById.get(testCase.pickleId)
71140
}
72141

142+
findPickleStepBy(testStep: TestStep) {
143+
assert.ok(testStep.pickleStepId, 'Expected TestStep to have a pickleStepId')
144+
return this.pickleStepById.get(testStep.pickleStepId)
145+
}
146+
73147
findAllTestCaseStarted(): ReadonlyArray<TestCaseStarted> {
74148
return [...this.testCaseStarted]
75149
}
@@ -93,6 +167,22 @@ export class ExtendedQuery extends CucumberQuery {
93167
)
94168
}
95169

170+
findTestStepBy(testStepFinished: TestStepFinished) {
171+
return this.testStepById.get(testStepFinished.testStepId)
172+
}
173+
174+
findTestStepFinishedAndTestStepBy(
175+
testCaseStarted: TestCaseStarted
176+
): ReadonlyArray<[TestStepFinished, TestStep]> {
177+
return this.testStepFinishedByTestCaseStartedId
178+
.get(testCaseStarted.id)
179+
.map((testStepFinished) => {
180+
const testStep = this.findTestStepBy(testStepFinished)
181+
assert.ok(testStep, 'Expected to find TestStep by TestStepFinished')
182+
return [testStepFinished, testStep]
183+
})
184+
}
185+
96186
findTestRunDuration() {
97187
if (!this.testRunStarted || !this.testRunFinished) {
98188
return undefined
@@ -114,13 +204,11 @@ export class ExtendedQuery extends CucumberQuery {
114204
[TestStepResultStatus.UNKNOWN]: 0,
115205
}
116206
for (const testCaseStarted of this.testCaseStarted) {
117-
const testCase = this.findTestCaseBy(testCaseStarted)
118-
assert.ok(testCase, 'Expected to find TestCase for TestCaseStarted')
119-
const statusesFromSteps = testCase.testSteps.map((testStep) => {
120-
return getWorstTestStepResult(this.getTestStepResults(testStep.id))
121-
})
122-
const overallStatus = getWorstTestStepResult(statusesFromSteps)
123-
result[overallStatus.status]++
207+
const testStepResults = this.findTestStepFinishedAndTestStepBy(testCaseStarted).map(
208+
([testStepFinished]) => testStepFinished.testStepResult
209+
)
210+
const mostSevereResult = getWorstTestStepResult(testStepResults)
211+
result[mostSevereResult.status]++
124212
}
125213
return result
126214
}

javascript/src/helpers.spec.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { TestStepResultStatus } from '@cucumber/messages'
1+
import { PickleStep, Step, TestStepResultStatus } from '@cucumber/messages'
22
import { expect, use } from 'chai'
33
import chaiAlmost from 'chai-almost'
44

5-
import { countStatuses, durationToSeconds } from './helpers.js'
5+
import { countStatuses, durationToSeconds, formatStep } from './helpers.js'
66

77
use(chaiAlmost())
88

@@ -43,4 +43,16 @@ describe('helpers', () => {
4343
)
4444
})
4545
})
46+
47+
describe('formatStep', () => {
48+
it('formats a step', () => {
49+
expect(
50+
formatStep(
51+
{ keyword: 'Given ' } as Step,
52+
{ text: 'I have 42 cukes in my belly' } as PickleStep,
53+
TestStepResultStatus.PASSED
54+
)
55+
).to.eq('Given I have 42 cukes in my belly...........................................passed')
56+
})
57+
})
4658
})

javascript/src/helpers.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { Duration, TestStepResultStatus, TimeConversion } from '@cucumber/messages'
1+
import {
2+
Duration,
3+
PickleStep,
4+
Step,
5+
TestStepResultStatus,
6+
TimeConversion,
7+
} from '@cucumber/messages'
28

39
export function durationToSeconds(duration?: Duration) {
410
if (!duration) {
@@ -15,3 +21,11 @@ export function countStatuses(
1521
.filter(([status]) => predicate(status as TestStepResultStatus))
1622
.reduce((prev, [, curr]) => prev + curr, 0)
1723
}
24+
25+
export function formatStep(step: Step, pickleStep: PickleStep, status: TestStepResultStatus) {
26+
let text = `${step.keyword.trim()} ${pickleStep.text.trim()}.`
27+
do {
28+
text += '.'
29+
} while (text.length < 76)
30+
return text + status.toLowerCase()
31+
}

javascript/src/index.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import * as assert from 'node:assert'
2+
13
import { Query as GherkinQuery } from '@cucumber/gherkin-utils'
2-
import { Envelope, TestCaseStarted, TestStepResultStatus } from '@cucumber/messages'
4+
import { Envelope, TestStepResultStatus } from '@cucumber/messages'
35
import xmlbuilder from 'xmlbuilder'
46

57
import { ExtendedQuery } from './ExtendedQuery.js'
6-
import { countStatuses, durationToSeconds } from './helpers.js'
7-
import * as assert from 'node:assert'
8+
import { countStatuses, durationToSeconds, formatStep } from './helpers.js'
89

910
export default {
1011
type: 'formatter',
@@ -39,6 +40,7 @@ export default {
3940
name: testCase.name,
4041
time: testCase.time,
4142
})
43+
element.ele('system-out', {}).cdata(testCase.output)
4244
}
4345

4446
write(builder.end({ pretty: true }))
@@ -60,6 +62,7 @@ interface TestCase {
6062
classname: string
6163
name: string
6264
time: number
65+
output: string
6366
}
6467

6568
function makeReport(query: ExtendedQuery): Report {
@@ -85,6 +88,18 @@ function makeTestCases(query: ExtendedQuery): ReadonlyArray<TestCase> {
8588
classname: pickle.uri,
8689
name: pickle.name,
8790
time: durationToSeconds(query.findTestCaseDurationBy(testCaseStarted)),
91+
output: query
92+
.findTestStepFinishedAndTestStepBy(testCaseStarted)
93+
// filter out hooks
94+
.filter(([, testStep]) => !!testStep.pickleStepId)
95+
.map(([testStepFinished, testStep]) => {
96+
const pickleStep = query.findPickleStepBy(testStep)
97+
assert.ok(pickleStep, 'Expected to find PickleStep by TestStep')
98+
const gherkinStep = query.findStepBy(pickleStep)
99+
assert.ok(gherkinStep, 'Expected to find Step by PickleStep')
100+
return formatStep(gherkinStep, pickleStep, testStepFinished.testStepResult.status)
101+
})
102+
.join('\n'),
88103
}
89104
})
90105
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy