Skip to main content

specification()

Docs for Vitest SDK v0.3.3

specification is the top-level container in the Specification pattern — a simpler alternative to BDD when you need to express technical rules, domain constraints, or unit-level requirements without Given/When/Then ceremony.

import { specification, rule } from "@swedevtools/livedoc-vitest";

specification("Password Validation", () => {
rule("Password must be at least 8 characters", () => {
expect(isValidPassword("short")).toBe(false);
expect(isValidPassword("longenough")).toBe(true);
});

rule("Password must contain a number", () => {
expect(isValidPassword("noNumbers")).toBe(false);
expect(isValidPassword("has1number")).toBe(true);
});
});

Reference​

specification(title, fn)​

Registers a specification block that maps to a Vitest describe() call prefixed with "Specification: ".

function specification(title: string, fn: (ctx: SpecificationCtx) => void): void

See more examples below.

Parameters​

  • title: string — The specification title with optional tags and description. Parsed identically to feature():

    • First line → specification title
    • Lines starting with @ → tags (space-separated)
    • Remaining lines → description text
  • fn: (ctx: SpecificationCtx) => void — Callback containing rule() and/or ruleOutline() calls. Must not be async.

The ctx Parameter​

PropertyTypeDescription
ctx.specificationSpecificationContext{ filename, title, description, tags }

Returns​

void — Specifications are registered as side effects.

Caveats​

  • The callback must not be async. Use async inside individual rule() callbacks.
  • Specifications are the outermost container in the specification pattern — they cannot be nested.
  • Do not mix scenario() inside a specification() — use rule() and ruleOutline() instead.

Modifiers​

specification.skip(title, fn)​

Skip this specification. All rules inside are marked as pending.

specification.skip("Legacy Validation — migrating to new rules", () => {
rule("Old rule", () => { /* skipped */ });
});

specification.only(title, fn)​

Run only this specification. All other specifications and features are skipped.

specification.only("Debugging this specification", () => {
rule("Focus rule", () => { /* only this runs */ });
});

Usage​

Basic: Group related rules​

import { specification, rule } from "@swedevtools/livedoc-vitest";

specification("Email Validation", () => {
rule("Email must contain an @ symbol", () => {
expect(isValidEmail("invalid")).toBe(false);
expect(isValidEmail("user@example.com")).toBe(true);
});

rule("Email must have a domain", () => {
expect(isValidEmail("user@")).toBe(false);
expect(isValidEmail("user@example.com")).toBe(true);
});

rule("Email domain must have a TLD", () => {
expect(isValidEmail("user@example")).toBe(false);
expect(isValidEmail("user@example.com")).toBe(true);
});
});

Tags and description​

import { specification, rule } from "@swedevtools/livedoc-vitest";

specification(`Tax Calculation Rules
@finance @tax @critical
Keeps tax results consistent for the domestic and
international orders covered by these rules.
`, (ctx) => {
rule("A 'CA' order of '100' has tax '7.25'", (ctx) => {
const [state, amount, expectedTax] = ctx.rule.values;
const tax = calculateTax({ state, amount });
expect(tax).toBe(expectedTax);
});

rule("A 'UK' order of '100' has tax '0'", (ctx) => {
const [country, amount, expectedTax] = ctx.rule.values;
const tax = calculateTax({ country, amount });
expect(tax).toBe(expectedTax);
});
});

Accessing specification metadata​

import { specification, rule } from "@swedevtools/livedoc-vitest";

specification(`Specification Metadata
@warehouse @v2
Readers can identify the subject and tags of this published specification.
`, (ctx) => {
rule("Read specification context", () => {
expect(ctx.specification.title).toBe("Specification Metadata");
expect(ctx.specification.tags).toEqual(["warehouse", "v2"]);
expect(ctx.specification.description).toContain("identify the subject and tags");
});
});

Mixing rule and ruleOutline​

import { specification, rule, ruleOutline } from "@swedevtools/livedoc-vitest";

specification("Discount Engine", () => {
rule("No discount for orders under $50", () => {
expect(getDiscount(49)).toBe(0);
});

ruleOutline(`Discount tiers
Examples:
| spend | discount |
| 50 | 0 |
| 100 | 5 |
| 200 | 10 |
| 500 | 15 |
`, (ctx) => {
expect(getDiscount(ctx.example.spend)).toBe(ctx.example.discount);
});
});

See Also​

  • rule() — individual test assertions within a specification
  • ruleOutline() — data-driven rules with examples tables
  • feature() — BDD alternative for user-story-driven tests
  • Context Object — full reference for ctx.specification