Skip to content

Commit

Permalink
feat: several additions to QuickPickleWorldInterface, fix explodeTags…
Browse files Browse the repository at this point in the history
…, refactor

feat: add QuickPickleWorld.toString() function that renders to a single descriptive line
feat: add QuickPickleWorld.info.stepIdx, to get the line number of the step within the scenario
feat: add QuickPickleWorld.info.explodedIdx, to get the index number for exploded tags
chore: renamed "qp" function to "gherkinStep", for better readability in traces
fix: fixed the explodeTags functionality when rendering
test: added tons of tests for the explodeTags functionality
  • Loading branch information
dnotes committed Oct 21, 2024
1 parent d3586c2 commit 94902af
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 58 deletions.
12 changes: 12 additions & 0 deletions .changeset/silent-parrots-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"quickpickle": minor
---

feat: several additions to QuickPickleWorldInterface, fix explodeTags, refactor

feat: add QuickPickleWorld.toString() function that renders to a single descriptive line
feat: add QuickPickleWorld.info.stepIdx, to get the line number of the step within the scenario
feat: add QuickPickleWorld.info.explodedIdx, to get the index number for exploded tags
chore: renamed "qp" function to "gherkinStep", for better readability in traces
fix: fixed the explodeTags functionality when rendering
test: added tons of tests for the explodeTags functionality
12 changes: 12 additions & 0 deletions packages/main/gherkin-example/example.feature
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,15 @@ Feature: QuickPickle's Comprehensive Gherkin Syntax Example
Given a Rule statement
When another Rule is indented below it
Then the indented Rule is NOT a child of the previous Rule

@1a @1b
Scenario: Exploded tags make multiple tests
Given an explodedTags config of [[ '@1a','@1b' ], [ '@2a','@2b' ]]
When this Scenario is run
Then it should be split into 2 tests

@1a @1b @2a @2b @tag3
Scenario: More tags make more tests
Given an explodedTags config of [[ '@1a','@1b' ], [ '@2a','@2b' ]]
When this Scenario is run
Then it should be split into 4 tests
136 changes: 96 additions & 40 deletions packages/main/gherkin-example/example.feature.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/main/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ interface StepDefinitionMatch {
parameters: any[];
}

export const qp = async (step: string, state: any, line: number, data?: any): Promise<any> => {
export const gherkinStep = async (step: string, state: any, line: number, stepIdx:number, explodeIdx?:number, data?:any): Promise<any> => {
const stepDefinitionMatch: StepDefinitionMatch = findStepDefinitionMatch(step);

// Set the state info
state.info.step = step
state.info.line = line
state.info.stepIdx = stepIdx
state.info.explodedIdx = explodeIdx

// Sort out the DataTable or DocString
if (Array.isArray(data)) {
Expand Down
30 changes: 17 additions & 13 deletions packages/main/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function renderGherkin(src:string, config:QuickPickleConfig, isMarkdown?:
return `// Generated by quickpickle
import { test, describe, beforeAll, afterAll } from 'vitest';
import {
qp,
gherkinStep,
applyBeforeAllHooks,
applyBeforeHooks,
applyAfterAllHooks,
Expand Down Expand Up @@ -95,7 +95,7 @@ function renderChildren(children:RuleChild[]|FeatureChild[], config:QuickPickleC
if (!children.length) return output

if (children[0].hasOwnProperty('background')) {
output.backgroundSteps = renderSteps(children.shift()!.background!.steps as Step[], config, sp)
output.backgroundSteps = renderSteps(children.shift()!.background!.steps as Step[], config, sp, '', true)
}

for (let child of children) {
Expand Down Expand Up @@ -169,10 +169,10 @@ ${sp}test${attrs}.for(${JSON.stringify(paramValues)})(
${sp} '${q(child.scenario?.keyword || '')}: ${describe}',
${sp} async ({ ${paramNames?.join(', ')} }, context) => {
${sp} let state = await ${initFn}(context, \`${name}\`, ['${tags.join("', '") || ''}']);
${child.scenario?.steps.map((step,i) => {
${child.scenario?.steps.map((step,idx) => {
let text = step.text.replace(/`/g, '\\`')
text = replaceParamNames(text,true)
return `${sp} await qp(\`${text}\`, state, ${step.location.line}${isExploded ? '.' + explodedIdx : ''});`
return `${sp} await gherkinStep(\`${text}\`, state, ${step.location.line}, ${idx+1}${isExploded ? `, ${explodedIdx + 1}` : ''});`
}).join('\n')
}
${sp} await afterScenario(state);
Expand All @@ -184,28 +184,29 @@ ${sp});
return `
${sp}test${attrs}('${q(child.scenario!.keyword)}: ${q(child.scenario!.name)}', async (context) => {
${sp} let state = await ${initFn}(context, '${q(child.scenario!.name)}', ['${tags.join("', '") || ''}']);
${renderSteps(child.scenario!.steps as Step[], config, sp + ' ', isExploded ? `.${explodedIdx}` : '')}
${renderSteps(child.scenario!.steps as Step[], config, sp + ' ', isExploded ? `${explodedIdx+1}` : '')}
${sp} await afterScenario(state);
${sp}});
`
}).join('\n\n')
}

