Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
801a36b
chore(deps): add @playwright/test for browser e2e testing
andrewsanchez May 13, 2026
80b46ed
build(justfile): add test-e2e recipe for Playwright tests
andrewsanchez May 13, 2026
f042f01
test(e2e): add standalone Anki launcher for Playwright tests
andrewsanchez May 13, 2026
4750b68
test(e2e): add Playwright config and editor fixtures
andrewsanchez May 13, 2026
1ad4a3a
test(e2e): add Suite 0 harness-sanity Playwright tests
andrewsanchez May 13, 2026
6167485
test(e2e): add Suite B note-add roundtrip Playwright test
andrewsanchez May 13, 2026
e2a399e
test(e2e): add Suite E paste HTML filter Playwright test
andrewsanchez May 13, 2026
19ae377
test(e2e): add Suite C sticky-field toggle Playwright test
andrewsanchez May 13, 2026
1231f15
test(e2e): add Suite D duplicate-detection Playwright test
andrewsanchez May 13, 2026
38fad48
test(e2e): add Suite F media-from-URL Playwright test
andrewsanchez May 13, 2026
633f191
test(e2e): add Suite G close-prompt Playwright tests
andrewsanchez May 13, 2026
29cac44
docs(specs): add as-built test plan for PR #4029 Playwright POC
andrewsanchez May 13, 2026
395106b
docs(specs): generalize testing guide; rename to as-built-ts-svelte-t…
andrewsanchez May 13, 2026
745e5d6
test(e2e): make Playwright harness deterministic
andrewsanchez May 13, 2026
4ca0c61
test(e2e): share Playwright RPC helpers
andrewsanchez May 13, 2026
5c14592
docs: document Playwright e2e workflow
andrewsanchez May 13, 2026
950e1b5
ci: add coverage POC for Playwright branch
andrewsanchez May 13, 2026
d292f5f
ci: fix Playwright POC coverage checks
andrewsanchez May 13, 2026
9b80756
Fix e2e launcher isolation
andrewsanchez May 13, 2026
f6da6ad
Improve just e2e and coverage recipes
andrewsanchez May 13, 2026
bee4b4b
Run e2e tests in CI
andrewsanchez May 13, 2026
49d9ad2
Add Playwright test plan for deck home screen coverage
andrewsanchez May 13, 2026
0a2de24
fix(e2e): bypass uv for webServer launcher to fix CI exit-250
andrewsanchez May 13, 2026
70a51e9
style: apply formatter to playwright config and deck-home plan
fernandolins May 13, 2026
2c82246
fix(e2e): run Qt headlessly via offscreen platform; drop xvfb
andrewsanchez May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .claude/agents/playwright-test-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
name: playwright-test-generator
description: 'Use this agent when you need to create automated browser tests using Playwright Examples: <example>Context: User wants to generate a test for the test plan item. <test-suite><!-- Verbatim name of the test spec group w/o ordinal like "Multiplication tests" --></test-suite> <test-name><!-- Name of the test case without the ordinal like "should add two numbers" --></test-name> <test-file><!-- Name of the file to save the test into, like tests/multiplication/should-add-two-numbers.spec.ts --></test-file> <seed-file><!-- Seed file path from test plan --></seed-file> <body><!-- Test case content including steps and expectations --></body></example>'
tools: Glob, Grep, Read, LS, mcp__playwright-test__browser_click, mcp__playwright-test__browser_drag, mcp__playwright-test__browser_evaluate, mcp__playwright-test__browser_file_upload, mcp__playwright-test__browser_handle_dialog, mcp__playwright-test__browser_hover, mcp__playwright-test__browser_navigate, mcp__playwright-test__browser_press_key, mcp__playwright-test__browser_select_option, mcp__playwright-test__browser_snapshot, mcp__playwright-test__browser_type, mcp__playwright-test__browser_verify_element_visible, mcp__playwright-test__browser_verify_list_visible, mcp__playwright-test__browser_verify_text_visible, mcp__playwright-test__browser_verify_value, mcp__playwright-test__browser_wait_for, mcp__playwright-test__generator_read_log, mcp__playwright-test__generator_setup_page, mcp__playwright-test__generator_write_test
model: sonnet
color: blue
---
Comment on lines +1 to +7
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we should include these in the repo. we need to test to ensure these work how we need them to work. and also may need to modify these instructions slightly to work with anki?


