smithery.ai

e11y-tdd

Use when implementing Phoenix LiveView features - TDD with html_snapshot for state inspection and axe-core for accessibility. Sprinkle snapshots to see what's rendered, delete when done.

First seen May 1, 2026

Installation

$ npx skills add https://smithery.ai

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,876 B
  • docs SUMMARY.md 199 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Excessibility TDD - Build with Inspection

Build Phoenix LiveView features with full visibility into rendered HTML and state.

Core Powers

  • html_snapshot(view) - Capture HTML at any point (sprinkle liberally while building)
  • axe-core checks - Ensure accessibility (WCAG compliance)
  • Timeline analysis - See state evolution across events

The e11y-TDD Cycle

1. EXPLORE   - Add html_snapshot(view) calls to see what's rendered
2. RED       - Write test with snapshot at key moment
3. GREEN     - Implement feature, use snapshots to debug
4. CHECK     - Run `mix excessibility` for axe-core/a11y validation
5. CLEAN     - Remove temporary snapshots, keep essential ones

Snapshot Strategies

Temporary Snapshots (for building/debugging)

Sprinkle these while building. Delete when feature works.

test "building new feature" do
  {:ok, view, _html} = live(conn, "/page")

  # Sprinkle these to see what's happening
  html_snapshot(view)  # <- see initial state

  view |> element("button") |> render_click()
  html_snapshot(view)  # <- see after click

  view |> form("#my-form") |> render_submit(%{name: "test"})
  html_snapshot(view)  # <- see after submit

  # Delete these when feature works
end

Permanent Snapshots (for regression testing)

Keep these - axe-core will check them on every run.

test "feature works and is accessible" do
  {:ok, view, _html} = live(conn, "/page")
  view |> element("button") |> render_click()

  # Keep this - axe-core will check it on every run
  html_snapshot(view)
end

When to Use

  • Building any LiveView feature - snapshots show you what's rendered
  • Debugging state issues - sprinkle snapshots, inspect, delete
  • Accessibility compliance - axe-core catches WCAG violations
  • Form implementations - see validation errors, field states
  • Modals/dialogs - verify focus management, aria attributes
  • Dynamic content - check aria-live regions render correctly

Commands

# Run tests (generates snapshots)
mix test test/my_live_view_test.exs

# Check accessibility on all snapshots
mix excessibility

# Run specific test then check its snapshots
mix excessibility test/my_live_view_test.exs

# Debug with timeline analysis
mix excessibility.debug test/my_live_view_test.exs

Reading Snapshots

After running tests, check:

test/excessibility/
  html_snapshots/           # HTML files from html_snapshot() calls
    MyApp_PageTest_42.html  # Module_Line.html naming
  timeline.json             # State evolution (if using debug)

Open HTML files in browser to see exactly what was rendered.

Common Patterns

Form with Validation

test "form shows validation errors accessibly" do
  {:ok, view, _html} = live(conn, "/register")

  # Submit empty form
  view |> form("#register-form") |> render_submit(%{})

  # Snapshot captures error state - axe-core will check:
  # - Error messages are associated with inputs (aria-describedby)
  # - Required fields are marked (aria-required)
  # - Invalid fields have aria-invalid
  html_snapshot(view)
end

Modal/Dialog

test "modal is accessible" do
  {:ok, view, _html} = live(conn, "/page")

  # Open modal
  view |> element("#open-modal") |> render_click()

  # Snapshot captures modal state - axe-core will check:
  # - role="dialog" or aria-modal
  # - aria-labelledby for title
  # - Focus trapped inside modal
  html_snapshot(view)
end

Loading States

test "loading state is accessible" do
  {:ok, view, _html} = live(conn, "/dashboard")

  # Trigger async load
  view |> element("#refresh") |> render_click()

  # Snapshot during loading - axe-core will check:
  # - aria-busy on loading container
  # - Loading indicator has appropriate role
  html_snapshot(view)
end

Debugging Tips

  1. Too much output? Use named snapshots:

``elixir htmlsnapshot(view, name: "afterclick") htmlsnapshot(view, name: "witherrors") ``

  1. Need to see assigns/state? Use debug mode:

``bash mix excessibility.debug test/my_test.exs ``

  1. axe-core error unclear? Check the snapshot HTML directly:

``bash open test/excessibility/htmlsnapshots/MyModule42.html ``

  1. Multiple snapshots per test? They're numbered:

`` MyModule421.html MyModule422.html ``

Integration with superpowers

This skill works well with:

  • test-driven-development - TDD discipline for implementation
  • systematic-debugging - When axe-core errors are unclear
  • verification-before-completion - Verify axe-core passes before claiming done