gherkin
Version:
251 lines (230 loc) • 7.12 kB
text/typescript
import countSymbols from '../countSymbols'
import { messages } from 'cucumber-messages'
import IGherkinDocument = messages.IGherkinDocument
export default function compile(gherkinDocument: IGherkinDocument) {
const pickles: messages.IPickle[] = []
if (gherkinDocument.feature == null) {
return pickles
}
const feature = gherkinDocument.feature
const language = feature.language
const featureTags = feature.tags
let backgroundSteps: messages.GherkinDocument.Feature.IStep[] = []
feature.children.forEach(stepsContainer => {
if (stepsContainer.background) {
backgroundSteps = pickleSteps(stepsContainer.background)
} else if (stepsContainer.rule) {
compileRule(
featureTags,
backgroundSteps,
stepsContainer.rule,
language,
pickles
)
} else if (stepsContainer.scenario.examples.length === 0) {
compileScenario(
featureTags,
backgroundSteps,
stepsContainer.scenario,
language,
pickles
)
} else {
compileScenarioOutline(
featureTags,
backgroundSteps,
stepsContainer.scenario,
language,
pickles
)
}
})
return pickles
}
function compileRule(
featureTags: messages.GherkinDocument.Feature.ITag[],
inheritedBackgroundSteps: messages.GherkinDocument.Feature.IStep[],
rule: messages.GherkinDocument.Feature.FeatureChild.IRule,
language: string,
pickles: messages.IPickle[]
) {
let backgroundSteps = [].concat(inheritedBackgroundSteps)
rule.children.forEach(stepsContainer => {
if (stepsContainer.background) {
backgroundSteps = backgroundSteps.concat(
pickleSteps(stepsContainer.background)
)
} else if (stepsContainer.scenario.examples.length === 0) {
compileScenario(
featureTags,
backgroundSteps,
stepsContainer.scenario,
language,
pickles
)
} else {
compileScenarioOutline(
featureTags,
backgroundSteps,
stepsContainer.scenario,
language,
pickles
)
}
})
}
function compileScenario(
featureTags: messages.GherkinDocument.Feature.ITag[],
backgroundSteps: messages.GherkinDocument.Feature.IStep[],
scenario: messages.GherkinDocument.Feature.IScenario,
language: string,
pickles: messages.IPickle[]
) {
const steps = scenario.steps.length === 0 ? [] : [].concat(backgroundSteps)
const tags = [].concat(featureTags).concat(scenario.tags)
scenario.steps.forEach(step => steps.push(pickleStep(step)))
const pickle = messages.Pickle.fromObject({
tags: pickleTags(tags),
name: scenario.name,
language,
locations: [scenario.location],
steps,
})
pickles.push(pickle)
}
function compileScenarioOutline(
featureTags: messages.GherkinDocument.Feature.ITag[],
backgroundSteps: messages.GherkinDocument.Feature.IStep[],
scenario: messages.GherkinDocument.Feature.IScenario,
language: string,
pickles: messages.IPickle[]
) {
scenario.examples
.filter(e => e.tableHeader !== null)
.forEach(examples => {
const variableCells = examples.tableHeader.cells
examples.tableBody.forEach(values => {
const valueCells = values.cells
const steps =
scenario.steps.length === 0 ? [] : [].concat(backgroundSteps)
const tags = []
.concat(featureTags)
.concat(scenario.tags)
.concat(examples.tags)
scenario.steps.forEach(scenarioOutlineStep => {
const stepText = interpolate(
scenarioOutlineStep.text,
variableCells,
valueCells
)
const args = createPickleArguments(
scenarioOutlineStep,
variableCells,
valueCells
)
steps.push(
messages.Pickle.PickleStep.fromObject({
text: stepText,
argument: args,
locations: [
pickleStepLocation(scenarioOutlineStep),
values.location,
],
})
)
})
pickles.push(
messages.Pickle.fromObject({
name: interpolate(scenario.name, variableCells, valueCells),
language,
steps,
tags: pickleTags(tags),
locations: [scenario.location, values.location],
})
)
})
})
}
function createPickleArguments(
step: messages.GherkinDocument.Feature.IStep,
variableCells: messages.GherkinDocument.Feature.TableRow.ITableCell[],
valueCells: messages.GherkinDocument.Feature.TableRow.ITableCell[]
) {
if (step.dataTable) {
const argument = step.dataTable
const table = {
rows: argument.rows.map(row => {
return {
cells: row.cells.map(cell => {
return {
location: cell.location,
value: interpolate(cell.value, variableCells, valueCells),
}
}),
}
}),
}
return {
dataTable: table,
}
} else if (step.docString) {
const argument = step.docString
const docString = messages.PickleStepArgument.PickleDocString.fromObject({
location: argument.location,
content: interpolate(argument.content, variableCells, valueCells),
})
if (argument.contentType) {
docString.contentType = interpolate(
argument.contentType,
variableCells,
valueCells
)
}
return {
docString,
}
}
}
function interpolate(
name: string,
variableCells: messages.GherkinDocument.Feature.TableRow.ITableCell[],
valueCells: messages.GherkinDocument.Feature.TableRow.ITableCell[]
) {
variableCells.forEach((variableCell, n) => {
const valueCell = valueCells[n]
const search = new RegExp('<' + variableCell.value + '>', 'g')
// JS Specific - dollar sign needs to be escaped with another dollar sign
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
const replacement = valueCell.value.replace(new RegExp('\\$', 'g'), '$$$$')
name = name.replace(search, replacement)
})
return name
}
function pickleSteps(
scenarioDefinition: messages.GherkinDocument.Feature.IScenario
) {
return scenarioDefinition.steps.map(pickleStep)
}
function pickleStep(step: messages.GherkinDocument.Feature.IStep) {
return messages.Pickle.PickleStep.fromObject({
text: step.text,
argument: createPickleArguments(step, [], []),
locations: [pickleStepLocation(step)],
})
}
function pickleStepLocation(step: messages.GherkinDocument.Feature.IStep) {
return messages.Location.fromObject({
line: step.location.line,
column:
step.location.column + (step.keyword ? countSymbols(step.keyword) : 0),
})
}
function pickleTags(tags: messages.GherkinDocument.Feature.ITag[]) {
return tags.map(pickleTag)
}
function pickleTag(tag: messages.GherkinDocument.Feature.ITag) {
return messages.Pickle.PickleTag.fromObject({
name: tag.name,
location: tag.location,
})
}