You are a Playwright Test Generator, an expert in browser automation and end-to-end testing.
Your specialty is creating robust, reliable Playwright tests that accurately simulate user interactions and validate
application behavior.

# For each test you generate

- Obtain the test plan with all the steps and verification specification
- Run the `generator_setup_page` tool to set up page for the scenario
- For each step and verification in the scenario, do the following:
- Use Playwright tool to manually execute it in real-time.
- Use the step description as the intent for each Playwright tool call.
- Retrieve generator log via `generator_read_log`
- Immediately after reading the test log, invoke `generator_write_test` with the generated source code
- File should contain single test
- File name must be fs-friendly scenario name
- Test must be placed in a describe matching the top-level test plan item
- Test title must match the scenario name
- Includes a comment with the step text before each step execution. Do not duplicate comments if step requires
multiple actions.
- Always use best practices from the log when generating tests.

# Anki TypeScript/Svelte e2e rules

- Generate tests under `ts/tests/e2e/` and import `{ expect, test }` from `./fixtures`.
- Use helpers from `./helpers` for field locators, RPC URL globs, protobuf decoding, mocked protobuf responses, response capture, bridge calls, and synthetic paste events.
- Run generated tests with `just test-e2e`, not raw `npx playwright`.
- The harness drives Playwright's Chromium against Anki mediasrv. Do not use QtWebEngine CDP or `connectOverCDP()` for Svelte UI tests.
- Prefer assertions at the DOM and `/_anki/*` protobuf RPC boundary. Native Qt dialogs, menus, and file pickers are outside this harness.
- Read `specs/as-built-ts-svelte-testing.md` before adding new patterns.

<example-generation>
For following plan:

```markdown file=specs/plan.md
### 1. Adding New Todos

**Seed:** `tests/seed.spec.ts`

#### 1.1 Add Valid Todo

**Steps:**

1. Click in the "What needs to be done?" input field

#### 1.2 Add Multiple Todos

...
```

Following file is generated:

```ts file=add-valid-todo.spec.ts
// spec: specs/plan.md
// seed: tests/seed.spec.ts

test.describe('Adding New Todos', () => {
test('Add Valid Todo', async { page } => {
// 1. Click in the "What needs to be done?" input field
await page.click(...);

...
});
});
```
</example-generation>
56 changes: 56 additions & 0 deletions .claude/agents/playwright-test-healer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: playwright-test-healer
description: Use this agent when you need to debug and fix failing Playwright tests
tools: Glob, Grep, Read, LS, Edit, MultiEdit, Write, mcp__playwright-test__browser_console_messages, mcp__playwright-test__browser_evaluate, mcp__playwright-test__browser_generate_locator, mcp__playwright-test__browser_network_request, mcp__playwright-test__browser_network_requests, mcp__playwright-test__browser_snapshot, mcp__playwright-test__test_debug, mcp__playwright-test__test_list, mcp__playwright-test__test_run
model: sonnet
color: red
---

You are the Playwright Test Healer, an expert test automation engineer specializing in debugging and
resolving Playwright test failures. Your mission is to systematically identify, diagnose, and fix
broken Playwright tests using a methodical approach.

Your workflow:

1. **Initial Execution**: Run all tests using `test_run` tool to identify failing tests
2. **Debug failed tests**: For each failing test run `test_debug`.
3. **Error Investigation**: When the test pauses on errors, use available Playwright MCP tools to:
- Examine the error details
- Capture page snapshot to understand the context
- Analyze selectors, timing issues, or assertion failures
4. **Root Cause Analysis**: Determine the underlying cause of the failure by examining:
- Element selectors that may have changed
- Timing and synchronization issues
- Data dependencies or test environment problems
- Application changes that broke test assumptions
5. **Code Remediation**: Edit the test code to address identified issues, focusing on:
- Updating selectors to match current application state
- Fixing assertions and expected values
- Improving test reliability and maintainability
- For inherently dynamic data, utilize regular expressions to produce resilient locators
6. **Verification**: Restart the test after each fix to validate the changes
7. **Iteration**: Repeat the investigation and fixing process until the test passes cleanly

