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

1,098 lines 53.7 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 () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.retrieveInternalSpecProperties = retrieveInternalSpecProperties; exports.default = createTests; const cucumber_expressions_1 = require("@cucumber/cucumber-expressions"); const messages = __importStar(require("@cucumber/messages")); const tag_expressions_1 = __importDefault(require("@cucumber/tag-expressions")); const seedrandom_1 = __importDefault(require("seedrandom")); const uuid_1 = require("uuid"); const constants_1 = require("./constants"); const cypress_task_definitions_1 = require("./cypress-task-definitions"); const data_table_1 = __importDefault(require("./data_table")); const assertions_1 = require("./helpers/assertions"); const ast_1 = require("./helpers/ast"); const cypress_1 = require("./helpers/cypress"); const environment_1 = require("./helpers/environment"); const messages_1 = require("./helpers/messages"); const options_1 = require("./helpers/options"); const snippets_1 = require("./helpers/snippets"); const strings_1 = require("./helpers/strings"); const tag_parser_1 = require("./helpers/tag-parser"); const type_guards_1 = require("./helpers/type-guards"); const registry_1 = require("./registry"); function getSourceReferenceFromPosition(position) { if (position) { return { uri: position.source, location: { line: position.line, column: position.column }, }; } else { return { uri: "not available", location: { line: 0, column: 0 }, }; } } function convertReturnValueToTestStepResultStatus(retval) { if (retval === "skipped") { return messages.TestStepResultStatus.SKIPPED; } else if (retval === "pending") { return messages.TestStepResultStatus.PENDING; } else { return messages.TestStepResultStatus.PASSED; } } const internalPropertiesReplacementText = "Internal properties of cypress-cucumber-preprocessor omitted from report."; const noopFn = () => { }; function retrieveInternalSpecProperties() { return Cypress.env(constants_1.INTERNAL_SPEC_PROPERTIES); } function updateInternalSpecProperties(newProperties) { Object.assign(retrieveInternalSpecProperties(), newProperties); } function retrieveInternalSuiteProperties() { return Cypress.env(constants_1.INTERNAL_SUITE_PROPERTIES); } function taskSpecEnvelopes(context) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_SPEC_ENVELOPES, { messages: context.specEnvelopes }, { log: false, }); } } function taskTestCaseStarted(context, testCaseStarted) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_TEST_CASE_STARTED, testCaseStarted, { log: false, }); } } function taskTestCaseFinished(context, testCasefinished) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_TEST_CASE_FINISHED, testCasefinished, { log: false, }); } } function taskTestStepStarted(context, testStepStarted) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_TEST_STEP_STARTED, testStepStarted, { log: false, }); } } function taskTestStepFinished(context, testStepfinished) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_TEST_STEP_FINISHED, testStepfinished, { log: false, }); } } function taskRunHookStarted(context, testRunHookStarted) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_TEST_RUN_HOOK_STARTED, testRunHookStarted, { log: false, }); } } function taskRunHookFinished(context, testRunHookFinished) { if (context.isTrackingState) { cy.task(cypress_task_definitions_1.TASK_TEST_RUN_HOOK_FINISHED, testRunHookFinished, { log: false, }); } } function taskFrontEndTrackingError(error) { var _a; cy.task(cypress_task_definitions_1.TASK_FRONTEND_TRACKING_ERROR, ((_a = error.stack) !== null && _a !== void 0 ? _a : error.message), { log: true, }); } function taskSuggestion(context, suggestion) { if (context.isTrackingState) { return cy.task(cypress_task_definitions_1.TASK_SUGGESTION, suggestion, { log: false, }); } else { return cy.wrap({}, { log: false }); } } function emitSkippedPickle(context, pickle) { var _a; const { registry } = context; const testCaseId = pickle.id; const pickleSteps = (_a = pickle.steps) !== null && _a !== void 0 ? _a : []; const tags = (0, ast_1.collectTagNames)(pickle.tags); const beforeHooks = registry.resolveBeforeHooks(tags); const afterHooks = registry.resolveAfterHooks(tags); const testCaseStartedId = context.newId(); const timestamp = (0, messages_1.createTimestamp)(); const steps = [ ...beforeHooks, ...pickleSteps, ...afterHooks, ]; taskTestCaseStarted(context, { id: testCaseStartedId, testCaseId, attempt: 0, timestamp, }); for (const step of steps) { const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId: step.id, }); taskTestStepStarted(context, { testStepId, testCaseStartedId, timestamp, }); taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.SKIPPED, duration: { seconds: 0, nanos: 0, }, }, timestamp, }); } taskTestCaseFinished(context, { testCaseStartedId, timestamp, willBeRetried: false, }); } function findPickleById(context, astId) { return (0, assertions_1.ensure)(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.ensure)(examples.tableBody, "Expected to find a table body").map((row) => (0, assertions_1.ensure)(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. 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.ensure)((0, assertions_1.ensure)(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 createFeature(context, feature) { var _a; const suiteOptions = Object.fromEntries((0, options_1.tagsToOptions)(feature.tags).filter(options_1.isExclusivelySuiteConfiguration)); const mochaGlobals = (_a = globalThis["__cypress_cucumber_preprocessor_mocha_dont_use_this"]) !== null && _a !== void 0 ? _a : globalThis; describe(feature.name || "<unamed feature>", suiteOptions, () => { mochaGlobals.before(function () { beforeHandler.call(this, context); }); mochaGlobals.beforeEach(function () { beforeEachHandler.call(this, context); }); mochaGlobals.after(function () { afterHandler.call(this, context); }); mochaGlobals.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.ensure)(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; } } } const suiteOptions = Object.fromEntries((0, options_1.tagsToOptions)(rule.tags).filter(options_1.isExclusivelySuiteConfiguration)); describe(rule.name || "<unamed rule>", suiteOptions, () => { 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.ensure)(scenario.id, "Expected scenario to have an id"); const pickle = findPickleById(context, scenarioId); createPickle(context, pickle); } } function createPickle(context, pickle) { var _a, _b, _c; const { registry, gherkinDocument, pickles, testFilter, dryRun } = 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 scenario = (0, assertions_1.ensure)(context.astIdsMap.get((0, assertions_1.ensure)((_b = pickle.astNodeIds) === null || _b === void 0 ? void 0 : _b[0], "Expected to find at least one astNodeId")), `Expected to find scenario associated with id = ${(_c = pickle.astNodeIds) === null || _c === void 0 ? void 0 : _c[0]}`); (0, assertions_1.assert)("tags" in scenario, "Expected a scenario to have a tags property"); (0, assertions_1.assert)("examples" in scenario, "Expected a scenario to have a examples property"); const testSpecificOptions = (0, options_1.tagsToOptions)([ ...scenario.tags, ...scenario.examples.flatMap((example) => example.tags), ]); for (const entry of testSpecificOptions) { if ((0, options_1.isExclusivelySuiteConfiguration)(entry)) { throw new Error(`The \`${entry[0]}\` configuration can only be overridden from a suite-level override (in Cucumber-terms this means on a Feature or Rule).`); } } const inheritedTestOptions = Object.fromEntries(tags .filter(tag_parser_1.looksLikeOptions) .map(tag_parser_1.tagToCypressOptions) .filter(options_1.isNotExclusivelySuiteConfiguration)); if (inheritedTestOptions.env) { Object.assign(inheritedTestOptions.env, internalEnv); } else { inheritedTestOptions.env = internalEnv; } it(scenarioName, inheritedTestOptions, function () { var _a, _b, _c, _d, _e; /** * This must always be true, otherwise something is off. */ (0, assertions_1.assert)(context.includedPickles[0].id === pickle.id, "Included pickle stack is unsynchronized"); const { remainingSteps, testCaseStartedId } = retrieveInternalSpecProperties(); taskTestCaseStarted(context, { id: testCaseStartedId, testCaseId, attempt: attempt++, timestamp: (0, messages_1.createTimestamp)(), }); window.testState = { gherkinDocument, pickles, pickle, }; const onAfterStep = (options) => { var _a, _b, _c; const { testStepId, testStepResult } = options; const end = (0, messages_1.createTimestamp)(); if (testStepResult.status === messages.TestStepResultStatus.PENDING || testStepResult.status === messages.TestStepResultStatus.SKIPPED) { taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult, timestamp: end, }); remainingSteps.shift(); for (const skippedStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.ensure)((_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)(), }); } for (let i = 0, count = remainingSteps.length; i < count; i++) { remainingSteps.pop(); } cy.then(() => this.skip()); } else { taskTestStepFinished(context, { testStepId, testCaseStartedId, testStepResult, timestamp: (0, messages_1.createTimestamp)(), }); remainingSteps.shift(); } }; 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, }; return (0, cypress_1.runStepWithLogGroup)({ fn: dryRun ? noopFn : () => registry.runCaseHook(this, hook, options), keyword: hook.keyword, text: createStepDescription(hook), }) .then(convertReturnValueToTestStepResultStatus) .then((status) => { return { start, status }; }); }) .then(({ start, status }) => onAfterStep({ testStepResult: { status, duration: (0, messages_1.duration)(start, (0, messages_1.createTimestamp)()), }, testStepId, })); } else if (step.pickleStep) { const pickleStep = step.pickleStep; const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId: pickleStep.id, }); const text = (0, assertions_1.ensure)(pickleStep.text, "Expected pickle step to have a text"); const scenarioStep = (0, assertions_1.ensure)(context.astIdsMap.get((0, assertions_1.ensure)((_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((results) => { const start = (0, messages_1.createTimestamp)(); return (0, cypress_1.runStepWithLogGroup)({ keyword: "BeforeStep", text: createStepDescription(beforeStepHook), fn: dryRun ? noopFn : () => registry.runStepHook(this, beforeStepHook, options), }) .then(convertReturnValueToTestStepResultStatus) .then((status) => results.concat({ status, duration: (0, messages_1.duration)(start, (0, messages_1.createTimestamp)()), })); }); }, cy.wrap([], { log: false })); const afterStepHooksChain = () => afterStepHooks.reduce((chain, afterStepHook) => { return chain.then((results) => { const start = (0, messages_1.createTimestamp)(); return (0, cypress_1.runStepWithLogGroup)({ keyword: "AfterStep", text: createStepDescription(afterStepHook), fn: dryRun ? noopFn : () => registry.runStepHook(this, afterStepHook, options), }) .then(convertReturnValueToTestStepResultStatus) .then((status) => results.concat({ status, duration: (0, messages_1.duration)(start, (0, messages_1.createTimestamp)()), })); }); }, cy.wrap([], { log: false, })); return beforeHooksChain() .then((beforeStepHookResults) => { return (0, cypress_1.runStepWithLogGroup)({ keyword: (0, assertions_1.ensure)("keyword" in scenarioStep && scenarioStep.keyword, "Expected to find a keyword in the scenario step"), argument, text, fn: () => { var _a, _b; try { return registry.runStepDefinition(this, text, dryRun, argument); } catch (e) { if (e instanceof registry_1.MissingDefinitionError || e instanceof registry_1.MultipleDefinitionsError) { this.test._retries = this.test._currentRetry; } if (e instanceof registry_1.MissingDefinitionError) { let parameterType = null; if ((_a = pickleStep.argument) === null || _a === void 0 ? void 0 : _a.dataTable) { parameterType = "dataTable"; } else if ((_b = pickleStep.argument) === null || _b === void 0 ? void 0 : _b.docString) { parameterType = "docString"; } const snippets = new cucumber_expressions_1.CucumberExpressionGenerator(() => context.registry.parameterTypeRegistry .parameterTypes) .generateExpressions(pickleStep.text) .map((expression) => (0, snippets_1.generateSnippet)(expression, (0, assertions_1.ensure)(pickleStep.type, "Expected pickleStep to have a type"), parameterType)); return taskSuggestion(context, { id: context.newId(), pickleStepId: pickleStep.id, snippets: snippets.map((code) => { return { language: "javascript", code, }; }), }).then(() => { throw new Error(createMissingStepDefinitionMessage(context, pickleStep, snippets)); }); } else { throw e; } } }, }) .then(convertReturnValueToTestStepResultStatus) .then((status) => { const testStepResult = { status, duration: (0, messages_1.duration)(start, (0, messages_1.createTimestamp)()), }; return { beforeStepHookResults, testStepResult, }; }); }) .then(({ beforeStepHookResults, testStepResult }) => { return afterStepHooksChain().then((afterStepHookResults) => { return messages.getWorstTestStepResult([ ...beforeStepHookResults, testStepResult, ...afterStepHookResults, ]); }); }); }) .then((testStepResult) => onAfterStep({ testStepResult, testStepId })); } } }); } 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 usually means you've not invoked `addCucumberPreprocessorPlugin()` or not returned the config object in `setupNodeEvents()`)"); } const { registry } = context; taskSpecEnvelopes(context); registry.resolveBeforeAllHooks().reduce((chain, hook) => { return chain.then(() => { const testRunHookStartedId = context.newId(); const start = (0, messages_1.createTimestamp)(); taskRunHookStarted(context, { id: testRunHookStartedId, hookId: hook.id, testRunStartedId: (0, assertions_1.ensure)(Cypress.env("testRunStartedId"), "Expected to find a testRunStartedId"), timestamp: start, }); (0, cypress_1.runStepWithLogGroup)({ fn: context.dryRun ? noopFn : () => registry.runRunHook(this, hook), keyword: "BeforeAll", }).then(() => { taskRunHookFinished(context, { testRunHookStartedId, timestamp: (0, messages_1.createTimestamp)(), result: { duration: (0, messages_1.duration)(start, (0, messages_1.createTimestamp)()), status: messages.TestStepResultStatus.PASSED, }, }); }); }); }, cy.wrap({}, { log: false })); while (context.includedPickles.length > 0 && context.includedPickles[0].willBekipped) { emitSkippedPickle(context, context.includedPickles.shift()); } } 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; (0, registry_1.freeRegistry)(); const properties = retrieveInternalSpecProperties(); const { pickle, testCaseStartedId, currentStepStartedAt, remainingSteps } = properties; const endTimestamp = (0, messages_1.createTimestamp)(); if (remainingSteps.length > 0) { try { if (((_a = this.currentTest) === null || _a === void 0 ? void 0 : _a.state) === "failed") { const error = (0, assertions_1.ensure)((_b = this.currentTest) === null || _b === void 0 ? void 0 : _b.err, "Expected to find an error"); const message = (0, assertions_1.ensure)(error.message, "Expected to find an error message"); if (constants_1.EACH_HOOK_FAILURE_EXPR.test(message) || constants_1.ALL_HOOK_FAILURE_EXPR.test(message)) { return; } const failedStep = (0, assertions_1.ensure)(remainingSteps.shift(), "Expected there to be a remaining step"); const hookIdOrPickleStepId = (0, assertions_1.ensure)((_d = (_c = failedStep.hook) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : (_e = failedStep.pickleStep) === null || _e === void 0 ? void 0 : _e.id, "Expected a step to either be a hook or a pickleStep"); const testStepId = getTestStepId({ context, pickleId: pickle.id, hookIdOrPickleStepId, }); const wasUndefinedStepDefinition = message.includes("Step implementation missing"); const failedTestStepFinished = wasUndefinedStepDefinition ? { testStepId, testCaseStartedId, testStepResult: { status: messages.TestStepResultStatus.UNDEFINED, duration: { seconds: 0, nanos: 0, }, }, timestamp: endTimestamp, } : { testStepId, testCaseStartedId, testStepResult: Object.assign(Object.assign({}, (message.includes("Multiple matching step definitions for") ? { status: messages.TestStepResultStatus.AMBIGUOUS, } : { status: messages.TestStepResultStatus.FAILED, exception: { type: error.name || "Error", message }, message, })), { duration: (0, messages_1.duration)((0, assertions_1.ensure)(currentStepStartedAt, "Expected there to be a timestamp for current step"), endTimestamp) }), timestamp: endTimestamp, }; taskTestStepFinished(context, failedTestStepFinished); for (const skippedStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.ensure)((_g = (_f = skippedStep.hook) === null || _f === void 0 ? void 0 : _f.id) !== null && _g !== void 0 ? _g : (_h = skippedStep.pickleStep) === null || _h === void 0 ? void 0 : _h.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, }); } } else if (((_j = this.currentTest) === null || _j === void 0 ? void 0 : _j.state) === "pending") { if (currentStepStartedAt) { const skippedStep = (0, assertions_1.ensure)(remainingSteps.shift(), "Expected there to be a remaining step"); const hookIdOrPickleStepId = (0, assertions_1.ensure)((_l = (_k = skippedStep.hook) === null || _k === void 0 ? void 0 : _k.id) !== null && _l !== void 0 ? _l : (_m = skippedStep.pickleStep) === null || _m === void 0 ? void 0 : _m.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, }); } for (const remainingStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.ensure)((_p = (_o = remainingStep.hook) === null || _o === void 0 ? void 0 : _o.id) !== null && _p !== void 0 ? _p : (_q = remainingStep.pickleStep) === null || _q === void 0 ? void 0 : _q.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, }); } } else { for (const remainingStep of remainingSteps) { const hookIdOrPickleStepId = (0, assertions_1.ensure)((_s = (_r = remainingStep.hook) === null || _r === void 0 ? void 0 : _r.id) !== null && _s !== void 0 ? _s : (_t = remainingStep.pickleStep) === null || _t === void 0 ? void 0 : _t.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, }); } } } catch (e) { if (e instanceof assertions_1.CypressCucumberAssertionError && context.isTrackingState && context.softErrors) { taskFrontEndTrackingError(e); } else { throw e; } } } const currentRetry = (0, assertions_1.ensure)((_u = this.currentTest) === null || _u === void 0 ? void 0 : _u._currentRetry, "Expected to find an attribute _currentRetry"); const retries = (0, assertions_1.ensure)((_v = this.currentTest) === null || _v === void 0 ? void 0 : _v._retries, "Expected to find an attribute _retries"); const willBeRetried = ((_w = this.currentTest) === null || _w === void 0 ? void 0 : _w.state) === "failed" ? currentRetry < retries : false; taskTestCaseFinished(context, { testCaseStartedId, timestamp: endTimestamp, willBeRetried, }); /** * Repopulate internal properties in case previous test is retried. */ if (willBeRetried) { updateInternalSpecProperties({ testCaseStartedId: context.newId(), remainingSteps: [...properties.allSteps], }); } else { context.includedPickles.shift(); while (context.includedPickles.length > 0 && context.includedPickles[0].willBekipped) { emitSkippedPickle(context, context.includedPickles.shift()); } } } function afterHandler(context) { const { registry } = context; registry.resolveAfterAllHooks().reduce((chain, hook) => { return chain.then(() => { const testRunHookStartedId = context.newId(); const start = (0, messages_1.createTimestamp)(); taskRunHookStarted(context, { id: testRunHookStartedId, hookId: hook.id, testRunStartedId: (0, assertions_1.ensure)(Cypress.env("testRunStartedId"), "Expected to find a testRunStartedId"), timestamp: start, }); (0, cypress_1.runStepWithLogGroup)({ fn: context.dryRun ? noopFn : () => registry.runRunHook(this, hook), keyword: "AfterAll", }).then(() => { taskRunHookFinished(context, { testRunHookStartedId, timestamp: (0, messages_1.createTimestamp)(), result: { duration: (0, messages_1.duration)(start, (0, messages_1.createTimestamp)()), status: messages.TestStepResultStatus.PASSED, }, }); }); }); }, cy.wrap({}, { log: false })); } function createTests(registry, seed, source, gherkinDocument, pickles, isTrackingState, softErrors, omitFiltered, stepDefinitionHints, dryRun) { const prng = (0, seedrandom_1.default)(seed.toString()); const newId = () => (0, uuid_1.v4)({ random: Uint8Array.of(...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: getSourceReferenceFromPosition(stepDefinition.position), lexicalOrder: stepDefinition.lexicalOrder, }; }); const runHooks = registry.runHooks.map((runHook) => { return { id: runHook.id, sourceReference: getSourceReferenceFromPosition(runHook.position), type: runHook.keyword === "BeforeAll" ? messages.HookType.BEFORE_TEST_RUN : messages.HookType.AFTER_TEST_RUN, lexicalOrder: runHook.lexicalOrder, }; }); const testStepIds = new Map(); const includedPickles = pickles.filter((pickle) => { return !omitFiltered || !shouldSkipPickle(testFilter, pickle); }); const testCases = includedPickles.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 stepDefinitions = registry.getMatchingStepDefinitions(pickleStep.text); return { id: createTestStepId({ testStepIds, newId, pickleId: pickle.id, hookIdOrPickleStepId: pickleStep.id, }), pickleStepId: pickleStep.id, stepDefinitionIds: stepDefinitions.map((stepDefinition) => stepDefinition.id), stepMatchArgumentsLists: stepDefinitions.map((stepDefinition) => { const result = stepDefinition.expression.match(pickleStep.text); return { stepMatchArguments: (result !== null && result !== void 0 ? result : []).map((arg) => { return { group: mapArgumentGroup(arg.group), parameterTypeName: arg.parameterType.name, }; }), }; }), }; }; 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.ensure)(gherkinDocument.uri, "Expected gherkin document to have URI"), mediaType: messages.SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN, }, }); specEnvelopes.push({ gherkinDocument, }); for (const pickle of includedPickles) { specEnvelopes.push({ pickle, }); } const parameterTypes = Array.from(registry.parameterTypeRegistry.parameterTypes) .filter((parameterType) => !parameterType.builtin) .map((parameterType) => { return { id: newId(), name: parameterType.name, preferForRegularExpressionMatch: parameterType.preferForRegexpMatch, regularExpressions: parameterType.regexpStrings, useForSnippets: parameterType.useForSnippets, sourceReference: getSourceReferenceFromPosition(), lexicalOrder: (0, assertions_1.ensure)(registry.parameterTypeOrdering.get(parameterType), "Expected parameter type to have a lexical order"), }; }); const caseHooks = registry.caseHooks.map((hook) => { return { id: hook.id, name: hook.name, sourceReference: getSourceReferenceFromPosition(hook.position), tagExpression: hook.tags, type: hook.keyword === "Before" ? messages.HookType.BEFORE_TEST_CASE : messages.HookType.AFTER_TEST_CASE, lexicalOrder: hook.lexicalOrder, }; }); const userCode = [ ...stepDefinitions.map((stepDefinition) => { return { stepDefinition }; }), ...runHooks.map((runHook) => { return { runHook }; }), ...caseHooks.map((caseHook) => { return { caseHook }; }), ...parameterTypes.map((parameterType) => { return { parameterType }; }), ]; userCode.sort((a, b) => { const userCodeA = a.stepDefinition || a.runHook || a.caseHook || a.parameterType; const userCodeB = b.stepDefinition || b.runHook || b.caseHook || b.parameterType; return userCodeA.lexicalOrder - userCodeB.lexicalOrder; }); const omit = (obj, key) => { const _a = obj, _b = key, _omitted = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); return rest; }; for (const userCodeEl of userCode) { const { stepDefinition, runHook, caseHook, parameterType } = userCodeEl; if (stepDefinition) { specEnvelopes.push({ stepDefinition: omit(stepDefinition, "lexicalOrder"), }); } else if (runHook) { specEnvelopes.push({ hook: omit(runHook, "lexicalOrder"), }); } else if (caseHook) { s