Web Application Testing
anthropics/skills
Tests local web applications with Python Playwright scripts, checking frontend behavior, capturing screenshots and reading browser console logs.
Canonical rules for writing, rewriting, or reviewing Shift desktop Playwright E2E tests and visual goldens under apps/desktop/e2e/.
$ npx skills add shift-editor/shift --skill writing-e2e-tests -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install shift-editor/shift writing-e2e-tests --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/shift-editor/shift.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.codex/skills/writing-e2e-tests .claude/skills/writing-e2e-tests && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "writing-e2e-tests" agent skill from https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-tests into .claude/skills/writing-e2e-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-e2e-tests", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-testsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add shift-editor/shift --skill writing-e2e-tests -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install shift-editor/shift writing-e2e-tests --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/shift-editor/shift.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.codex/skills/writing-e2e-tests .agents/skills/writing-e2e-tests && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "writing-e2e-tests" agent skill from https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-tests into .agents/skills/writing-e2e-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-e2e-tests", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add shift-editor/shift --skill writing-e2e-tests -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install shift-editor/shift writing-e2e-tests --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/shift-editor/shift.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.codex/skills/writing-e2e-tests .cursor/skills/writing-e2e-tests && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "writing-e2e-tests" agent skill from https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-tests into .cursor/skills/writing-e2e-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-e2e-tests", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/shift-editor/shift.git --path .codex/skills/writing-e2e-tests--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add shift-editor/shift --skill writing-e2e-tests -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install shift-editor/shift writing-e2e-tests --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/shift-editor/shift.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.codex/skills/writing-e2e-tests .gemini/skills/writing-e2e-tests && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "writing-e2e-tests" agent skill from https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-tests into .gemini/skills/writing-e2e-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-e2e-tests", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install shift-editor/shift writing-e2e-testsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add shift-editor/shift --skill writing-e2e-tests -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/shift-editor/shift.git skills-src && mkdir -p .github/skills && cp -r skills-src/.codex/skills/writing-e2e-tests .github/skills/writing-e2e-tests && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "writing-e2e-tests" agent skill from https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-tests into .github/skills/writing-e2e-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-e2e-tests", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add shift-editor/shift --skill writing-e2e-tests -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install shift-editor/shift writing-e2e-tests --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/shift-editor/shift.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.codex/skills/writing-e2e-tests .opencode/skills/writing-e2e-tests && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "writing-e2e-tests" agent skill from https://github.com/shift-editor/shift/tree/main/.codex/skills/writing-e2e-tests into .opencode/skills/writing-e2e-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "writing-e2e-tests", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
writing-e2e-testsCanonical rules for writing, rewriting, or reviewing Shift desktop Playwright E2E tests and visual goldens under apps/desktop/e2e/.
Writing E2E Tests is an agent skill from shift-editor/shift. Canonical rules for writing, rewriting, or reviewing Shift desktop Playwright E2E tests and visual goldens under apps/desktop/e2e/. Use whenever you add or change a .spec.ts, a fixture, EditorDriver, a screenshot baseline, or Playwright project membership, and whenever you investigate a flaky or failing E2E test. Covers waits, oracles, goldens, fixtures, projects, and flake verification.
Its SKILL.md is about 3.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering End-to-end testing. It works with Playwright. The repository describes itself as: A cross-platform font editor built in Rust and TypeScript. The licence is Apache-2.0.
3 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit e7dacfa. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pnpmnodeFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Writing E2E Tests loads about 3.4k tokens when it runs. Until then it costs about 104 tokens; SKILL.md has 1,546 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from shift-editor/shift at commit e7dacfa, republished under its Apache-2.0 licence (© shift-editor). 1,546 words, ~3,400 tokens.
.claude/skills/writing-e2e-tests/SKILL.md (or your agent's skills folder).An E2E test is worth its cost only when it fails for exactly one reason: the user-visible behavior it names is broken. It must not fail because the machine was slow, the theme changed, a sidebar moved, or a retry happened to pass.
Read /writing-tests first for the general rules (observable state, no mocks, migration ledgers). Read apps/desktop/e2e/README.md for the full fixture and project reference. This skill is the checklist that turns those into a test that stays green for the right reasons.
| The behavior is… | Owning test |
|---|---|
| Pure computation (layout math, latch rules, range selection) | Pure unit test — extract the function first |
| Observable through editor state after a click, drag, or key | TestEditor tool or command test |
| A real browser or Electron contract (DOM events, focus, native menus, dialogs, windows, processes, files) | Semantic Playwright test |
| Appearance: colours, strokes, handles, layout | One focused golden, after a semantic precondition |
| Hardware rendering, GPU residency, WebGPU presentation | gpu project test |
| Save, quit, crash, recovery, file activation, cross-OS paths | platform project test |
If most assertions in a draft E2E test read editor state after page.evaluate, the behavior probably belongs in TestEditor. Keep the E2E test as a thin proof that the real UI reaches it.
waitForTimeout is banned. Wait for the condition that makes the next step valid:
| Before you… | Wait for |
|---|---|
| Read geometry, project coordinates, or send pointer input after setup changed geometry or camera | editor.waitForCanvasRender() |
Assert after raw page.mouse moves | editor.flushPointerMoves(), then waitForCanvasRender() or waitForIdle() |
| Act on an editor route | waitForEditorReady() / openCatalogGlyph() (works for authored and preview sessions) |
| Click a catalog cell by coordinates | clickFirstCatalogGlyph() — it waits for a laid-out, settled Grid |
| Act on a workspace | waitForWorkspaceReady() |
| Assert after quit or close | dirtyDocumentDecisions() / dirtyDocumentRequests() — main-process records, not elapsed time |
| Compare Grid frames after an edit | Published Grid state (data-grid-readiness, data-atlas-build-count, active location), armed after setup settles |
When elapsed time is itself the contract (debounce, momentum, idle timeouts), put the rule in a pure function driven by timestamps and unit-test it. If the E2E test must remain, dispatch events inside the page and wait on the page clock (performance.now()) that stamps them. glyph-view.spec.ts zoom momentum is the template.
Negative assertions ("nothing else happened") need a positive anchor: wait for the event that would have triggered the unwanted outcome, then assert the outcome is absent.
Never count or sample hard-coded colours from a canvas. Colour oracles break under themes, alpha, anti-aliasing, device scale, and renderer changes, and many pass when the feature is broken (an empty canvas has zero "wrong" pixels).
Use published state instead:
editor.outline(), pointPosition(), selectionIds(), selectionBounds();toolState(), hoverId(), activeSnapGuides();visibleOutlines(nodeId) and handleStates(node) on the glyph node definition;aria-pressed, aria-checked, aria-disabled, data-* state published for tests;savedGlyphNames() for .shift files and exportedGlyphNames() for exported fonts — never existsSync, byte inequality, or size > 0.If the state you need is not published, publish it from the production code that renders it (same computation, not a parallel reimplementation), add a unit test for it, then assert it. That is how visibleOutlines and handleStates were added.
Assertions must be exact enough to fail on the wrong answer:
count() > N or not.toEqual(before);All goldens go through fixtures/snapshots.ts; scripts/check-e2e-projects.mjs rejects toHaveScreenshot or toMatchSnapshot anywhere else.
expectCanvasSnapshot(editor, name) — the editor canvas stack, exact comparison, after the canvas has rendered.expectPanelSnapshot(locator, name) — one panel, menu, toolbar, or dialog.expectPageSnapshot(page, name) — full window; use sparingly, only for overall chrome.Before every golden:
data-color-theme), or devicePixelRatio.Rules:
maxDiffPixels: 0 with threshold: 0.02 on every host: enough for antialiasing differences between hosts (≤ 0.009), far below a real colour-token change (~0.07). Never raise either to make a mismatch pass; the default threshold of 0.2 silently accepts token changes.expectPanelSnapshot, expectPageSnapshot) are exact but compared on CI only, with baselines generated on the runner via the ci: update visual snapshots label. Never commit a locally generated interface baseline. Prefer semantic assertions and keep interface goldens few.dragCanvas(), canvasPagePoint()) so layout changes cannot redraw geometry.data-color-theme first. HiDPI goldens use test.use({ deviceScaleFactor: 2 }) and assert devicePixelRatio first. Add one golden per palette branch or rendering path, not one per theme.Updating baselines: only for an intentional appearance change. Run the focused spec with --update-snapshots -g "<title>", open every changed PNG and describe what changed, then rerun without update mode and with --retries=0 --repeat-each=3. Canvas baselines may be generated locally. Interface baselines are generated only by the ci: update visual snapshots label; inspect the runner-generated images before merging.
editor fixture; construct EditorDriver directly only for additional windows.relaunch fixture, never raw electron.launch. The process registry owns every launched tree, attaches diagnostics, and kills it even when the test times out.shiftTestEnvironment(). Never spread process.env into a launch.dirtyDocumentChoice(s), saveShiftPaths, openFontPath). An unexpected renderer dialog fails the test; opt in with allowRendererDialogs only when the dialog is the behavior.EditorDriver (openScratchGlyph(), commitInputValue(), toolButton()), not copied helpers in specs. Do not grow EditorDriver with one-off helpers.getByRole() / getByLabel() and locators from fixtures/appLocators.ts. No parent traversal (locator("..")), no styling classes, no toHaveCSS() unless the style value is the product contract.page.evaluate or insertContent; the behavior under test must go through the user surface.Membership is explicit in apps/desktop/playwright.config.ts. Add a new spec to the right list — visual, platform, gpu, or perf — and run node scripts/check-e2e-projects.mjs. A spec that needs native lifecycle behavior on Windows and Linux belongs in platform. A spec whose only GPU dependency is incidental belongs in visual.
perf project runs nightly or manually, not in the normal correctness suite. Protect a large-list UI change with a small visual interaction test that reaches an offscreen row, preserves selection and keyboard focus, and bounds the number of mounted rows.perf, not visual; verify the test fails for the original regression rather than only when it times out.EditorDriver for navigation and edit settling. Keep the performance fixture responsible for the hardware launch and generated data, not editor behavior.Before committing a new or changed E2E test:
pnpm test:e2e:visual e2e/<spec>.spec.ts -g "<title>" --repeat-each=10 --retries=0For timing-sensitive flows, repeat under CPU load (for example, several yes > /dev/null & processes, killed afterwards), because CI runners are slower than development machines. For platform behavior, rely on the Windows and Linux CI jobs and say so in the pull request.
When a test fails or flakes:
electron-diagnostics before changing anything.The CI "E2E Report" job lists tests that passed only on retry. Treat every entry as a bug to fix, not noise.
TestEditor can observe is tested there.waitForTimeout, no fixed delays, and no polling without a semantic condition.fixtures/snapshots.ts, captures one contract at the smallest element, and follows a semantic precondition.--retries=0.--repeat-each=10 --retries=0, and the pull request lists the exact E2E commands and any coverage not run.© shift-editor, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .codex/skills/writing-e2e-tests of shift-editor/shift.
Open the folder on GitHubat commit e7dacfa
Writing E2E Tests next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Writing E2E Tests this skillshift-editor/shift | 343 | — | ~3.4k | Automated safety check: Pass | Apache-2.0 | |
| Web Application Testinganthropics/skills | 180k | 51 repos | ~966 | Automated safety check: Pass | Apache-2.0 | |
| playwright-cli Browser Automationgithub/gh-aw | 5.3k | 23 repos | ~2.8k | Automated safety check: Pass | MIT | |
| Write and Verify Playwright Testsappsmithorg/appsmith | 41k | — | ~2.9k | Automated safety check: Notes | Apache-2.0 | |
| Cucumber and Playwright E2E Testslanggenius/dify | 158k | — | ~682 | Automated safety check: Pass | Custom licence | |
| E2E Testinglangflow-ai/langflow | 156k | — | ~3.3k | Automated safety check: Pass | MIT |
anthropics/skills
Tests local web applications with Python Playwright scripts, checking frontend behavior, capturing screenshots and reading browser console logs.
github/gh-aw
Drives a real browser from the command line with playwright-cli to open pages, interact, mock requests, save state and work with Playwright tests.
appsmithorg/appsmith
Writes a Playwright end-to-end test from a prompt, runs it against a live Appsmith deployment and retries with fixes up to three times until it passes.
langgenius/dify
Guides changes and reviews of the Cucumber and Playwright end-to-end suite under `e2e/`: feature files, step definitions, support code, tags, locators and assertions.
langflow-ai/langflow
Write and review Playwright E2E tests for Langflow. An agent skill from langflow-ai/langflow.
handsontable/handsontable
Guides writing and changing Playwright end-to-end tests for Handsontable using page objects, data-testid hooks and deterministic waits.
shift-editor/shift
Rules for writing git commits in the Shift font editor repo: Conventional Commits subjects, user-facing changelog wording, concise subjects and logical commit boundaries.
shift-editor/shift
Finds unused files, exports and class members with Knip, then verifies each candidate through reference tracing before removing anything, never using knip --fix.
shift-editor/shift
Updates or creates DOCS.md files for Shift subsystems, recording the architecture invariants and constraints that cannot be learned from reading the source.
shift-editor/shift
Fact-checks DOCS.md files against the source code, testing each concrete claim and sorting it as true, false, stale or unverifiable.
shift-editor/shift
Sets the rules for finding, writing and updating Shift GitHub issues: search for duplicates first, use outcome-focused titles and testable acceptance criteria.
shift-editor/shift
Guides writing JSDoc for Shift exported APIs as a stable caller contract, covering ownership, lifetime, side effects and nullability that TypeScript types cannot express.
Works with
Categories
Canonical rules for writing, rewriting, or reviewing Shift desktop Playwright E2E tests and visual goldens under apps/desktop/e2e/. Writing E2E Tests is an agent skill from shift-editor/shift. Canonical rules for writing, rewriting, or reviewing Shift desktop Playwright E2E tests and visual goldens under apps/desktop/e2e/.
Writing E2E Tests fits situations like: change a .spec.ts; A screenshot baseline; playwright project membership; whenever you investigate a flaky.
Run `npx skills add shift-editor/shift --skill writing-e2e-tests -a claude-code`. Or copy the skill folder (.codex/skills/writing-e2e-tests in shift-editor/shift) into .claude/skills/writing-e2e-tests in your project. Claude Code loads it when a task matches its description.
Run `npx skills add shift-editor/shift --skill writing-e2e-tests -a codex`. Or copy the skill folder (.codex/skills/writing-e2e-tests in shift-editor/shift) into .agents/skills/writing-e2e-tests in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add shift-editor/shift --skill writing-e2e-tests -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/writing-e2e-tests, .gemini/skills/writing-e2e-tests, .github/skills/writing-e2e-tests and .opencode/skills/writing-e2e-tests in your project.
Going by SKILL.md and its folder, Writing E2E Tests needs the command-line tools its instructions call (pnpm and node).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Writing E2E Tests is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.4k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Writing E2E Tests: Web Application Testing (anthropics/skills, 180k stars), playwright-cli Browser Automation (github/gh-aw, 5.3k stars), Write and Verify Playwright Tests (appsmithorg/appsmith, 41k stars) and Cucumber and Playwright E2E Tests (langgenius/dify, 158k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
shift-editor (a GitHub organization) maintains it in shift-editor/shift, which has 343 GitHub stars. The repository holds 14 skills in this directory. The repository was last updated on October 6, 2026.
Source: shift-editor/shift on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.