From ee59a4efc9997ef67222fa83f11daf7546f6df2e Mon Sep 17 00:00:00 2001 From: Luke Bjerring Date: Sun, 31 May 2020 19:36:58 -0400 Subject: [PATCH] feat: add support for custom step timeout Add support for passing in a config param, matching the signature of cucumber-js, to set the step timeout in cypress. --- lib/createTestFromScenario.js | 8 +- lib/resolveStepDefinition.js | 34 +++++--- lib/testHelpers/setupTestFramework.js | 13 ++- steps/index.d.ts | 110 ++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 steps/index.d.ts diff --git a/lib/createTestFromScenario.js b/lib/createTestFromScenario.js index c30a78d1..14ca3793 100644 --- a/lib/createTestFromScenario.js +++ b/lib/createTestFromScenario.js @@ -1,6 +1,7 @@ /* eslint-disable prefer-template */ const statuses = require("cucumber/lib/status").default; const { + resolveStepDefinition, resolveAndRunStepDefinition, resolveAndRunBeforeHooks, resolveAndRunAfterHooks @@ -15,8 +16,13 @@ const replaceParameterTags = (rowData, text) => // eslint-disable-next-line func-names const stepTest = function(state, stepDetails, exampleRowData) { + const step = resolveStepDefinition.call( + this, + stepDetails, + state.feature.name + ); cy.then(() => state.onStartStep(stepDetails)) - .then(() => + .then((step && step.config) || {}, () => resolveAndRunStepDefinition.call( this, stepDetails, diff --git a/lib/resolveStepDefinition.js b/lib/resolveStepDefinition.js index 83ef4f3c..cb602070 100644 --- a/lib/resolveStepDefinition.js +++ b/lib/resolveStepDefinition.js @@ -18,7 +18,15 @@ class StepDefinitionRegistry { }; this.definitions = []; - this.runtime = (matcher, implementation) => { + this.runtime = (...args) => { + let matcher; + let config; + let implementation; + if (args.length > 2) { + [matcher, config, implementation] = args; + } else { + [matcher, implementation] = args; + } let expression; if (matcher instanceof RegExp) { expression = new RegularExpression( @@ -35,6 +43,7 @@ class StepDefinitionRegistry { this.definitions.push({ implementation, expression, + config, featureName: window.currentFeatureName || "___GLOBAL_EXECUTION___" }); }; @@ -178,6 +187,9 @@ function parseHookArgs(args) { } module.exports = { + resolveStepDefinition(step, featureName) { + return resolveStepDefinition(step, featureName); + }, resolveAndRunBeforeHooks(scenarioTags, featureName) { return resolveAndRunHooks(beforeHookRegistry, scenarioTags, featureName); }, @@ -210,20 +222,20 @@ module.exports = { } throw new Error(`Step implementation missing for: ${stepText}`); }, - given: (expression, implementation) => { - stepDefinitionRegistry.runtime(expression, implementation); + given: (...args) => { + stepDefinitionRegistry.runtime(...args); }, - when: (expression, implementation) => { - stepDefinitionRegistry.runtime(expression, implementation); + when: (...args) => { + stepDefinitionRegistry.runtime(...args); }, - then: (expression, implementation) => { - stepDefinitionRegistry.runtime(expression, implementation); + then: (...args) => { + stepDefinitionRegistry.runtime(...args); }, - and: (expression, implementation) => { - stepDefinitionRegistry.runtime(expression, implementation); + and: (...args) => { + stepDefinitionRegistry.runtime(...args); }, - but: (expression, implementation) => { - stepDefinitionRegistry.runtime(expression, implementation); + but: (...args) => { + stepDefinitionRegistry.runtime(...args); }, Before: (...args) => { const { tags, implementation } = parseHookArgs(args); diff --git a/lib/testHelpers/setupTestFramework.js b/lib/testHelpers/setupTestFramework.js index a636dbbf..7743e5de 100644 --- a/lib/testHelpers/setupTestFramework.js +++ b/lib/testHelpers/setupTestFramework.js @@ -24,9 +24,18 @@ const { After } = require("../resolveStepDefinition"); +const mockedThen = (funcOrConfig, func) => { + if (typeof funcOrConfig === "object") { + func(); + } else { + funcOrConfig(); + } + return { then: mockedThen }; +}; + const mockedPromise = func => { func(); - return { then: mockedPromise }; + return { then: mockedThen }; }; window.defineParameterType = defineParameterType; @@ -46,6 +55,6 @@ window.cy = { startStep: mockedPromise, finishStep: mockedPromise, finishTest: mockedPromise, - then: mockedPromise, + then: mockedThen, end: mockedPromise }; diff --git a/steps/index.d.ts b/steps/index.d.ts new file mode 100644 index 00000000..fa6b3586 --- /dev/null +++ b/steps/index.d.ts @@ -0,0 +1,110 @@ +export function given( + expression: RegExp | string, + implementation: (...args: any[]) => void +): void; +export function when( + expression: RegExp | string, + implementation: (...args: any[]) => void +): void; +export function then( + expression: RegExp | string, + implementation: (...args: any[]) => void +): void; +export function and( + expression: RegExp | string, + implementation: (...args: any[]) => void +): void; +export function but( + expression: RegExp | string, + implementation: (...args: any[]) => void +): void; +export function given( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function when( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function then( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function and( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function but( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function defineStep( + expression: RegExp | string, + implementation: (...args: any[]) => void +): void; +export function defineParameterType(): void; + +// Aliased versions of the above funcs. +export function Given( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function When( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function Then( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function And( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function But( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function Given( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function When( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function Then( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function And( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function But( + expression: RegExp | string, + config: { timeout?: number }, + implementation: (...args: any[]) => void +): void; +export function Before( + optionsOrImplementation: object | ((...args: any[]) => void), + implementation?: (...args: any[]) => void +): void; +export function After( + optionsOrImplementation: object | ((...args: any[]) => void), + implementation?: (...args: any[]) => void +): void;