diff --git a/.changeset/happy-chefs-shout.md b/.changeset/happy-chefs-shout.md new file mode 100644 index 0000000..679f5fa --- /dev/null +++ b/.changeset/happy-chefs-shout.md @@ -0,0 +1,5 @@ +--- +"quickpickle": patch +--- + +Render empty Features and Rules without errors. diff --git a/packages/main/src/render.ts b/packages/main/src/render.ts index 3a3455d..aee6176 100644 --- a/packages/main/src/render.ts +++ b/packages/main/src/render.ts @@ -19,8 +19,9 @@ export function renderGherkin(src:string, config:QuickPickleConfig, isMarkdown?: const gherkinDocument = isMarkdown ? mdParser.parse(src) : gherkinParser.parse(src) // Exit if there's no feature or scenarios - if (!gherkinDocument?.feature || !gherkinDocument.feature?.children?.length) { - return '' + if (!gherkinDocument?.feature) { + return `import { test } from 'vitest' + test.skip('')` } return `// Generated by quickpickle @@ -93,7 +94,7 @@ function renderChildren(children:RuleChild[]|FeatureChild[], config:QuickPickleC children: '', } - if (!children.length) return output + if (!children.length) return { ...output, children: `${sp} test.skip('');`} if (children[0].hasOwnProperty('background')) { output.backgroundSteps = renderSteps(children.shift()!.background!.steps as Step[], config, sp, '', true) diff --git a/packages/main/tests/renderer.feature b/packages/main/tests/renderer.feature new file mode 100644 index 0000000..c4f8291 --- /dev/null +++ b/packages/main/tests/renderer.feature @@ -0,0 +1,83 @@ +Feature: Rendering engine + + Rule: Empty Features and Rules should be allowed + + Scenario: Render completely empty feature file + Given the following feature file is rendered: "" + Then the rendered feature file should contain: + ```js + import { test } from 'vitest' + test.skip('') + ``` + + Scenario Outline: Render empty Features + Given the following feature file is rendered: "" + Then the rendered feature file should contain: + ```js + , () => { + test.skip('') + }) + ``` + + Examples: + | feature | + | Feature: | + | Feature: Empty | + + Scenario: Render empty features with descriptions + Given the following feature file is rendered: + ```gherkin + Feature: Empty + + As a developer or project lead + I want to be able to write empty Feature files + In anticipation of future development + ``` + Then the rendered feature file should contain "describe('Feature: Empty', () => {" + And the rendered feature file should contain: + ```js + , () => { + test.skip('') + }) + ``` + + Scenario: Render empty Rules without error + Given the following feature file: + ```gherkin + Feature: Empty Rules + + Rule: Empty + ``` + When the feature is rendered + Then the rendered feature file should contain: + ```js + describe('Rule: Empty', () => { + const initRuleScenario = async (context, scenario, tags, steps) => { + let state = await initScenario(context, scenario, tags, steps) + state.info.rule = 'Empty' + return state + } + test.skip('') + }) + ``` + + Scenario: Render empty Rules with descriptions + Given the following feature file: + ```gherkin + Feature: Empty Rules + + Rule: Empty + Rules can have descriptions too + ``` + When the feature is rendered + Then the rendered feature file should contain: + ```js + describe('Rule: Empty', () => { + const initRuleScenario = async (context, scenario, tags, steps) => { + let state = await initScenario(context, scenario, tags, steps) + state.info.rule = 'Empty' + return state + } + test.skip('') + }) + ``` diff --git a/packages/main/tests/tests.steps.ts b/packages/main/tests/tests.steps.ts index c3ee5cd..4a2880c 100644 --- a/packages/main/tests/tests.steps.ts +++ b/packages/main/tests/tests.steps.ts @@ -1,8 +1,9 @@ import { expect } from "vitest"; -import { Given, Then, When, defineParameterType } from "../src"; +import { Given, Then, When, defaultConfig, defineParameterType } from "../src"; import type { DataTable } from "../src"; -import { clone, get, set } from "lodash-es"; +import { clone, get, set, escapeRegExp } from "lodash-es"; import type { DocString } from "../src/models/DocString"; +import { renderGherkin } from "../src/render"; defineParameterType({ name: 'updown', @@ -94,4 +95,34 @@ Then('the flag should be set', (world) => { // CUSTOM PARAMETER TYPES When('I push all the numbers {updown}( again)', (world, updown:'up'|'down') => { world.numbers = world.numbers.map(n => updown === 'up' ? n+1 : n-1) +}) + +// RENDERER + +Given("the following feature( file)( is rendered):", (world, feature:DocString) => { + world.data.featureText = feature; + world.data.featureRendered = renderGherkin(world.data.featureText, world.data.featureConfig ?? {}, (world.data.featureText?.mediaType === 'md' || world.data.featureText?.mediaType === 'markdown')); +}); +Given("the following feature( file)( is rendered): {string}", (world, feature:string) => { + world.data.featureText = feature; + world.data.featureRendered = renderGherkin(world.data.featureText, world.data.featureConfig ?? {}, (world.data.featureText?.mediaType === 'md' || world.data.featureText?.mediaType === 'markdown')); +}); +Given("the following quickpickle config/configuration json/JSON:", (world, config:DocString) => { + world.data.featureConfig = JSON.parse((config.toString())); +}); +When("the feature is rendered", (world) => { + world.data.featureRendered = renderGherkin(world.data.featureText, world.data.featureConfig ?? {}, (world.data.featureText?.mediaType === 'md' || world.data.featureText?.mediaType === 'markdown')); +}); +Then("the rendered feature (file )should contain {string}", (world, expected) => { + expect(world.data.featureRendered).toMatch(expected); +}) +Then("the rendered feature (file )should contain:", (world, expected) => { + expect(world.data.featureRendered).toMatch( + // Create a new RegExp from the docString + new RegExp(escapeRegExp(expected.toString()) + // Ignore omitted semicolons (in test code), number of newlines, or spacing at the start of lines + .replace(/\n+/gm, ';?[\\n\\s]+') + // Ignore newlines and spacing at the start of the test string + .replace(/^/gm, '[\\n\\s]*')) + ); }) \ No newline at end of file