Skip to content

Commit f4795ef

Browse files
committed
Report failing steps with correct duration
This fixes #963 [1]. [1] #963
1 parent 3569210 commit f4795ef

File tree

4 files changed

+95
-11
lines changed

4 files changed

+95
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
66

77
- Add BeforeStep and AfterStep hooks, fixes [#847](https://github.com/badeball/cypress-cucumber-preprocessor/issues/847).
88

9+
- Report failing steps with correct duration, fixes [#963](https://github.com/badeball/cypress-cucumber-preprocessor/issues/963).
10+
911
## v17.1.1
1012

1113
- Allow generation of JSON reports with hooks (After / Before) even if `baseUrl` is undefined, fixes [#1017](https://github.com/badeball/cypress-cucumber-preprocessor/issues/1017).

features/issues/963.feature

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# https://github.com/badeball/cypress-cucumber-preprocessor/issues/963
2+
3+
Feature: message timestamps
4+
Scenario: failing step
5+
Given additional preprocessor configuration
6+
"""
7+
{
8+
"messages": {
9+
"enabled": true
10+
}
11+
}
12+
"""
13+
And a file named "cypress/e2e/a.feature" with:
14+
"""
15+
Feature: a feature
16+
Scenario: a scenario
17+
Given a failing step
18+
"""
19+
And a file named "cypress/support/step_definitions/steps.js" with:
20+
"""
21+
const { Given } = require("@badeball/cypress-cucumber-preprocessor");
22+
Given("a failing step", function() {
23+
cy.wait(1000).then(() => { throw "some error" })
24+
})
25+
"""
26+
When I run cypress
27+
Then it fails
28+
And the message report should contain a non-zero duration of the step

features/step_definitions/messages_steps.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,21 @@ function ndJsonToString(ndjson: any) {
9393
return ndjson.map((o: any) => JSON.stringify(o)).join("\n") + "\n";
9494
}
9595

96-
async function readMessagesReport(cwd: string): Promise<messages.Envelope[]> {
96+
async function readMessagesReport(
97+
cwd: string,
98+
options: { normalize: boolean } = { normalize: true }
99+
): Promise<messages.Envelope[]> {
97100
const absoluteMessagesPath = path.join(cwd, "cucumber-messages.ndjson");
98101

99102
const content = await fs.readFile(absoluteMessagesPath);
100103

101-
return prepareMessagesReport(stringToNdJson(content.toString()));
104+
const messages = stringToNdJson(content.toString());
105+
106+
if (options.normalize) {
107+
return prepareMessagesReport(messages);
108+
} else {
109+
return messages;
110+
}
102111
}
103112

104113
function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
@@ -219,3 +228,41 @@ Then("the messages report shouldn't contain any specs", async function () {
219228
}
220229
}
221230
});
231+
232+
Then(
233+
"the message report should contain a non-zero duration of the step",
234+
async function () {
235+
const messages = await readMessagesReport(this.tmpDir, {
236+
normalize: false,
237+
});
238+
239+
type TestStepFinishedEnvelope = Pick<
240+
Required<messages.Envelope>,
241+
"testStepFinished"
242+
>;
243+
244+
const isTestStepFinishedEnvelope = (
245+
envelope: messages.Envelope
246+
): envelope is TestStepFinishedEnvelope => !!envelope.testStepFinished;
247+
248+
const testStepFinishedCol: TestStepFinishedEnvelope[] = messages.filter(
249+
isTestStepFinishedEnvelope
250+
);
251+
252+
if (testStepFinishedCol.length !== 1) {
253+
throw new Error(
254+
"Expected to find a single testStepFinished envelope, but found " +
255+
testStepFinishedCol.length
256+
);
257+
}
258+
259+
const [{ testStepFinished }] = testStepFinishedCol;
260+
261+
if (
262+
testStepFinished.testStepResult.duration.seconds === 0 &&
263+
testStepFinished.testStepResult.duration.nanos === 0
264+
) {
265+
throw new Error("Expected to find non-zero duration");
266+
}
267+
}
268+
);

lib/browser-runtime.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { notNull } from "./helpers/type-guards";
5353

5454
import { looksLikeOptions, tagToCypressOptions } from "./helpers/tag-parser";
5555

56-
import { createTimestamp, duration } from "./helpers/messages";
56+
import { createTimestamp, duration, StrictTimestamp } from "./helpers/messages";
5757

5858
import { indent, stripIndent } from "./helpers/strings";
5959

@@ -97,6 +97,7 @@ interface IStep {
9797
export interface InternalSpecProperties {
9898
pickle: messages.Pickle;
9999
testCaseStartedId: string;
100+
currentStepStartedAt?: StrictTimestamp;
100101
currentStep?: IStep;
101102
allSteps: IStep[];
102103
remainingSteps: IStep[];
@@ -360,6 +361,8 @@ function createPickle(context: CompositionContext, pickle: messages.Pickle) {
360361

361362
const start = createTimestamp();
362363

364+
internalProperties.currentStepStartedAt = start;
365+
363366
if (context.messagesEnabled) {
364367
taskTestStepStarted({
365368
testStepId: hook.id,
@@ -424,10 +427,11 @@ function createPickle(context: CompositionContext, pickle: messages.Pickle) {
424427
cy.then(() => {
425428
window.testState.pickleStep = step.pickleStep;
426429

427-
internalProperties.currentStep = { pickleStep };
428-
429430
const start = createTimestamp();
430431

432+
internalProperties.currentStep = { pickleStep };
433+
internalProperties.currentStepStartedAt = start;
434+
431435
if (context.messagesEnabled) {
432436
taskTestStepStarted({
433437
testStepId: pickleStep.id,
@@ -620,7 +624,8 @@ function afterEachHandler(this: Mocha.Context, context: CompositionContext) {
620624

621625
const properties = retrieveInternalSpecProperties();
622626

623-
const { testCaseStartedId, remainingSteps } = properties;
627+
const { testCaseStartedId, currentStepStartedAt, remainingSteps } =
628+
properties;
624629

625630
if (context.messagesEnabled) {
626631
const endTimestamp = createTimestamp();
@@ -666,11 +671,13 @@ function afterEachHandler(this: Mocha.Context, context: CompositionContext) {
666671
testStepResult: {
667672
status: messages.TestStepResultStatus.FAILED,
668673
message: this.currentTest?.err?.message,
669-
// TODO: Create a proper duration from when the step started.
670-
duration: {
671-
seconds: 0,
672-
nanos: 0,
673-
},
674+
duration: duration(
675+
assertAndReturn(
676+
currentStepStartedAt,
677+
"Expected there to be a timestamp for current step"
678+
),
679+
endTimestamp
680+
),
674681
},
675682
timestamp: endTimestamp,
676683
};

0 commit comments

Comments
 (0)