Token Snapshot Testing
Token Snapshot Testing
Token snapshot testing captures the current state of tokens and compares against that baseline to detect changes. Snapshot tests excel at catching unintended modifications that other test types might miss. When tokens change unexpectedly, snapshot tests fail, prompting review before changes propagate.
What Is Token Snapshot Testing
Token snapshot testing stores a copy of token values or generated outputs, then compares future test runs against this stored snapshot. Any difference between current state and snapshot triggers a test failure, requiring explicit acknowledgment before updates proceed.
Snapshots serve as a regression detection mechanism, ensuring token changes are intentional and reviewed rather than accidental.
How Token Snapshot Testing Works
Source token snapshots capture raw definitions:
// token.test.js
import tokens from './tokens.json';
test('token values match snapshot', () => {
expect(tokens).toMatchSnapshot();
});
First run creates __snapshots__/token.test.js.snap:
exports[`token values match snapshot 1`] = `
{
"color": {
"primary": "#3B82F6",
"background": "#FFFFFF"
}
}
`;
Output snapshots capture generated files:
import fs from 'fs';
test('CSS output matches snapshot', () => {
const css = fs.readFileSync('dist/tokens.css', 'utf8');
expect(css).toMatchSnapshot();
});
Inline snapshots embed expected values:
test('primary color value', () => {
expect(tokens.color.primary).toMatchInlineSnapshot(`"#3B82F6"`);
});
Selective snapshots focus on critical subsets:
test('semantic colors match snapshot', () => {
const semanticColors = {
primary: tokens.color.action.primary,
error: tokens.color.status.error,
success: tokens.color.status.success
};
expect(semanticColors).toMatchSnapshot();
});
Key Considerations
- Snapshot updates should require explicit approval
- Large snapshots can obscure meaningful changes
- Snapshot maintenance is ongoing work
- CI should fail on snapshot mismatches
- Review process should examine snapshot diffs carefully
- Formatting changes can cause false positives
- Selective snapshots are easier to review than complete dumps
- Snapshot naming should identify what is captured
Common Questions
When should snapshots be updated?
Snapshots should be updated when changes are intentional and reviewed.
Legitimate update triggers:
- Token values intentionally changed
- New tokens added to the system
- Token structure reorganized
- Output format improved
Update workflow:
- Developer makes token changes
- Tests fail showing snapshot diff
- Developer reviews diff for correctness
- Developer runs
jest --updateSnapshotor equivalent - Updated snapshots committed with changes
- Code review includes snapshot diff examination
Review questions:
- Does the diff show expected changes only?
- Are there unexpected side effects?
- Do removed tokens have migration paths?
- Are value changes intentional?
CI enforcement:
- name: Test tokens
run: npm test -- --ci
# --ci flag fails on snapshot updates, requiring explicit local update
How should snapshot scope be managed?
Snapshot scope affects maintainability and review quality.
Full snapshots capture everything:
test('all tokens', () => {
expect(allTokens).toMatchSnapshot();
});
Advantages: Complete coverage, catches any change Disadvantages: Large diffs, hard to review, noisy
Categorical snapshots group by type:
test('color tokens', () => {
expect(tokens.color).toMatchSnapshot();
});
test('spacing tokens', () => {
expect(tokens.spacing).toMatchSnapshot();
});
Advantages: Focused diffs, easier review Disadvantages: Multiple snapshots to maintain
Critical-only snapshots cover high-value tokens:
const criticalTokens = [
'color.primary',
'color.error',
'spacing.base'
];
test('critical tokens', () => {
const critical = criticalTokens.reduce((acc, path) => {
acc[path] = get(tokens, path);
return acc;
}, {});
expect(critical).toMatchSnapshot();
});
Advantages: Small, focused, easy to review Disadvantages: May miss changes in non-critical tokens
How do snapshots complement other testing?
Snapshots work alongside other test types:
Unit tests validate specific properties:
test('primary color is valid hex', () => {
expect(tokens.color.primary).toMatch(/^#[A-Fa-f0-9]{6}$/);
});
Unit tests verify correctness; snapshots verify stability.
Visual tests capture rendered appearance:
// Chromatic or Percy capture visual output
export const ColorPalette = () => <SwatchGrid tokens={colors} />;
Visual tests catch rendering issues; snapshots catch value changes.
Accessibility tests verify compliance:
test('contrast ratio', () => {
expect(getContrast(text, bg)).toBeGreaterThan(4.5);
});
Accessibility tests verify safety; snapshots catch drift.
Snapshots fill the gap of detecting unintended changes that pass other validations.
Summary
Token snapshot testing captures token state for comparison against future changes, detecting regressions through diff comparison. Snapshots should be updated intentionally with proper review. Scope management balances completeness with review quality. Snapshots complement unit tests, visual tests, and accessibility tests by focusing specifically on change detection rather than correctness validation.
Buoy scans your codebase for design system inconsistencies before they ship
Detect Design Drift Free