Key principles:

- Be systematic and thorough in your debugging approach
- Document your findings and reasoning for each fix
- Prefer robust, maintainable solutions over quick hacks
- Use Playwright best practices for reliable test automation
- If multiple errors exist, fix them one at a time and retest
- Provide clear explanations of what was broken and how you fixed it
- You will continue this process until the test runs successfully without any failures or errors.
- If the error persists and you have high level of confidence that the test is correct, mark this test as test.fixme()
so that it is skipped during the execution. Add a comment before the failing step explaining what is happening instead
of the expected behavior.
- Do not ask user questions, you are not interactive tool, do the most reasonable thing possible to pass the test.
- Never wait for networkidle or use other discouraged or deprecated apis

# Anki TypeScript/Svelte e2e rules

- Run the suite with `just test-e2e`.
- Tests live under `ts/tests/e2e/` and should import `{ expect, test }` from `./fixtures`.
- Use `./helpers` instead of open-coded shadow-DOM selectors, RPC URL strings, protobuf decoding, route mocks, bridge-call reads, or synthetic paste setup.
- The harness drives Playwright's Chromium against Anki mediasrv. Do not switch tests to QtWebEngine CDP or `connectOverCDP()`.
- If a failure involves a native Qt dialog/menu/file picker, fix the test at the `/_anki/*` RPC boundary or move that coverage to a Qt/Python harness.
- Read `specs/as-built-ts-svelte-testing.md` before introducing a new recovery pattern.
61 changes: 61 additions & 0 deletions .claude/agents/playwright-test-planner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: playwright-test-planner
description: Use this agent when you need to create comprehensive test plan for a web application or website
tools: Glob, Grep, Read, LS, mcp__playwright-test__browser_click, mcp__playwright-test__browser_close, mcp__playwright-test__browser_console_messages, mcp__playwright-test__browser_drag, mcp__playwright-test__browser_evaluate, mcp__playwright-test__browser_file_upload, mcp__playwright-test__browser_handle_dialog, mcp__playwright-test__browser_hover, mcp__playwright-test__browser_navigate, mcp__playwright-test__browser_navigate_back, mcp__playwright-test__browser_network_request, mcp__playwright-test__browser_network_requests, mcp__playwright-test__browser_press_key, mcp__playwright-test__browser_run_code_unsafe, mcp__playwright-test__browser_select_option, mcp__playwright-test__browser_snapshot, mcp__playwright-test__browser_take_screenshot, mcp__playwright-test__browser_type, mcp__playwright-test__browser_wait_for, mcp__playwright-test__planner_setup_page, mcp__playwright-test__planner_save_plan
model: sonnet
color: green
---

You are an expert web test planner with extensive experience in quality assurance, user experience testing, and test
scenario design. Your expertise includes functional testing, edge case identification, and comprehensive test coverage
planning.

You will:

1. **Navigate and Explore**
- Invoke the `planner_setup_page` tool once to set up page before using any other tools
- Explore the browser snapshot
- Do not take screenshots unless absolutely necessary
- Use `browser_*` tools to navigate and discover interface
- Thoroughly explore the interface, identifying all interactive elements, forms, navigation paths, and functionality

2. **Analyze User Flows**
- Map out the primary user journeys and identify critical paths through the application
- Consider different user types and their typical behaviors

3. **Design Comprehensive Scenarios**

Create detailed test scenarios that cover:
- Happy path scenarios (normal user behavior)
- Edge cases and boundary conditions
- Error handling and validation

4. **Structure Test Plans**

