e2e-tests
Skill13k starsChanged 8 days agoApache-2.0View on GitHub
Rules for writing, improving and reviewing Piskel's Playwright e2e tests (tests/e2e/playwright). Use this whenever adding or changing a *.spec.ts test, covering a claim from docs/specs/untested.txt, fixing a flaky e2e test, or reviewing e2e test code, even if the request only says "add a test" or "cover this spec".
10 other projects use a version of this.
Trending
Less talk lately.about the whole repository
Most recently taken up by
- microsoft/physical-ai-toolchaintheir own version, first seen Nov 1, 2026
- pablopetr/claude-skillstheir own version, first seen Oct 25, 2026
- rterakedis/leanwheel-skillstheir own version, first seen Oct 17, 2026
- vstorm-co/agenticostheir own version, first seen Oct 16, 2026
- braintrustdata/braintrust-sdktheir own version, first seen Oct 8, 2026
- borgbase/vykartheir own version, first seen Oct 8, 2026
Who's talking about piskelapp/piskel
- Victris Games“How To Make A Game with GDevelop - Basics (E01)”YouTube · Dec 16, 2021 · 103k views
- Victris Games“How To Make A Game with GDevelop - Programming (E02)”YouTube · Dec 20, 2021 · 25k views
- Victris Games“How To Make A Game with GDevelop - Movement (E03)”YouTube · Dec 27, 2021 · 17k views
- Victris Games“How To Make A Game with GDevelop - Camera Follow (E04)”YouTube · Jan 2, 2022 · 11k views
- Chrs56k“Piskel, a free and open-source pixel art designer - App pick”YouTube · Aug 2, 2018 · 4.6k views
The biggest 5 of 32 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 32
Talked about on GitHub, YouTube, Hacker News and Bluesky (32 times).
On GitHub · 25
- Apr 17, 2018Idea - integrate Piskel/other pixel art editor in newIDE — 4ian/GDevelop1 reaction · 55 comments
- Nov 6, 2026Feat/drifter sprites — david-mntl/driftward-ace0 reactions
- Jun 6, 2026Record sprite tooling decision — shipshitgames/shipshit.games0 reactions
- Jun 6, 2026Decide Pixelorama toolchain fit — shipshitgames/shipshit.games0 reactions
- Jun 6, 2026Add Sprite QA workbench — shipshitgames/shipshit.games0 reactions
20 more on GitHub
- Jun 6, 2026Embed Piskel sprite editor — shipshitgames/shipshit.games0 reactions
- Apr 13, 2026piskel: init at 0.15.2-SNAPSHOT-unstable-2026-04-09 — NixOS/nixpkgs0 reactions · 3 comments
- Dec 30, 2025Add internationalization (i18n) support — Unveil-gg/RetroPiskel0 reactions · 2 comments
- Dec 29, 2025Add Apache 2.0 license with Piskel attribution — fabkury/makapix0 reactions
- Dec 20, 2025[Feature] add the ability to hide individual layers — Unveil-gg/RetroPiskel0 reactions · 1 comment
- Dec 20, 2025Could add an option to export as SVG? — Unveil-gg/RetroPiskel0 reactions · 1 comment
- Dec 20, 2025Export as BMP file — Unveil-gg/RetroPiskel0 reactions · 1 comment
- Sep 23, 2025Add .piskel extension — pre-commit/identify0 reactions
- Nov 23, 2024Added Piskel to pixel art — KenneyNL/Adobe-Alternatives0 reactions
- May 3, 2024add color shift tool — gingerbeardman/piskel-playdate0 reactions
- Mar 11, 2024Hook up shortcut key to export as png — gingerbeardman/piskel-playdate0 reactions
- Jul 24, 2022flatpak-node-generator Throws KeyError: 'integrity' — flatpak/flatpak-builder-tools0 reactions · 7 comments
- Jan 28, 2020Changing Piskel to be presented as open source — ellisonleao/magictools0 reactions
- Jan 23, 2020Add a Pixel Editor to web interface — MelodyToys/NeoJS0 reactions · 1 comment
- Aug 12, 2019spritesheet animations empty — pixijs/pixijs0 reactions · 3 comments
- Jul 28, 2019Pixel Art Support — Graviton-Code-Editor/Graviton-App0 reactions · 1 comment
- Sep 15, 2018Use webp compression instead of png - piskel export to gdevelop — 4ian/GDevelop0 reactions · 6 comments
- Jul 22, 2018https://github.com/piskelapp/piskel — CircleCI-Public/circleci-demo-workflows0 reactions · 1 comment
- Jul 20, 2018investigate integration with https://github.com/piskelapp/piskel — steemgg/steemgg-website0 reactions · 1 comment
- Mar 13, 2018VirusTotal reports an issue for the win32 version of nwjs.exe — nwjs/nw.js0 reactions · 1 comment
On YouTube · 5
- Dec 16, 2021How To Make A Game with GDevelop - Basics (E01) — Victris Games103k views · 84 comments
- Dec 20, 2021How To Make A Game with GDevelop - Programming (E02) — Victris Games25k views · 41 comments
- Dec 27, 2021How To Make A Game with GDevelop - Movement (E03) — Victris Games17k views · 52 comments
- Jan 2, 2022How To Make A Game with GDevelop - Camera Follow (E04) — Victris Games11k views · 29 comments
- Aug 2, 2018Piskel, a free and open-source pixel art designer - App pick — Chrs56k4.6k views
On Hacker News · 1
- Oct 27, 2022A simple web-based tool for Spriting and Pixel art2 points
On Bluesky · 1
- Sep 21, 2024Piskel - an open-source sprite editor/animator github.com/piskelapp/pi... — @cinematronic.bsky.social1 likes and repost
Other versions10 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 10
- vitessio/vitess★ 21ksame name
- borgbase/vykar★ 722same name
- vstorm-co/agenticos★ 241same name
- microsoft/physical-ai-toolchain★ 138same name
- braintrustdata/braintrust-sdk★ 30same name
- issue-orchestrator/issue-orchestrator★ 10same name
- Joomla-Bible-Study/joomla-skills★ 8same name
- GlamgarOnDiscord/claude-saas-blueprint★ 2same name
- rterakedis/leanwheel-skills★ 2same name
- pablopetr/claude-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
Show its rules and text
We split this skill into the rules it gives an agent
18 rules. 0 are common, 12 are distinctive, and 6 are very specific to this project.
0
Common
Most of the 9 edited versions we read keep these.
12
Distinctive
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Follow this for all three kinds of work:
- Distinctive: line 11
Improving: keep what the test verifies and bring it in line with the rules below.
- Very specific: line 27
When picking names, use user-friendly, semantic names rather than short, cryptic ones, such as layer1 instead of l1, so the reader doesn't …
- Distinctive: line 29
Add a comment for each high-level user step, so the test reads as a scenario from top to bottom:
- Very specific: line 46
Every e2e test references at least one spec claim, using a tag for each claim it verifies: { tag: ['@layers.rename'] }.
- Very specific: line 47
When a claim gets its first test, remove its id from docs/specs/untested.txt.
- Very specific: line 48
If the code and the spec disagree, ask which one is wrong rather than writing the test to match either.
- Very specific: line 54
Avoid window.pskl internals.
- Distinctive: line 55
When a test uses modifier keys, add a comment saying what each one does, because the keys alone don't tell the reader which behavior is …
- Distinctive: line 81
Write each grid one row per line, so it looks like the shape.
- Distinctive: line 82
Use a 10x10 square sprite by default, like a real canvas.
- Distinctive: line 93
When an action has effects elsewhere in the app, check those effects as well as the local change, because a button updating its own look …
- Distinctive: line 103
After changing a layer's opacity, check the preview as well as the color of the α button.
- Distinctive: line 104
After deleting a frame, check what the preview plays as well as the frame tiles.
- Distinctive: line 105
When something should stay unchanged, check that too: changing the layer preview opacity must not change the animated preview.
- Distinctive: line 107
Use a screenshot only when the claim is about what's rendered.
- Very specific: line 113
Prefer polling (waitForGrid, waitFor, expect(locator)) over fixed waits.
- Distinctive: line 124
Before temporarily breaking the app to check that a test can fail, make sure nothing is already running on port 9001.
“Common” is measured: kept by at least 6 in 10 of the 9 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Piskel e2e tests
Follow this for all three kinds of work:
- Writing: pick the claims, read the code behind them, write the tests, then run them.
- Improving: keep what the test verifies and bring it in line with the rules below.
- Reviewing: report where a test breaks a rule or could pass while the behavior is broken. Give the file, the line and a concrete fix.
Readability
An e2e test should be easy for a human to read. Someone new to the test should quickly see what it sets up, what it does and what it expects, because that's how they tell whether a failure is a bug in the app or in the test. When a shorter or cleverer version would be harder to follow, prefer the clearer one.
Each test should read like very simple instructions about what the user is doing. If a step is a convoluted expression or takes too many lines, first check whether testutils.ts already has a helper for it. If not, add one there with a user-friendly, descriptive name, so the test tells a story:
// Instead of
await waitFor(async () => (await getFrameTiles(page).count()) === 2);
// write
await assertFrameCount(page, 2);When picking names, use user-friendly, semantic names rather than short, cryptic ones, such as layer1 instead of l1, so the reader doesn't have to work out what a name refers to.
Add a comment for each high-level user step, so the test reads as a scenario from top to bottom:
// Draw in second frame.
await clickTool(page, 'tool-pen');
await drawAtPixel(page, 0, 0);
expect(await readPixelRows(page, 10, 10, 0, 1)).toEqual(PIXEL_AT_0_0);
// Go back to first frame and undo.
await selectFrame(page, 0);
await undo(page);
await waitForGrid(page, 10, 10, EMPTY, { frameIndex: 1 });Specs
- Tests for
docs/specs/<spec>.mdlive intests/e2e/playwright/integration/<spec>/. - Every e2e test references at least one spec claim, using a tag for each claim it verifies:
{ tag: ['@layers.rename'] }.spec-checkdoesn't catch a missing tag, so check this yourself. - When a claim gets its first test, remove its id from
docs/specs/untested.txt. Runnpm run spec-checkto confirm. - If the code and the spec disagree, ask which one is wrong rather than writing the test to match either. Known problems are listed in
docs/known-issues.md.
Interacting with the app
- Act and read through the UI, as a user would, so tests survive internal refactors.
- Find elements with
data-test-idand thetestId(page, 'id')helper. Add the attribute to the template or controller when it's missing, so tests don't depend on styling classes. When the work must not change the app, use the existing class in atestutils.tshelper instead, assetLayerPreviewOpacityandassertOtherLayerOpacityOnCanvasdo. - Avoid
window.psklinternals. The accepted bridges aresetPiskelFromGridfor fixtures, the pixel readers (getPixelColor,readPixelGrid,readPixelRows,assertColorRows), the mouse helpers that turn a pixel into a screen position (drawAtPixel,rightClickAtPixel,dragThroughPixels,dragBetweenPixels, …) andassertOtherLayerOpacityOnCanvas, which have no DOM alternative. When a test uses modifier keys, add a comment saying what each one does, because the keys alone don't tell the reader which behavior is being tested:
// Shift applies the flip to all frames, Ctrl to all layers await clickTransform(page, 'tool-flip', { shift: true, ctrl: true });
Asserting
When testing the rendering in the canvas or any 2-dimensional artifact (e.g. the shape of the selection), use a matrix (2D array) or a list of strings instead of querying each position line by line, because the reader can visualize the content being asserted and stray pixels fail the test:
expect(await readPixelRows(page, 10, 10)).toEqual([ '..........', '.......X..', '.......X..', '.......X..', '...XXXXX..', '..........', '..........', '..........', '..........', '..........', ]);- Write each grid one row per line, so it looks like the shape. Don't build grids with helpers or spreads, even for empty rows.
- Use a 10x10 square sprite by default, like a real canvas. Use a smaller sprite only to test an edge case, such as a 2x2 sprite for clipping, and a rectangular one only when the shape matters. Say why in a comment.
readPixelRowsonly tells colored from transparent. When the color matters, useassertColorRows, whose grids show each color as a letter, never just "not transparent". UsegetPixelColorandcolorToInt('#FF0000')orTRANSPARENTonly for a color without a letter.- Work out expected values from the spec or by hand. Output copied from a run only proves the code does what it does.
Assert the frame after each drawing action in the setup, as an ASCII grid when possible, so a broken setup fails at the step that caused it rather than later at the behavior being tested, and the reader can see the state at each step:
await drawAtPixel(page, 1, 1); expect(await readPixelRows(page, 10, 10, 1, 1)).toEqual(PIXEL_AT_1_1);Declare grids used more than once, such as
PIXEL_AT_1_1, as constants at the top of the file, still one row per line.When an action has effects elsewhere in the app, check those effects as well as the local change, because a button updating its own look doesn't prove the feature works:
// The eye icon changed, but are the other layers really hidden? await toggleLayerPreview(page); await assertLayerPreviewEnabled(page, false); await assertOtherLayerHiddenOnCanvas(page, 0, 0);Other examples:
- After changing a layer's opacity, check the preview as well as the color of the α button.
- After deleting a frame, check what the preview plays as well as the frame tiles.
- When something should stay unchanged, check that too: changing the layer preview opacity must not change the animated preview.
- Use a screenshot only when the claim is about what's rendered. Screenshot the single element, not the page (unless it's a global test like an app-level layout), and avoid text.
- For animated content, use
assertPreviewPlaysrather than a screenshot, because a screenshot depends on timing. - Make sure a test can fail. For "does nothing" claims, also check that no side effect happened, such as a history step: draw first, and check that undo removes the drawing. For claims about limits or timing, temporarily disable the behavior and confirm the test fails, because these tests can easily pass for the wrong reason.
Timing
- Prefer polling (
waitForGrid,waitFor,expect(locator)) over fixed waits. - Undo and redo are ignored within 50ms of the previous one (
undo-redo.throttle). Polling can finish sooner than that, so putawait wait(100)between consecutive presses.
Running
playwright.config.tssetsretries: 3, which hides flakiness. Check new or changed tests with:npx playwright test <path> --retries=0 --repeat-each=5- Before temporarily breaking the app to check that a test can fail, make sure nothing is already running on port 9001. Playwright reuses that server, so it can serve an old or broken build and the results won't count.
- Report the real result, including any test you didn't run.
Mutation testing
After writing tests for a claim, break each behavior it covers, one at a time, and confirm a test fails. Restore src/ after each one and check that git diff is empty. If a mutation isn't caught, either strengthen the test or explain why the mutation couldn't have failed it.
Report progress to the user every 5 mutations done, because mutation checks are long runs and the user wants to follow them. When they run in the background, watch their log; when they run in a subagent, have it notify the main agent every 5 mutations.
Adding rules
This skill grows as we write tests. Always ask the user before adding anything to it, even a rule that seems obvious from their feedback, because they decide what becomes a standing rule. Add each approved rule to the section it belongs to, in one or two lines, with the reason when it isn't obvious.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

