Skip to content

Use vitest-cucumber without feature file

defineFeature works like describeFeature but without feature file. You can use function like Scenario, Background, Given etc just to organize your tests.

Since v.6.5.0, ScenarioOutline (and RuleScenarioOutline inside a Rule) is also supported in defineFeature.

import { expect } from 'vitest'
import { defineFeature } from '@amiceli/vitest-cucumber'

defineFeature('Define feature with ScenarioOutline', (f) => {
    const seen: Array<{ name: string; age: number }> = []

    f.ScenarioOutline(
        'Outline with examples',
        (s, variables) => {
            s.Given('user <name> is <age> years old', () => {
                seen.push({
                    name: String(variables.name),
                    age: Number(variables.age),
                })
            })
            s.Then('values are recorded', () => {
                expect(seen.length).toBeGreaterThan(0)
            })
        },
        [
            { name: 'Alice', age: 30 },
            { name: 'Bob', age: 42 },
        ],
    )

    f.Rule('Compute', (r) => {
        const computed: number[] = []

        r.RuleScenarioOutline(
            'Doubles values',
            (s, variables) => {
                s.Given('I have <input>', () => {
                    computed.push(Number(variables.input) * 2)
                })
                s.Then('I get <expected>', () => {
                    expect(computed.at(-1)).toEqual(variables.expected)
                })
            },
            [
                { input: 2, expected: 4 },
                { input: 5, expected: 10 },
            ],
        )
    })
})

f.ScenarioOutline.skip / f.ScenarioOutline.only (and the same on r.RuleScenarioOutline) are also available.

Other features / checks like same step, same scenario etc are present in defineFeature.

import { describe, expect, vi } from 'vitest'
import { defineFeature } from '../define-feature'

defineFeature('Define feature without Gherkin', (f) => {
    let count: number = 0
    const testFn = vi.fn()

    f.AfterEachScenario(() => {
        vi.resetAllMocks()
    })

    f.BeforeEachScenario(() => {
        count += 1
    })

    f.Background((b) => {
        b.Given('I love Background', () => {
            testFn()
        })
    })

    f.Scenario('Use Scenario', (s) => {
        s.context.details = ''

        s.Given('I use scenario', () => {
            expect(s.context.details).toEqual('')
        })
        s.When('I use step', () => {
            s.context.details = 'When'
        })
        s.Then('Code is executed', () => {
            expect(count).toEqual(1)
            expect(testFn).toHaveBeenCalledTimes(1)
        })
    })

    f.Rule('Vitest', (r) => {
        r.context.tests = 1
        r.context.testFn = vi.fn()

        r.RuleBackground.skip((b) => {
            b.Given('I love vitest', () => {
                r.context.tests += 1
                r.context.testFn()
            })
        })
    })
})