| name | e11y-tdd |
| description | 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. |
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
mix test test/my_live_view_test.exs
mix excessibility
mix excessibility test/my_live_view_test.exs
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
-
Too much output? Use named snapshots:
html_snapshot(view, name: "after_click")
html_snapshot(view, name: "with_errors")
-
Need to see assigns/state? Use debug mode:
mix excessibility.debug test/my_test.exs
-
axe-core error unclear? Check the snapshot HTML directly:
open test/excessibility/html_snapshots/MyModule_42.html
-
Multiple snapshots per test? They're numbered:
MyModule_42_1.html
MyModule_42_2.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