All skills
lexler avatar

/approval-tests

@83aee6a
by Lada Kesselerlexler/skill-factory238 stars
61

Writes approval tests (snapshot/golden master testing) for Python, JavaScript/TypeScript, or Java. Use when verifying complex output, characterization testing legacy code, testing combinations, or working with .approved/.received files.

Use this Skill: https://skilld.dev/gh/lexler/skill-factory/approval-tests

This session only. Nothing lands on disk.

referencespythonpatterns.md

≈1.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Python Testing Patterns

Contents

Quick Decision Guide

  • Objects → verify_as_json(obj), not verify(str(obj))
  • Lists (structured) → verify_as_json({"items": items})
  • Lists (labeled) → verify_all("Items", items, formatter)
  • Non-deterministic data → scrubbers, add before first run (scrubbers.md)
  • Multiple scenarios per test → NamerFactory.with_parameters(), not multiple verify() calls
  • Input combinations → combinations.md
  • State progression → Storyboard (api.md)
  • Log output → logging.md

Characterization Tests

Capture existing behavior before refactoring:

from approvaltests import verify

def test_legacy_billing():
    result = legacy_billing_system.calculate(test_order)
    verify(result)

Run once to capture current behavior as baseline. The approval file becomes your safety net during refactoring.

Multiple Approvals Per Test

By default, one verify() per test. For multiple approvals, use NamerFactory.with_parameters().

Parametrized Tests (pytest)

import pytest
from approvaltests import verify
from approvaltests.namer import NamerFactory

@pytest.mark.parametrize("year", [1992, 1993, 1900, 2000])
def test_leap_year(year):
    result = is_leap_year(year)
    verify(f"{year}: {result}", options=NamerFactory.with_parameters(year))

Creates: test_leap_year.1992.approved.txt, test_leap_year.1993.approved.txt, etc.

Multiple Verifies in One Test

from approvaltests import verify, settings
from approvaltests.namer import NamerFactory

def test_multiple():
    settings().allow_multiple_verify_calls_for_this_method()

    verify(result1, options=NamerFactory.with_parameters("scenario1"))
    verify(result2, options=NamerFactory.with_parameters("scenario2"))

Run All, Report All Failures

from approvaltests import verify
from approvaltests.asserts import gather_all_exceptions_and_throw
from approvaltests.namer import NamerFactory

def test_all_scenarios():
    scenarios = ["a", "b", "c", "d"]
    gather_all_exceptions_and_throw(
        scenarios,
        lambda s: verify(process(s), options=NamerFactory.with_parameters(s))
    )

Adding Suffix to Filename

from approvaltests import verify, Options

verify(result, options=Options().for_file.with_additional_information("scenario1"))

Creates: TestClass.test_method.scenario1.approved.txt

Common Mistakes

Mixing approvals with assertions

The approval captures everything. If you're adding assertions alongside verify(), you're probably testing two things.

# Not this
def test_user():
    user = create_user()
    assert user.id > 0
    verify_as_json(user)

# This - the approval captures everything including id
def test_user():
    verify_as_json(create_user())

Over-approving

Approving an entire database record when you only care about one field. Large approvals hide real changes in noise.

# Not this - approves 50 fields when you care about 3
verify_as_json(full_user_record)

# This - approve only what matters
verify_as_json({
    "name": user.name,
    "email": user.email,
    "status": user.status,
})

Under-scrubbing

Tests pass locally, fail in CI.

If it varies by environment, scrub it:

  • Timestamps
  • UUIDs/GUIDs
  • File paths
  • Hostnames
  • Process IDs

Hand-editing .approved files

Breaks the contract. The approved file should only be created by running the test and approving the received output.

If the output is wrong, fix the code and regenerate.

Multiple verify() without NamerFactory

Each verify() overwrites the same file. Only the last one is tested.

# Broken - only tests result2
def test_both():
    verify(result1)
    verify(result2)

# Fixed - separate files
def test_both():
    settings().allow_multiple_verify_calls_for_this_method()
    verify(result1, options=NamerFactory.with_parameters("first"))
    verify(result2, options=NamerFactory.with_parameters("second"))

Source: SKILL.md on GitHub

1 warning6d4 checks · Risk SAFE
  • Gen Agent Trust Hub6d

    The skill provides instructions and patterns for implementing approval testing (snapshot testing) across multiple programming languages. It includes capabilities for file system operations, command execution for testing CLI tools, and launching external diff reporters, which are consistent with the skill's purpose. The analysis identified an indirect prompt injection surface when verifying external or untrusted data.

  • Socket6d

    No alerts

  • Snyk6d

    Risk: LOW · No issues

  • Runlayer7mo

    25/25 files flagged

Signed by skilld at 83aee6a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 8 months ago

README badge

README badge for lexler/skill-factory/approval-tests