DPE Testing Strategy
The DPE follows a 4-layer testing pyramid, adapted from the Sipi testing strategy. Target distribution: ~50% unit, ~30% E2E, ~15% snapshot, ~5% fuzz.
Testing Pyramid
╱╲
╱ ╲ Layer 4: Fuzz Testing (nightly CI)
╱────╲ cargo-fuzz, corpus persisted
╱ ╲
╱ E2E ╲ Layer 3: E2E Tests (Playwright)
╱──────────╲ Tab switching, search, accessibility (axe-core)
╱ ╲
╱ Snapshots ╲ Layer 2: Snapshot Tests (insta)
╱────────────────╲ SSR output, SSE fragments, ARIA attributes
╱ ╲
╱ Unit Tests ╲ Layer 1: Unit Tests (cargo test)
╱────────────────────╲ Fragment handlers, OAI protocol, domain logic
Layer 1: Unit Tests
- Location:
#[cfg(test)]modules in each crate - Runner:
cargo test --workspace - Scope: Fragment handlers, OAI protocol, domain types, data loading, filtering/pagination
- Crate: dpe-core tests run independently —
cargo test -p dpe-core
Layer 2: Snapshot Tests (insta)
- Dependency:
instawithyamlandfiltersfeatures - Location: Adjacent
snapshots/directories - CI: Set
INSTA_UPDATE=newso failures produce.snap.newartifacts for review - Scope: SSR output, SSE fragment response bodies, ARIA attributes
Layer 3: E2E Tests (Playwright)
- Location:
modules/dpe/web-e2e-tests/ - Runner:
npx playwright test - Scope: Tab switching, search autocomplete, scroll preservation, accessibility (axe-core), visual regression
- Accessibility: Full-page axe-core scans against WCAG 2.1 AA
Layer 4: Fuzz Testing
- Tool: cargo-fuzz (nightly Rust)
- Schedule: Nightly CI, 10 minutes per target
- Targets: Tab name validation, SSE response construction, query parameter parsing
- Corpus: Persisted between runs
CI Pipeline Budget
Target: ≤ 10 minutes wall-clock per PR.
Parallel job group 1 (~2 min):
cargo fmt --check
cargo clippy --all-targets -Dwarnings
cargo-deny check
Parallel job group 2 (~5 min):
cargo nextest run --workspace
cargo leptos build --release
cargo-llvm-cov (coverage → Codecov)
Parallel job group 3 (~5 min):
Playwright E2E tests
axe-core accessibility scans
Lighthouse CI performance budgets
Testing Conventions
Test naming: Use descriptive names following the test_{what}_{condition}_{expected} pattern. For example: test_parse_project_missing_title_returns_error.
Test locations:
- Unit tests: In-crate
#[cfg(test)]modules or adjacent_tests.rsfiles - Snapshot files:
.snapfiles committed to git insnapshots/directories - E2E tests:
web-e2e-tests/for DPE,playground-e2e-tests/for Mosaic - Fuzz corpus: Persisted in the repository under
fuzz/corpus/
Test file naming: {feature}_tests.rs for Rust, {feature}.spec.ts for Playwright.
Snapshot tests: Use the insta crate. Use with_settings! for scrubbing dynamic values (timestamps, IDs). CI runs with INSTA_UPDATE=new so unexpected changes produce .snap.new files for review.