function renderSteps(steps:Step[], config:QuickPickleConfig, sp = ' ', explodedText = '') {
return steps.map(step => {
function renderSteps(steps:Step[], config:QuickPickleConfig, sp = ' ', explodedText = '', isBackground:boolean = false) {
let minus = isBackground ? '-' : ''
return steps.map((step,idx) => {

if (step.dataTable) {
let data = JSON.stringify(step.dataTable.rows.map(r => {
return r.cells.map(c => c.value)
}))
return `${sp}await qp('${q(step.text)}', state, ${step.location.line}${explodedText}, ${data});`
return `${sp}await gherkinStep('${q(step.text)}', state, ${step.location.line}, ${minus}${idx+1}, ${explodedText || 'undefined'}, ${data});`
}
else if (step.docString) {
let data = JSON.stringify(pick(step.docString, ['content','mediaType']))
return `${sp}await qp('${q(step.text)}', state, ${step.location.line}${explodedText}, ${data});`
return `${sp}await gherkinStep('${q(step.text)}', state, ${step.location.line}, ${minus}${idx+1}, ${explodedText || 'undefined'}, ${data});`
}

return `${sp}await qp('${q(step.text)}', state, ${step.location.line}${explodedText});`
return `${sp}await gherkinStep('${q(step.text)}', state, ${step.location.line}, ${minus}${idx+1}${explodedText ? `, ${explodedText}` : ''});`
}).join('\n')
}

Expand All @@ -218,17 +219,20 @@ const q = (t:string) => (t.replace(/'/g, "\\'"))

/**
* Creates a 2d array of all possible combinations of the items in the input array
* @param arr Array
* @param arr A 2d array of strings
* @returns A 2d array of all possible combinations of the items in the input array
*/
function explodeArray(arr: string[][]): string[][] {
export function explodeArray(arr: string[][]): string[][] {
if (arr.length === 0) return [[]];
arr = arr.map(subArr => {
return subArr.length ? subArr : ['']
})

const [first, ...rest] = arr;
const subCombinations = explodeArray(rest);

return first.flatMap(item =>
subCombinations.map(subCombo => [item, ...subCombo])
subCombinations.map(subCombo => [item, ...subCombo].filter(Boolean))
);
}

Expand Down
11 changes: 11 additions & 0 deletions packages/main/src/world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface QuickPickleWorldInterface {
rule?: string,
step?: string,
line?: number,
explodedIdx?: number,
stepIdx?: number,
}
context: TestContext,
common: {
Expand All @@ -33,6 +35,15 @@ export class QuickPickleWorld implements QuickPickleWorldInterface {
tagsMatch(tags: string[]) {
return tagsMatch(tags, this.info.tags)
}
toString() {
let parts = [
this.constructor.name,
this.info.feature,
this.info.scenario + (this.info.explodedIdx ? ` (${this.info.tags.join(',')})` : ''),
`${this.info.stepIdx?.toString().padStart(2,'0')} ${this.info.step}`,
]
return parts.join('_')
}
}

export type WorldConstructor = new (
Expand Down
Loading

0 comments on commit 94902af

Please sign in to comment.