SkillAgentSearch skills...

Excessibility

Accessibility snapshot testing for Phoenix LiveView - capture HTML during tests, run Pa11y for WCAG compliance, debug with AI-friendly timeline analysis

Install / Use

/learn @lessthanseventy/Excessibility

README

Excessibility

Hex.pm Hex Docs CI License: MIT Ask DeepWiki

Accessibility Snapshot Testing for Elixir + Phoenix

Excessibility helps you test your Phoenix apps for accessibility (WCAG compliance) by taking HTML snapshots during tests and running them through Pa11y.

Why Excessibility?

  • Keep accessibility in your existing test feedback loop. Snapshots are captured inside ExUnit, Wallaby, and LiveView tests, so regressions surface together with your functional failures.
  • Ship safer refactors. Explicit baseline locking and comparison lets reviewers see exactly what changed and approve intentionally.
  • Debug CI-only failures quickly. Pa11y output points to the failing snapshot, and the saved artifacts make it easy to reproduce locally.

How It Works

  1. During tests, call html_snapshot(conn) to capture HTML from your Phoenix responses, LiveViews, or Wallaby sessions
  2. After tests, run mix excessibility to check all snapshots with Pa11y for WCAG violations
  3. Lock baselines with mix excessibility.baseline when snapshots represent a known-good state
  4. Compare changes with mix excessibility.compare to review what changed and approve/reject
  5. In CI, Pa11y reports accessibility violations alongside your test failures

Features

  • Snapshot HTML from Plug.Conn, Wallaby.Session, Phoenix.LiveViewTest.View, and Phoenix.LiveViewTest.Element
  • Explicit baseline locking and comparison workflow
  • Interactive good/bad approval when comparing snapshots
  • Optional PNG screenshots via ChromicPDF
  • Mockable system/browser calls for CI
  • Pa11y configuration with sensible LiveView defaults

LLM Development Features

Excessibility includes powerful features for debugging Phoenix apps with AI assistance (Claude, Cursor, etc.).

Telemetry-Based Auto-Capture (Zero Code Changes!)

Debug any existing LiveView test with automatic snapshot capture - no test changes required:

# Your test - completely vanilla, zero Excessibility code
test "user interaction flow", %{conn: conn} do
  {:ok, view, _html} = live(conn, "/dashboard")
  view |> element("#button") |> render_click()
  view |> element("#form") |> render_submit(%{name: "Alice"})
  assert render(view) =~ "Welcome Alice"
end

Debug it:

mix excessibility.debug test/my_test.exs

🚀 Rich Timeline Capture

mix excessibility.debug automatically enables telemetry capture, dramatically increasing event visibility:

  • Without telemetry: ~4 events (mount, handle_params only)
  • With telemetry: 10-20x more events including all render cycles

Example from real test:

  • Basic test: 4 events → 11 events (added 7 render events)
  • Complex test: Limited snapshots → 236 timeline events with rich analyzer insights

Render events enable powerful pattern detection:

  • 🔴 Memory leak detected (2.3x growth over render cycles)
  • ⚠️ 7 consecutive renders without user interaction
  • 🔴 Performance bottleneck (15ms render blocking)
  • ⚠️ Rapid state changes (potential infinite loop)

This happens automatically - no test changes needed!

Automatically captures:

  • LiveView mount events
  • All handle_event calls (clicks, submits, etc.)
  • All render cycles (form updates, state changes triggered by render_change, render_click, render_submit)
  • Real LiveView assigns at each step
  • Complete state timeline with memory tracking and performance metrics

Example captured snapshot:

<!--
Excessibility Telemetry Snapshot
Test: test user interaction flow
Sequence: 2
Event: handle_event:submit_form
Timestamp: 2026-01-25T10:30:12.345Z
View Module: MyAppWeb.DashboardLive
Assigns: %{
  current_user: %User{name: "Alice"},
  form_data: %{name: "Alice"},
  submitted: true
}
-->

Debug Command

The debug command outputs a comprehensive markdown report with:

  • Test results and error output
  • All captured snapshots with inline HTML
  • Event timeline showing state changes
  • Real LiveView assigns at each snapshot
  • Metadata (timestamps, event sequence, view modules)

The report is both human-readable and AI-parseable, perfect for pasting into Claude.

Available formats (all args pass through to mix test):

mix excessibility.debug test/my_test.exs                    # Markdown report (default)
mix excessibility.debug test/my_test.exs:42                 # Run specific test
mix excessibility.debug --only live_view                    # Run tests with tag
mix excessibility.debug test/my_test.exs --format=json      # Structured JSON
mix excessibility.debug test/my_test.exs --format=package   # Directory with MANIFEST
mix excessibility.latest                                    # Re-display last report