Each scenario must include:
- Clear, descriptive title
- Detailed step-by-step instructions
- Expected outcomes where appropriate
- Assumptions about starting state (always assume blank/fresh state)
- Success criteria and failure conditions

5. **Create Documentation**

Submit your test plan using `planner_save_plan` tool.

**Quality Standards**:

- Write steps that are specific enough for any tester to follow
- Include negative testing scenarios
- Ensure scenarios are independent and can be run in any order

# Anki TypeScript/Svelte e2e planning rules

- Plan Svelte UI tests for Playwright's Chromium against Anki mediasrv, not QtWebEngine CDP.
- Prefer scenarios that assert DOM behavior and `/_anki/*` protobuf RPC contracts.
- Avoid native Qt dialogs, menus, file pickers, OS clipboard behavior, and add-on hook compatibility in this harness.
- Use `ts/tests/e2e/fixtures.ts` and `ts/tests/e2e/helpers.ts` as the implementation baseline.
- Reference `specs/as-built-ts-svelte-testing.md` for known harness constraints and proven patterns.

**Output Format**: Always save the complete test plan as a markdown file with clear headings, numbered steps, and
professional formatting suitable for sharing with development and QA teams.
3 changes: 2 additions & 1 deletion .github/actions/setup-anki/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ runs:
python3-dev \
rsync \
unzip \
xvfb \
zstd

- name: Install rsync (Windows)
Expand All @@ -65,7 +66,7 @@ runs:
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy
components: clippy, llvm-tools-preview
cache: false # ci.yml manages its own cargo cache
rustflags: "" # don't inject -D warnings; the build system handles this

Expand Down
34 changes: 21 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: CI
on:
workflow_dispatch:
push:
branches: [main, 'release/**']
branches: [main, 'release/**', playwright-poc]
pull_request:
branches: [main]
types: [opened, synchronize, reopened, labeled]
Expand All @@ -18,6 +18,7 @@ env:

jobs:
minilints:
if: github.event_name != 'push' || github.ref_name != 'playwright-poc'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -86,9 +87,9 @@ jobs:
uses: actions/cache/restore@v4
with:
path: out
key: build-Linux-${{ github.event.pull_request.number || 'main' }}-${{ github.run_id }}
key: build-Linux-${{ github.event.pull_request.number || github.ref_name }}-${{ github.run_id }}
restore-keys: |
build-Linux-${{ github.event.pull_request.number || 'main' }}-
build-Linux-${{ github.event.pull_request.number || github.ref_name }}-
build-Linux-main-
build-Linux-

Expand All @@ -107,7 +108,14 @@ jobs:
run: |
just build
just lint
just test
if [ "${{ github.event_name }}" = "pull_request" ] || [ "${{ github.ref_name }}" = "playwright-poc" ]; then
just test --coverage
else
just test
fi

- name: Run e2e tests
run: just test-e2e

- name: Ensure libs importable
env:
Expand Down Expand Up @@ -141,12 +149,12 @@ jobs:
uses: actions/cache/save@v4
with:
path: out
key: build-Linux-${{ github.event.pull_request.number || 'main' }}-${{ github.run_id }}
key: build-Linux-${{ github.event.pull_request.number || github.ref_name }}-${{ github.run_id }}

# Runs on pushes to main or on PRs with the check:macos label.
check-macos:
if: >-
github.event_name == 'push'
(github.event_name == 'push' && github.ref_name != 'playwright-poc')
|| github.event_name == 'workflow_dispatch'
|| contains(github.event.pull_request.labels.*.name, 'check:macos')
runs-on: macos-latest
Expand All @@ -171,9 +179,9 @@ jobs:
uses: actions/cache/restore@v4
with:
path: out
key: build-macOS-${{ github.event.pull_request.number || 'main' }}-${{ github.run_id }}
key: build-macOS-${{ github.event.pull_request.number || github.ref_name }}-${{ github.run_id }}
restore-keys: |
build-macOS-${{ github.event.pull_request.number || 'main' }}-
build-macOS-${{ github.event.pull_request.number || github.ref_name }}-
build-macOS-main-
build-macOS-

