Skip to content

Commit fe56ee6

Browse files
committed
Update @cucumber/compatibility-kit to v23.0.0
1 parent 9b1cfe8 commit fe56ee6

14 files changed

+190
-118
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 & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import {
1919
ITaskFrontendTrackingError,
2020
ITaskSpecEnvelopes,
21+
ITaskSuggestion,
2122
ITaskTestCaseFinished,
2223
ITaskTestCaseStarted,
2324
ITaskTestRunHookFinished,
@@ -26,6 +27,7 @@ import {
2627
ITaskTestStepStarted,
2728
TASK_FRONTEND_TRACKING_ERROR,
2829
TASK_SPEC_ENVELOPES,
30+
TASK_SUGGESTION,
2931
TASK_TEST_CASE_FINISHED,
3032
TASK_TEST_CASE_STARTED,
3133
TASK_TEST_RUN_HOOK_FINISHED,
@@ -273,6 +275,12 @@ function taskFrontEndTrackingError(error: CypressCucumberAssertionError) {
273275
);
274276
}
275277

278+
function taskSuggestion(suggestion: messages.Suggestion) {
279+
return cy.task(TASK_SUGGESTION, suggestion satisfies ITaskSuggestion, {
280+
log: false,
281+
});
282+
}
283+
276284
function emitSkippedPickle(
277285
context: CompositionContext,
278286
pickle: messages.Pickle,
@@ -862,60 +870,94 @@ function createPickle(context: CompositionContext, pickle: messages.Pickle) {
862870

863871
return beforeHooksChain()
864872
.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;
873+
return runStepWithLogGroup({
874+
keyword: ensure(
875+
"keyword" in scenarioStep && scenarioStep.keyword,
876+
"Expected to find a keyword in the scenario step",
877+
),
878+
argument,
879+
text,
880+
fn: () => {
881+
try {
882+
return registry.runStepDefinition(
883+
this,
884+
text,
885+
dryRun,
886+
argument,
887+
);
888+
} catch (e) {
889+
if (
890+
e instanceof MissingDefinitionError ||
891+
e instanceof MultipleDefinitionsError
892+
) {
893+
(this.test as any)._retries = (
894+
this.test as any
895+
)._currentRetry;
896+
}
897+
898+
if (e instanceof MissingDefinitionError) {
899+
let parameterType: "dataTable" | "docString" | null =
900+
null;
901+
902+
if (pickleStep.argument?.dataTable) {
903+
parameterType = "dataTable";
904+
} else if (pickleStep.argument?.docString) {
905+
parameterType = "docString";
889906
}
907+
908+
const snippets = new CucumberExpressionGenerator(
909+
() =>
910+
context.registry.parameterTypeRegistry
911+
.parameterTypes,
912+
)
913+
.generateExpressions(pickleStep.text)
914+
.map((expression) =>
915+
generateSnippet(
916+
expression,
917+
ensure(
918+
pickleStep.type,
919+
"Expected pickleStep to have a type",
920+
),
921+
parameterType,
922+
),
923+
);
924+
925+
return taskSuggestion({
926+
id: context.newId(),
927+
pickleStepId: pickleStep.id,
928+
snippets: snippets.map((code) => {
929+
return {
930+
language: "javascript",
931+
code,
932+
};
933+
}),
934+
}).then(() => {
935+
throw new Error(
936+
createMissingStepDefinitionMessage(
937+
context,
938+
pickleStep,
939+
snippets,
940+
),
941+
);
942+
});
943+
} else {
890944
throw e;
891945
}
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-
}
946+
}
947+
},
948+
})
949+
.then(convertReturnValueToTestStepResultStatus)
950+
.then((status) => {
951+
const testStepResult = {
952+
status,
953+
duration: duration(start, createTimestamp()),
954+
};
955+
956+
return {
957+
beforeStepHookResults,
958+
testStepResult,
959+
};
960+
});
919961
})
920962
.then(({ beforeStepHookResults, testStepResult }) => {
921963
return afterStepHooksChain().then((afterStepHookResults) => {
@@ -1574,7 +1616,7 @@ function strictIsTextTerminal(): boolean {
15741616
function createMissingStepDefinitionMessage(
15751617
context: CompositionContext,
15761618
pickleStep: messages.PickleStep,
1577-
parameterTypeRegistry: ParameterTypeRegistry,
1619+
snippets: string[],
15781620
) {
15791621
const noStepDefinitionPathsTemplate = `
15801622
Step implementation missing for "<text>".
@@ -1629,28 +1671,6 @@ function createMissingStepDefinitionMessage(
16291671
const prettyPrintList = (items: string[]) =>
16301672
items.map((item) => " - " + maybeEscape(item)).join("\n");
16311673

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-
16541674
return stripIndent(template)
16551675
.replaceAll("<text>", pickleStep.text)
16561676
.replaceAll(
@@ -1665,7 +1685,10 @@ function createMissingStepDefinitionMessage(
16651685
"<step-definition-paths>",
16661686
prettyPrintList(stepDefinitionHints.stepDefinitionPaths),
16671687
)
1668-
.replaceAll("<snippets>", snippets);
1688+
.replaceAll(
1689+
"<snippets>",
1690+
snippets.map((snippet) => indent(snippet, { count: 2 })).join("\n\n"),
1691+
);
16691692
}
16701693

16711694
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)