Skip to content

Commit b0c15e5

Browse files
committed
Update @cucumber/compatibility-kit to v23.0.0
1 parent 587899f commit b0c15e5

14 files changed

+190
-119
lines changed

compatibility/cck_spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ const ignorableKeys = [
4545
// errors
4646
"message",
4747
"stackTrace",
48+
// suggestions
49+
"snippets",
4850
];
4951

5052
function isObject(object: any): object is object {
@@ -99,6 +101,7 @@ describe("Cucumber Compatibility Kit", () => {
99101
case "hooks-conditional": // Expections during hooks are difficult to mimick due to no try-catch
100102
case "global-hooks-beforeall-error": // See above
101103
case "global-hooks-afterall-error": // See above
104+
case "hooks-undefined": // See above
102105
case "multiple-features": // The "correct" message order is difficult to mimick
103106
case "multiple-features-reversed": // Cypress has no `reversed` option
104107
it.skip(`passes the cck suite for '${suiteName}'`);
@@ -278,7 +281,7 @@ describe("Cucumber Compatibility Kit", () => {
278281
(await fs.readFile(ndjsonFile)).toString(),
279282
).map(normalizeMessage);
280283

281-
if (suiteName === "pending") {
284+
if (suiteName === "pending" || suiteName === "retry-pending") {
282285
/**
283286
* We can't control Cypress exit code without failing a test, thus is cucumber-js behavior
284287
* difficult to mimic.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Given } from "@badeball/cypress-cucumber-preprocessor";
22

3-
Given(/a (.*?) with (.*?)/, function () {
3+
Given(/^a (.*?) with (.*?)$/, function () {
44
// first one
55
});
66

7-
Given(/a step with (.*)/, function () {
7+
Given(/^a step with (.*)$/, function () {
88
// second one
99
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Given, Then, When } from "@badeball/cypress-cucumber-preprocessor";
2+
3+
Given("there are {int} cucumbers", function (initialCount) {
4+
this.count = initialCount;
5+
});
6+
7+
When("I eat {int} cucumbers", function (eatCount: number) {
8+
this.count -= eatCount;
9+
});
10+
11+
Then("I should have {int} cucumbers", function (expectedCount: number) {
12+
expect(this.count).to.equal(expectedCount);
13+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Given } from "@badeball/cypress-cucumber-preprocessor";
2+
3+
Given("an ambiguous step", function () {
4+
// first one
5+
});
6+
7+
Given("an ambiguous step", function () {
8+
// second one
9+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Given } from "@badeball/cypress-cucumber-preprocessor";
2+
3+
Given("a pending step", function () {
4+
return "pending";
5+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// There are intentionally no steps defined for this sample

compatibility/step_definitions/retry.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,3 @@ Given("a step that passes the third time", function () {
2323
Given("a step that always fails", function () {
2424
throw new Error("Exception in step");
2525
});
26-
27-
Given("an ambiguous step", function () {
28-
// first one
29-
});
30-
31-
Given("an ambiguous step", function () {
32-
// second one
33-
});
34-
35-
Given("a pending step", function () {
36-
return "pending";
37-
});

lib/add-cucumber-preprocessor-plugin.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
TASK_CREATE_STRING_ATTACHMENT,
1313
TASK_FRONTEND_TRACKING_ERROR,
1414
TASK_SPEC_ENVELOPES,
15+
TASK_SUGGESTION,
1516
TASK_TEST_CASE_FINISHED,
1617
TASK_TEST_CASE_STARTED,
1718
TASK_TEST_RUN_HOOK_FINISHED,
@@ -34,6 +35,7 @@ import {
3435
frontendTrackingErrorHandler,
3536
OnAfterStep,
3637
specEnvelopesHandler,
38+
suggestion,
3739
testCaseFinishedHandler,
3840
testCaseStartedHandler,
3941
testRunHookFinishedHandler,
@@ -133,6 +135,7 @@ export async function addCucumberPreprocessorPlugin(
133135
null,
134136
config,
135137
),
138+
[TASK_SUGGESTION]: suggestion.bind(null, config),
136139
});
137140

138141
const tags = getTags(config.env);

lib/browser-runtime.ts

Lines changed: 98 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
CucumberExpressionGenerator,
33
Group,
4-
ParameterTypeRegistry,
54
RegularExpression,
65
} from "@cucumber/cucumber-expressions";
76
import * as messages from "@cucumber/messages";
@@ -18,6 +17,7 @@ import {
1817
import {
1918
ITaskFrontendTrackingError,
2019
ITaskSpecEnvelopes,
20+
ITaskSuggestion,
2121
ITaskTestCaseFinished,
2222
ITaskTestCaseStarted,
2323
ITaskTestRunHookFinished,
@@ -26,6 +26,7 @@ import {
2626
ITaskTestStepStarted,
2727
TASK_FRONTEND_TRACKING_ERROR,
2828
TASK_SPEC_ENVELOPES,
29+
TASK_SUGGESTION,
2930
TASK_TEST_CASE_FINISHED,
3031
TASK_TEST_CASE_STARTED,
3132
TASK_TEST_RUN_HOOK_FINISHED,
@@ -273,6 +274,12 @@ function taskFrontEndTrackingError(error: CypressCucumberAssertionError) {
273274
);
274275
}
275276

277+
function taskSuggestion(suggestion: messages.Suggestion) {
278+
return cy.task(TASK_SUGGESTION, suggestion satisfies ITaskSuggestion, {
279+
log: false,
280+
});
281+
}
282+
276283
function emitSkippedPickle(
277284
context: CompositionContext,
278285
pickle: messages.Pickle,
@@ -862,60 +869,94 @@ function createPickle(context: CompositionContext, pickle: messages.Pickle) {
862869

863870
return beforeHooksChain()
864871
.then((beforeStepHookResults) => {
865-
try {
866-
return runStepWithLogGroup({
867-
keyword: ensure(
868-
"keyword" in scenarioStep && scenarioStep.keyword,
869-
"Expected to find a keyword in the scenario step",
870-
),
871-
argument,
872-
text,
873-
fn: () => {
874-
try {
875-
return registry.runStepDefinition(
876-
this,
877-
text,
878-
dryRun,
879-
argument,
880-
);
881-
} catch (e) {
882-
if (
883-
e instanceof MissingDefinitionError ||
884-
e instanceof MultipleDefinitionsError
885-
) {
886-
(this.test as any)._retries = (
887-
this.test as any
888-
)._currentRetry;
872+
return runStepWithLogGroup({
873+
keyword: ensure(
874+
"keyword" in scenarioStep && scenarioStep.keyword,
875+
"Expected to find a keyword in the scenario step",
876+
),
877+
argument,
878+
text,
879+
fn: () => {
880+
try {
881+
return registry.runStepDefinition(
882+
this,
883+
text,
884+
dryRun,
885+
argument,
886+
);
887+
} catch (e) {
888+
if (
889+
e instanceof MissingDefinitionError ||
890+
e instanceof MultipleDefinitionsError
891+
) {
892+
(this.test as any)._retries = (
893+
this.test as any
894+
)._currentRetry;
895+
}
896+
897+
if (e instanceof MissingDefinitionError) {
898+
let parameterType: "dataTable" | "docString" | null =
899+
null;
900+
901+
if (pickleStep.argument?.dataTable) {
902+
parameterType = "dataTable";
903+
} else if (pickleStep.argument?.docString) {
904+
parameterType = "docString";
889905
}
906+
907+
const snippets = new CucumberExpressionGenerator(
908+
() =>
909+
context.registry.parameterTypeRegistry
910+
.parameterTypes,
911+
)
912+
.generateExpressions(pickleStep.text)
913+
.map((expression) =>
914+
generateSnippet(
915+
expression,
916+
ensure(
917+
pickleStep.type,
918+
"Expected pickleStep to have a type",
919+
),
920+
parameterType,
921+
),
922+
);
923+
924+
return taskSuggestion({
925+
id: context.newId(),
926+
pickleStepId: pickleStep.id,
927+
snippets: snippets.map((code) => {
928+
return {
929+
language: "javascript",
930+
code,
931+
};
932+
}),
933+
}).then(() => {
934+
throw new Error(
935+
createMissingStepDefinitionMessage(
936+
context,
937+
pickleStep,
938+
snippets,
939+
),
940+
);
941+
});
942+
} else {
890943
throw e;
891944
}
892-
},
893-
})
894-
.then(convertReturnValueToTestStepResultStatus)
895-
.then((status) => {
896-
const testStepResult = {
897-
status,
898-
duration: duration(start, createTimestamp()),
899-
};
900-
901-
return {
902-
beforeStepHookResults,
903-
testStepResult,
904-
};
905-
});
906-
} catch (e) {
907-
if (e instanceof MissingDefinitionError) {
908-
throw new Error(
909-
createMissingStepDefinitionMessage(
910-
context,
911-
pickleStep,
912-
context.registry.parameterTypeRegistry,
913-
),
914-
);
915-
} else {
916-
throw e;
917-
}
918-
}
945+
}
946+
},
947+
})
948+
.then(convertReturnValueToTestStepResultStatus)
949+
.then((status) => {
950+
const testStepResult = {
951+
status,
952+
duration: duration(start, createTimestamp()),
953+
};
954+
955+
return {
956+
beforeStepHookResults,
957+
testStepResult,
958+
};
959+
});
919960
})
920961
.then(({ beforeStepHookResults, testStepResult }) => {
921962
return afterStepHooksChain().then((afterStepHookResults) => {
@@ -1574,7 +1615,7 @@ function strictIsTextTerminal(): boolean {
15741615
function createMissingStepDefinitionMessage(
15751616
context: CompositionContext,
15761617
pickleStep: messages.PickleStep,
1577-
parameterTypeRegistry: ParameterTypeRegistry,
1618+
snippets: string[],
15781619
) {
15791620
const noStepDefinitionPathsTemplate = `
15801621
Step implementation missing for "<text>".
@@ -1629,28 +1670,6 @@ function createMissingStepDefinitionMessage(
16291670
const prettyPrintList = (items: string[]) =>
16301671
items.map((item) => " - " + maybeEscape(item)).join("\n");
16311672

1632-
let parameter: "dataTable" | "docString" | null = null;
1633-
1634-
if (pickleStep.argument?.dataTable) {
1635-
parameter = "dataTable";
1636-
} else if (pickleStep.argument?.docString) {
1637-
parameter = "docString";
1638-
}
1639-
1640-
const snippets = new CucumberExpressionGenerator(
1641-
() => parameterTypeRegistry.parameterTypes,
1642-
)
1643-
.generateExpressions(pickleStep.text)
1644-
.map((expression) =>
1645-
generateSnippet(
1646-
expression,
1647-
ensure(pickleStep.type, "Expected pickleStep to have a type"),
1648-
parameter,
1649-
),
1650-
)
1651-
.map((snippet) => indent(snippet, { count: 2 }))
1652-
.join("\n\n");
1653-
16541673
return stripIndent(template)
16551674
.replaceAll("<text>", pickleStep.text)
16561675
.replaceAll(
@@ -1665,7 +1684,10 @@ function createMissingStepDefinitionMessage(
16651684
"<step-definition-paths>",
16661685
prettyPrintList(stepDefinitionHints.stepDefinitionPaths),
16671686
)
1668-
.replaceAll("<snippets>", snippets);
1687+
.replaceAll(
1688+
"<snippets>",
1689+
snippets.map((snippet) => indent(snippet, { count: 2 })).join("\n\n"),
1690+
);
16691691
}
16701692

16711693
function mapArgumentGroup(group: Group): messages.Group {

lib/cypress-task-definitions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export const TASK_FRONTEND_TRACKING_ERROR =
4545

4646
export type ITaskFrontendTrackingError = string;
4747

48+
export const TASK_SUGGESTION = "cypress-cucumber-preprocessor:suggestion";
49+
50+
export type ITaskSuggestion = messages.Suggestion;
51+
4852
export interface ITaskCreateStringAttachment {
4953
data: string;
5054
fileName?: string;

0 commit comments

Comments
 (0)