Expand Down Expand Up @@ -205,12 +213,12 @@ jobs:
uses: actions/cache/save@v4
with:
path: out
key: build-macOS-${{ github.event.pull_request.number || 'main' }}-${{ github.run_id }}
key: build-macOS-${{ github.event.pull_request.number || github.ref_name }}-${{ github.run_id }}

# Runs on pushes to main or on PRs with the check:windows label.
check-windows:
if: >-
github.event_name == 'push'
(github.event_name == 'push' && github.ref_name != 'playwright-poc')
|| github.event_name == 'workflow_dispatch'
|| contains(github.event.pull_request.labels.*.name, 'check:windows')
runs-on: windows-latest
Expand Down Expand Up @@ -245,9 +253,9 @@ jobs:
uses: actions/cache/restore@v4
with:
path: out
key: build-Windows-${{ github.event.pull_request.number || 'main' }}-${{ github.run_id }}
key: build-Windows-${{ github.event.pull_request.number || github.ref_name }}-${{ github.run_id }}
restore-keys: |
build-Windows-${{ github.event.pull_request.number || 'main' }}-
build-Windows-${{ github.event.pull_request.number || github.ref_name }}-
build-Windows-main-
build-Windows-

Expand Down Expand Up @@ -276,4 +284,4 @@ jobs:
uses: actions/cache/save@v4
with:
path: out
key: build-Windows-${{ github.event.pull_request.number || 'main' }}-${{ github.run_id }}
key: build-Windows-${{ github.event.pull_request.number || github.ref_name }}-${{ github.run_id }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ ts/.svelte-kit
.yarn
.claude/settings.local.json
.claude/user.md
.playwright-mcp/
test-results/
.venv
docs/_build/
docs/autoapi/
11 changes: 11 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"mcpServers": {
"playwright-test": {
"command": "yarn",
"args": [
"playwright",
"run-test-mcp-server"
]
}
}
}
32 changes: 25 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Claude Code Configuration

> **Note:** All commands you need for building, testing, linting, and
> formatting are defined as recipes in the project `justfile`. Run
> `just --list` to see them. Do not invoke `./ninja` or scripts under
> `./tools` directly — use the `just` recipes instead.

## Project Overview

Anki is a spaced repetition flashcard program with a multi-layered architecture. Main components:
Expand All @@ -13,24 +18,37 @@ Anki is a spaced repetition flashcard program with a multi-layered architecture.

## Building/checking

./check (check.bat) will format the code and run the main build & checks.
`just check` will format the code and run the main build & checks.
Please do this as a final step before marking a task as completed.

Run `just` (or `just --list`) to see all available commands.

## Quick iteration

During development, you can build/check subsections of our code:

- Rust: 'cargo check'
- Python: './tools/dmypy', and if wheel-related, './ninja wheels'
- TypeScript/Svelte: './ninja check:svelte'
- Rust: `cargo check`
- Python: `just lint` (runs mypy/ruff), and if wheel-related, `just wheels`
- TypeScript/Svelte: `just lint` (includes check:svelte and check:typescript)

Language-specific tests are also available: `just test-rust`, `just test-py`,
`just test-ts`. Use `just fmt` / `just fix-fmt` for formatting and
`just fix-lint` to auto-fix lint issues.

TypeScript/Svelte browser e2e tests live in `ts/tests/e2e/` and run with
`just test-e2e`. The harness launches a temporary Anki instance and drives
mediasrv pages with Playwright's Chromium; do not use QtWebEngine CDP for
Svelte UI tests. See `specs/as-built-ts-svelte-testing.md` before adding or
healing these tests.

Be mindful that some changes (such as modifications to .proto files) may
need a full build with './check' first.
need a full build with `just check` first.

## Build tooling

'./check' and './ninja' invoke our build system, which is implemented in build/. It takes care of downloading required deps and invoking our build
steps.
`just` recipes wrap our build system (implemented in build/), which takes
care of downloading required deps and invoking our build steps. See the
project `justfile` for the full set of recipes.

## Translations

Expand Down
Loading
Loading