UNPKG

@badeball/cypress-cucumber-preprocessor

Version:

[![Build status](https://github.com/badeball/cypress-cucumber-preprocessor/actions/workflows/build.yml/badge.svg)](https://github.com/badeball/cypress-cucumber-preprocessor/actions/workflows/build.yml) [![Npm package weekly downloads](https://badgen.net/n

853 lines (836 loc) 38.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.retrieveInternalSpecProperties = void 0; const messages = __importStar(require("@cucumber/messages")); const tag_expressions_1 = __importDefault(require("@cucumber/tag-expressions")); const cucumber_expressions_1 = require("@cucumber/cucumber-expressions"); const uuid_1 = require("uuid"); const seedrandom_1 = __importDefault(require("seedrandom")); const assertions_1 = require("./helpers/assertions"); const data_table_1 = __importDefault(require("./data_table")); const registry_1 = require("./registry"); const ast_1 = require("./helpers/ast"); const constants_1 = require("./constants"); const cypress_task_definitions_1 = require("./cypress-task-definitions"); const type_guards_1 = require("./helpers/type-guards"); const tag_parser_1 = require("./helpers/tag-parser"); const messages_1 = require("./helpers/messages"); const strings_1 = require("./helpers/strings"); const snippets_1 = require("./helpers/snippets"); const cypress_1 = require("./helpers/cypress"); const environment_1 = require("./helpers/environment"); const sourceReference = { uri: "not available", location: { line: 0 }, }; const internalPropertiesReplacementText = "Internal properties of cypress-cucumber-preprocessor omitted from report."; function retrieveInternalSpecProperties() { return Cypress.env(constants_1.INTERNAL_SPEC_PROPERTIES); } exports.retrieveInternalSpecProperties = retrieveInternalSpecProperties; function updateInternalSpecProperties(newProperties) { Object.assign(retrieveInternalSpecProperties(), newProperties); } function retrieveInternalSuiteProperties() { return Cypress.env(constants_1.INTERNAL_SUITE_PROPERTIES); } function shouldPropagateMessages(context) { return context.prettyEnabled || context.messagesEnabled; } function taskSpecEnvelopes(context) { if (shouldPropagateMessages(context)) { cy.task(cypress_task_definitions_1.TASK_SPEC_ENVELOPES, { messages: context.specEnvelopes }, { log: false, }); } } function taskTestCaseStarted(context, testCaseStarted) { if (shouldPropagateMessages(context)) { cy.task(cypress_task_definitions_1.TASK_TEST_CASE_STARTED, testCaseStarted, { log: false, }); } } function taskTestCaseFinished(context, testCasefinished) { if (shouldPropagateMessages(context)) { cy.task(cypress_task_definitions_1.TASK_TEST_CASE_FINISHED, testCasefinished, { log: false, }); } } function taskTestStepStarted(context, testStepStarted) { if (shouldPropagateMessages(context)) { cy.task(cypress_task_definitions_1.TASK_TEST_STEP_STARTED, testStepStarted, { log: false, }); } } function taskTestStepFinished(context, testStepfinished, wasLastStep) { if (shouldPropagateMessages(context)) { cy.task(cypress_task_definitions_1.TASK_TEST_STEP_FINISHED, Object.assign(Object.assign({}, testStepfinished), { wasLastStep }), { log: false, }); } } function findPickleById(context, astId) { return (0, assertions_1.assertAndReturn)(context.pickles.find((pickle) => pickle.astNodeIds && pickle.astNodeIds.includes(astId)), `Expected to find a pickle associated with id = ${astId}`); } function collectExampleIds(examples) { return examples .map((examples) => { return (0, assertions_1.assertAndReturn)(examples.tableBody, "Expected to find a table body").map((row) => (0, assertions_1.assertAndReturn)(row.id, "Expected table row to have an id")); }) .reduce((acum, el) => acum.concat(el), []); } function createTestStepId(options) { const { testStepIds, newId, pickleId, hookIdOrPickleStepId } = options; const testStepId = newId(); let pickleStepIds; if (testStepIds.has(pickleId)) { // See https://github.com/microsoft/TypeScript/issues/9619. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion pickleStepIds = testStepIds.get(pickleId); } else { pickleStepIds = new Map(); testStepIds.set(pickleId, pickleStepIds); } pickleStepIds.set(hookIdOrPickleStepId, testStepId); return testStepId; } function getTestStepId(options) { const { context, pickleId, hookIdOrPickleStepId } = options; return (0, assertions_1.assertAndReturn)((0, assertions_1.assertAndReturn)(context.testStepIds.get(pickleId), "Expected to find test step IDs for pickle = " + pickleId).get(hookIdOrPickleStepId), "Expected to find test step ID for hook or pickleStep = " + hookIdOrPickleStepId); } function createStepDescription({ name, tags, }) { if (name == null && tags == null) { return; } else if (name == null) { return tags; } else if (tags == null) { return name; } else { return `${name} (${tags})`; } } function isLastEl(col, el) { return col[col.length - 1] === el; } function createFeature(context, feature) { describe(feature.name || "<unamed feature>", () => { before(function () { beforeHandler.call(this, context); }); beforeEach(function () { beforeEachHandler.call(this, context); }); afterEach(function () { afterEachHandler.call(this, context); }); if (feature.children) { for (const child of feature.children) { if (child.scenario) { createScenario(context, child.scenario); } else if (child.rule) { createRule(context, child.rule); } } } }); } function createRule(context, rule) { var _a; const picklesWithinRule = (_a = rule.children) === null || _a === void 0 ? void 0 : _a.map((child) => child.scenario).filter(type_guards_1.notNull).flatMap((scenario) => { if (scenario.examples.length > 0) { return collectExampleIds(scenario.examples).map((exampleId) => { return findPickleById(context, exampleId); }); } else { const scenarioId = (0, assertions_1.assertAndReturn)(scenario.id, "Expected scenario to have an id"); return findPickleById(context, scenarioId); } }); if (picklesWithinRule) { if (context.omitFiltered) { const matches = picklesWithinRule.filter((pickle) => context.testFilter.evaluate((0, ast_1.collectTagNames)(pickle.tags))); if (matches.length === 0) { return; } } } describe(rule.name || "<unamed rule>", () => { if (rule.children) { for (const child of rule.children) { if (child.scenario) { createScenario(context, child.scenario); } } } }); } function createScenario(context, scenario) { if (scenario.examples.length > 0) { const exampleIds = collectExampleIds(scenario.examples); for (let i = 0; i < exampleIds.length; i++) { const exampleId = exampleIds[i]; const pickle = findPickleById(context, exampleId); const baseName = pickle.name || "<unamed scenario>"; const exampleName = `${baseName} (example #${i + 1})`; createPickle(context, Object.assign(Object.assign({}, pickle), { name: exampleName })); } } else { const scenarioId = (0, assertions_1.assertAndReturn)(scenario.id, "Expected scenario to have an id"); const pickle = findPickleById(context, scenarioId); createPickle(context, pickle); } } function createPickle(context, pickle) { var _a; const { registry, gherkinDocument, pickles, testFilter } = context; const testCaseId = pickle.id; const pickleSteps = (_a = pickle.steps) !== null && _a !== void 0 ? _a : []; const scenarioName = pickle.name || "<unamed scenario>"; const tags = (0, ast_1.collectTagNames)(pickle.tags); const beforeHooks = registry.resolveBeforeHooks(tags); const afterHooks = registry.resolveAfterHooks(tags); const steps = [ ...beforeHooks.map((hook) => ({ hook })), ...pickleSteps.map((pickleStep) => ({ pickleStep })), ...afterHooks.map((hook) => ({ hook })), ]; if (shouldSkipPickle(testFilter, pickle)) { if (!context.omitFiltered) { it.skip(scenarioName); } return; } let attempt = 0; const internalProperties = { pickle, testCaseStartedId: context.newId(), allSteps: steps, remainingSteps: [...steps], toJSON: () => internalPropertiesReplacementText, }; const internalEnv = { [constants_1.INTERNAL_SPEC_PROPERTIES]: internalProperties, }; const suiteOptions = tags .filter(tag_parser_1.looksLikeOptions) .map(tag_parser_1.tagToCypressOptions) .reduce(Object.assign, {}); if (suiteOptions.env) { Object.assign(suiteOptions.env, internalEnv); } else { suiteOptions.env = internalEnv; } it(scenarioName, suiteOptions, function () { var _a, _b, _c, _d, _e; const { remainingSteps, testCaseStartedId } = retrieveInternalSpecProperties(); taskTestCaseStarted(context, { id: testCaseStartedId, testCaseId, attempt: attempt++, timestamp: (0, messages_1.createTimestamp)(), }); window.testState = { gherkinDocument, pickles, pickle, }; for (const step of steps) { if (step.hook) { const hook = step.hook; const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId: hook.id, }); cy.then(() => { delete window.testState.pickleStep; const start = (0, messages_1.createTimestamp)(); internalProperties.currentStepStartedAt = start; taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp: start, }); return cy.wrap(start, { log: false }); }) .then((start) => { const options = { pickle, gherkinDocument, testCaseStartedId, }; (0, cypress_1.runStepWithLogGroup)({ fn: () => registry.runHook(this, hook, options), keyword: hook.keyword, text: createStepDescription(hook), }); return cy.wrap(start, { log: false }); }) .then((start) => { const end = (0, messages_1.createTimestamp)(); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.PASSED, duration: (0, messages_1.duration)(start, end), }, timestamp: end, }, isLastEl(steps, step)); remainingSteps.shift(); }); } else if (step.pickleStep) { const pickleStep = step.pickleStep; const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId: pickleStep.id, }); const text = (0, assertions_1.assertAndReturn)(pickleStep.text, "Expected pickle step to have a text"); const scenarioStep = (0, assertions_1.assertAndReturn)(context.astIdsMap.get((0, assertions_1.assertAndReturn)((_a = pickleStep.astNodeIds) === null || _a === void 0 ? void 0 : _a[0], "Expected to find at least one astNodeId")), `Expected to find scenario step associated with id = ${(_b = pickleStep.astNodeIds) === null || _b === void 0 ? void 0 : _b[0]}`); const argument = ((_c = pickleStep.argument) === null || _c === void 0 ? void 0 : _c.dataTable) ? new data_table_1.default(pickleStep.argument.dataTable) : ((_e = (_d = pickleStep.argument) === null || _d === void 0 ? void 0 : _d.docString) === null || _e === void 0 ? void 0 : _e.content) ? pickleStep.argument.docString.content : undefined; cy.then(() => { window.testState.pickleStep = step.pickleStep; const start = (0, messages_1.createTimestamp)(); internalProperties.currentStep = { pickleStep }; internalProperties.currentStepStartedAt = start; taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp: start, }); return cy.wrap(start, { log: false }); }) .then((start) => { const beforeStepHooks = registry.resolveBeforeStepHooks(tags); const afterStepHooks = registry.resolveAfterStepHooks(tags); const options = { pickle, pickleStep, gherkinDocument, testCaseStartedId, testStepId, }; const beforeHooksChain = beforeStepHooks.reduce((chain, beforeStepHook) => { return chain.then(() => (0, cypress_1.runStepWithLogGroup)({ keyword: "BeforeStep", text: createStepDescription(beforeStepHook), fn: () => registry.runStepHook(this, beforeStepHook, options), })); }, cy.wrap({}, { log: false })); return beforeHooksChain.then(() => { try { return (0, cypress_1.runStepWithLogGroup)({ keyword: (0, assertions_1.assertAndReturn)("keyword" in scenarioStep && scenarioStep.keyword, "Expected to find a keyword in the scenario step"), argument, text, fn: () => registry.runStepDefininition(this, text, argument), }).then((result) => { return afterStepHooks .reduce((chain, afterStepHook) => { return chain.then(() => (0, cypress_1.runStepWithLogGroup)({ keyword: "AfterStep", text: createStepDescription(afterStepHook), fn: () => registry.runStepHook(this, afterStepHook, options), })); }, cy.wrap({}, { log: false })) .then(() => { return { start, result }; }); }); } catch (e) { if (e instanceof registry_1.MissingDefinitionError) { throw new Error(createMissingStepDefinitionMessage(context, pickleStep, context.registry.parameterTypeRegistry)); } else { throw e; } } }); }) .then(({ start, result }) => { var _a, _b, _c; const end = (0, messages_1.createTimestamp)(); if (result === "pending" || result === "skipped") { if (result === "pending") { taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.PENDING, duration: (0, messages_1.duration)(start, end), }, timestamp: end, }, isLastEl(steps, step)); } else { taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.SKIPPED, duration: (0, messages_1.duration)(start, end), }, timestamp: end, }, isLastEl(steps, step)); } remainingSteps.shift(); for (const skippedStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.assertAndReturn)((_b = (_a = skippedStep.hook) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : (_c = skippedStep.pickleStep) === null || _c === void 0 ? void 0 : _c.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp: (0, messages_1.createTimestamp)(), }); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.SKIPPED, duration: { seconds: 0, nanos: 0, }, }, timestamp: (0, messages_1.createTimestamp)(), }, isLastEl(remainingSteps, skippedStep)); } for (let i = 0, count = remainingSteps.length; i < count; i++) { remainingSteps.pop(); } cy.then(() => this.skip()); } else { taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.PASSED, duration: (0, messages_1.duration)(start, end), }, timestamp: end, }, isLastEl(steps, step)); remainingSteps.shift(); } }); } } }); } function collectTagNamesFromGherkinDocument(gherkinDocument) { const tagNames = []; for (const node of (0, ast_1.traverseGherkinDocument)(gherkinDocument)) { if ("tags" in node) { tagNames.push(...(0, ast_1.collectTagNames)(node.tags)); } } return tagNames; } function createTestFilter(gherkinDocument, environment) { const tagsInDocument = collectTagNamesFromGherkinDocument(gherkinDocument); if (tagsInDocument.includes("@only") || tagsInDocument.includes("@focus")) { return (0, tag_expressions_1.default)("@only or @focus"); } else { const tags = (0, environment_1.getTags)(environment); return tags ? (0, tag_expressions_1.default)(tags) : { evaluate: () => true }; } } function shouldSkipPickle(testFilter, pickle) { const tags = (0, ast_1.collectTagNames)(pickle.tags); return !testFilter.evaluate(tags) || tags.includes("@skip"); } function beforeHandler(context) { var _a; if (!((_a = retrieveInternalSuiteProperties()) === null || _a === void 0 ? void 0 : _a.isEventHandlersAttached)) { (0, assertions_1.fail)("Missing preprocessor event handlers (this usally means you've not invoked `addCucumberPreprocessorPlugin()` or not returned the config object in `setupNodeEvents()`)"); } taskSpecEnvelopes(context); } function beforeEachHandler(context) { (0, registry_1.assignRegistry)(context.registry); } function afterEachHandler(context) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x; (0, registry_1.freeRegistry)(); const properties = retrieveInternalSpecProperties(); const { pickle, testCaseStartedId, currentStepStartedAt, remainingSteps } = properties; const endTimestamp = (0, messages_1.createTimestamp)(); if (remainingSteps.length > 0) { if (((_a = this.currentTest) === null || _a === void 0 ? void 0 : _a.state) === "failed") { const error = (0, assertions_1.assertAndReturn)((_c = (_b = this.currentTest) === null || _b === void 0 ? void 0 : _b.err) === null || _c === void 0 ? void 0 : _c.message, "Expected to find an error message"); if (constants_1.HOOK_FAILURE_EXPR.test(error)) { return; } const failedStep = (0, assertions_1.assertAndReturn)(remainingSteps.shift(), "Expected there to be a remaining step"); const hookIdOrPickleStepId = (0, assertions_1.assertAndReturn)((_e = (_d = failedStep.hook) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : (_f = failedStep.pickleStep) === null || _f === void 0 ? void 0 : _f.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); const failedTestStepFinished = error.includes("Step implementation missing") ? { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.UNDEFINED, duration: { seconds: 0, nanos: 0, }, }, timestamp: endTimestamp, } : { testStepId, testCaseStartedId, testStepResult: { status: error.includes("Multiple matching step definitions for") ? messages.TestStepResultStatus.AMBIGUOUS : messages.TestStepResultStatus.FAILED, message: error, duration: (0, messages_1.duration)((0, assertions_1.assertAndReturn)(currentStepStartedAt, "Expected there to be a timestamp for current step"), endTimestamp), }, timestamp: endTimestamp, }; taskTestStepFinished(context, failedTestStepFinished, remainingSteps.length === 0); for (const skippedStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.assertAndReturn)((_h = (_g = skippedStep.hook) === null || _g === void 0 ? void 0 : _g.id) !== null && _h !== void 0 ? _h : (_j = skippedStep.pickleStep) === null || _j === void 0 ? void 0 : _j.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp: endTimestamp, }); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.SKIPPED, duration: { seconds: 0, nanos: 0, }, }, timestamp: endTimestamp, }, isLastEl(remainingSteps, skippedStep)); } } else if (((_k = this.currentTest) === null || _k === void 0 ? void 0 : _k.state) === "pending") { if (currentStepStartedAt) { const skippedStep = (0, assertions_1.assertAndReturn)(remainingSteps.shift(), "Expected there to be a remaining step"); const hookIdOrPickleStepId = (0, assertions_1.assertAndReturn)((_m = (_l = skippedStep.hook) === null || _l === void 0 ? void 0 : _l.id) !== null && _m !== void 0 ? _m : (_o = skippedStep.pickleStep) === null || _o === void 0 ? void 0 : _o.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.SKIPPED, duration: (0, messages_1.duration)(currentStepStartedAt, endTimestamp), }, timestamp: endTimestamp, }, remainingSteps.length === 0); } for (const remainingStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.assertAndReturn)((_q = (_p = remainingStep.hook) === null || _p === void 0 ? void 0 : _p.id) !== null && _q !== void 0 ? _q : (_r = remainingStep.pickleStep) === null || _r === void 0 ? void 0 : _r.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp: endTimestamp, }); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.SKIPPED, duration: { seconds: 0, nanos: 0, }, }, timestamp: endTimestamp, }, isLastEl(remainingSteps, remainingStep)); } } else { for (const remainingStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.assertAndReturn)((_t = (_s = remainingStep.hook) === null || _s === void 0 ? void 0 : _s.id) !== null && _t !== void 0 ? _t : (_u = remainingStep.pickleStep) === null || _u === void 0 ? void 0 : _u.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp: endTimestamp, }); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.UNKNOWN, duration: { seconds: 0, nanos: 0, }, }, timestamp: endTimestamp, }, isLastEl(remainingSteps, remainingStep)); } } } const currentRetry = (0, assertions_1.assertAndReturn)((_v = this.currentTest) === null || _v === void 0 ? void 0 : _v._currentRetry, "Expected to find an attribute _currentRetry"); const retries = (0, assertions_1.assertAndReturn)((_w = this.currentTest) === null || _w === void 0 ? void 0 : _w._retries, "Expected to find an attribute _retries"); const willBeRetried = ((_x = this.currentTest) === null || _x === void 0 ? void 0 : _x.state) === "failed" ? currentRetry < retries : false; taskTestCaseFinished(context, { testCaseStartedId, timestamp: endTimestamp, willBeRetried, }); /** * Repopulate internal properties in case previous test is retried. */ updateInternalSpecProperties({ testCaseStartedId: context.newId(), remainingSteps: [...properties.allSteps], }); } function createTests(registry, seed, source, gherkinDocument, pickles, prettyEnabled, messagesEnabled, omitFiltered, stepDefinitionHints) { const prng = (0, seedrandom_1.default)(seed.toString()); const newId = () => (0, uuid_1.v4)({ random: Array.from({ length: 16 }, () => Math.floor(prng() * 256)), }); registry.finalize(newId); const testFilter = createTestFilter(gherkinDocument, Cypress.env()); const stepDefinitions = registry.stepDefinitions.map((stepDefinition) => { const type = stepDefinition.expression instanceof cucumber_expressions_1.RegularExpression ? messages.StepDefinitionPatternType.REGULAR_EXPRESSION : messages.StepDefinitionPatternType.CUCUMBER_EXPRESSION; return { id: stepDefinition.id, pattern: { type, source: stepDefinition.expression.source, }, sourceReference, }; }); const testStepIds = new Map(); const testCases = pickles .filter((pickle) => { return !omitFiltered || !shouldSkipPickle(testFilter, pickle); }) .map((pickle) => { const tags = (0, ast_1.collectTagNames)(pickle.tags); const beforeHooks = registry.resolveBeforeHooks(tags); const afterHooks = registry.resolveAfterHooks(tags); const hooksToStep = (hook) => { return { id: createTestStepId({ testStepIds, newId, pickleId: pickle.id, hookIdOrPickleStepId: hook.id, }), hookId: hook.id, }; }; const pickleStepToTestStep = (pickleStep) => { const stepDefinitionIds = registry .getMatchingStepDefinitions(pickleStep.text) .map((stepDefinition) => stepDefinition.id); return { id: createTestStepId({ testStepIds, newId, pickleId: pickle.id, hookIdOrPickleStepId: pickleStep.id, }), pickleStepId: pickleStep.id, stepDefinitionIds, }; }; return { id: pickle.id, pickleId: pickle.id, testSteps: [ ...beforeHooks.map(hooksToStep), ...pickle.steps.map(pickleStepToTestStep), ...afterHooks.map(hooksToStep), ], }; }); const specEnvelopes = []; specEnvelopes.push({ source: { data: source, uri: (0, assertions_1.assertAndReturn)(gherkinDocument.uri, "Expected gherkin document to have URI"), mediaType: messages.SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN, }, }); specEnvelopes.push({ gherkinDocument, }); for (const pickle of pickles) { specEnvelopes.push({ pickle, }); } for (const hook of registry.hooks) { specEnvelopes.push({ hook: { id: hook.id, name: hook.name, sourceReference, }, }); } for (const stepDefinition of stepDefinitions) { specEnvelopes.push({ stepDefinition, }); } for (const testCase of testCases) { specEnvelopes.push({ testCase, }); } const context = { registry, newId, gherkinDocument, astIdsMap: (0, ast_1.createAstIdMap)(gherkinDocument), testStepIds, pickles, specEnvelopes, testFilter, omitFiltered, prettyEnabled, messagesEnabled, stepDefinitionHints, }; if (gherkinDocument.feature) { createFeature(context, gherkinDocument.feature); } } exports.default = createTests; function strictIsInteractive() { const isInteractive = Cypress.config("isInteractive"); if (typeof isInteractive === "boolean") { return isInteractive; } throw new Error("Expected to find a Cypress configuration property `isInteractive`, but didn't"); } function createMissingStepDefinitionMessage(context, pickleStep, parameterTypeRegistry) { var _a, _b; const noStepDefinitionPathsTemplate = ` Step implementation missing for "<text>". We tried searching for files containing step definitions using the following search pattern templates: <step-definitions> These templates resolved to the following search patterns: <step-definition-patterns> These patterns matched **no files** containing step definitions. This almost certainly means that you have misconfigured \`stepDefinitions\`. You can implement it using the suggestion(s) below. <snippets> `; const someStepDefinitionPathsTemplate = ` Step implementation missing for "<text>". We tried searching for files containing step definitions using the following search pattern templates: <step-definitions> These templates resolved to the following search patterns: <step-definition-patterns> These patterns matched the following files: <step-definition-paths> However, none of these files contained a step definition matching "<text>". You can implement it using the suggestion(s) below. <snippets> `; const { stepDefinitionHints } = context; const template = stepDefinitionHints.stepDefinitionPaths.length > 0 ? someStepDefinitionPathsTemplate : noStepDefinitionPathsTemplate; const maybeEscape = (string) => strictIsInteractive() ? string.replaceAll("*", "\\*") : string; const prettyPrintList = (items) => items.map((item) => " - " + maybeEscape(item)).join("\n"); let parameter = null; if ((_a = pickleStep.argument) === null || _a === void 0 ? void 0 : _a.dataTable) { parameter = "dataTable"; } else if ((_b = pickleStep.argument) === null || _b === void 0 ? void 0 : _b.docString) { parameter = "docString"; } const snippets = new cucumber_expressions_1.CucumberExpressionGenerator(() => parameterTypeRegistry.parameterTypes) .generateExpressions(pickleStep.text) .map((expression) => (0, snippets_1.generateSnippet)(expression, (0, assertions_1.assertAndReturn)(pickleStep.type, "Expected pickleStep to have a type"), parameter)) .map((snippet) => (0, strings_1.indent)(snippet, { count: 2 })) .join("\n\n"); return (0, strings_1.stripIndent)(template) .replaceAll("<text>", pickleStep.text) .replaceAll("<step-definitions>", prettyPrintList([stepDefinitionHints.stepDefinitions].flat())) .replaceAll("<step-definition-patterns>", prettyPrintList(stepDefinitionHints.stepDefinitionPatterns)) .replaceAll("<step-definition-paths>", prettyPrintList(stepDefinitionHints.stepDefinitionPaths)) .replaceAll("<snippets>", snippets); }