🔍 Telemetry Timeline Analysis

Automatically captures LiveView state throughout test execution and generates scannable timeline reports:

  • Smart Filtering - Removes Ecto metadata, Phoenix internals, and other noise
  • Diff Detection - Shows what changed between events
  • Multiple Formats - JSON for automation, Markdown for humans/AI
  • CLI Control - Override filtering with flags for deep debugging
mix excessibility.debug test/my_test.exs

See CLAUDE.md for detailed usage.

Telemetry Implementation

Excessibility hooks into Phoenix LiveView's built-in telemetry events:

  • [:phoenix, :live_view, :mount, :stop]
  • [:phoenix, :live_view, :handle_event, :stop]
  • [:phoenix, :live_view, :handle_params, :stop]
  • [:phoenix, :live_view, :render, :stop] - Captures all render cycles (form updates, state changes)

When you run mix excessibility.debug, it:

  1. Enables telemetry capture via environment variable
  2. Attaches telemetry handlers to LiveView events
  3. Runs your test
  4. Captures snapshots with real assigns from the LiveView process
  5. Generates a complete debug report

No test changes needed - it works with vanilla Phoenix LiveView tests!

Manual Capture Mode

For fine-grained control, you can also manually capture snapshots:

use Excessibility

@tag capture_snapshots: true
test "manual capture", %{conn: conn} do
  {:ok, view, _} = live(conn, "/")
  html_snapshot(view)  # Manual snapshot with auto-tracked metadata

  view |> element("#btn") |> render_click()
  html_snapshot(view)  # Another snapshot
end

Claude Documentation

Create .claude_docs/excessibility.md to teach Claude how to use these debugging features:

mix excessibility.setup_claude_docs

MCP Server & Claude Code Skills

Excessibility includes an MCP (Model Context Protocol) server and Claude Code skills plugin for AI-assisted development.

MCP Server

The MCP server provides tools for AI assistants to run accessibility checks and debug LiveView state.

Available tools:

| Tool | Speed | Description | |------|-------|-------------| | check_route | Fast | Run Pa11y on a live route (requires app running) | | explain_issue | Fast | Get explanation and fix suggestions for a WCAG violation code | | suggest_fixes | Fast | Get Phoenix-specific code fixes for accessibility issues | | generate_test | Fast | Generate test code with html_snapshot() calls for a route | | list_analyzers | Fast | List available timeline analyzers | | get_timeline | Fast | Read captured timeline showing LiveView state evolution | | get_snapshots | Fast | List or read HTML snapshots captured during tests | | analyze_timeline | Fast | Run analyzers on captured timeline data | | list_violations | Fast | List recent Pa11y violations from snapshots | | e11y_check | Slow | Run tests and/or Pa11y accessibility checks on HTML snapshots | | e11y_debug | Slow | Run tests with telemetry capture - returns timeline for analysis |

Recommended workflow:

  1. check_route - Quick accessibility check on running app
  2. explain_issue - Understand what violations mean
  3. generate_test - Create test with html_snapshot() calls
  4. e11y_debug - Run test to capture timeline
  5. analyze_timeline - Find performance issues

Automatic Setup:

MCP server support is configured automatically when you run the installer:

mix excessibility.install
mix deps.get

This creates .claude/mcp_servers.json with the excessibility MCP server configuration.

Use --no-mcp to skip MCP setup if you don't need AI assistant integration.

Manual Setup:

Configure Claude Code's mcp_servers.json:

{
  "excessibility": {
    "command": "mix",
    "args": ["run", "--no-halt", "-e", "Excessibility.MCP.Server.start()"],
    "cwd": "/path/to/your/project"
  }
}

The MCP server is now available in Claude Code.

Claude Code Skills Plugin

Install the skills plugin for structured accessibility workflows:

claude plugins add /path/to/excessibility/priv/claude-plugin

Available skills:

| Skill | Description | |-------|-------------| | /e11y-tdd | TDD workflow with html_snapshot and Pa11y - sprinkle snapshots to see what's rendered, delete when done | | /e11y-debug | Debug workflow with timeline analysis - inspect state at each event, correlate with Pa11y failures | | /e11y-fix | Reference guide for fixing Pa11y/WCAG errors with Phoenix-specific patterns |

Example workflow:

/e11y-tdd

# Claude will guide you through:
# 1. EXPLORE - Add html_snapshot() calls to see what's rendered
# 2. RED - Write test with snapshot at key moment
# 3. GREEN - Implement featur

Related Skills

View on GitHub
GitHub Stars40
CategoryDevelopment
Updated2d ago
Forks5

Languages

Elixir

Security Score

95/100

Audited on Mar 23, 2026

No findings