LogoSkills

jaspr-web:regression

Per-route screenshot diff vs baseline. Catches Jaspr/CoUI visual regressions on deploy.

ํ•ญ๋ชฉ๋‚ด์šฉ
Invoke/jaspr-web:regression
Categorycocode-web
Complexitymoderate
MCP Serversplaywright

/jaspr-web regression โ€” ํ™”๋ฉด ํ‹€์–ด์ง ์ž๋™ ๊ฒ€์‚ฌ#

ํ•œ๋งˆ๋””๋กœ#

๋ฐฐํฌ ์ „ํ›„๋กœ ์›น ํ™”๋ฉด์„ ํŽ˜์ด์ง€๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์ฐ์–ด์„œ, "์ •๋‹ต ์‚ฌ์ง„(๊ธฐ์ค€ ํ™”๋ฉด)"๊ณผ ํ•œ ์žฅ์”ฉ ๊ฒน์ณ ๋น„๊ตํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ํ‹€๋ฆฐ ๊ทธ๋ฆผ ์ฐพ๊ธฐ์ฒ˜๋Ÿผ, ๋ฒ„ํŠผยท์—ฌ๋ฐฑยท์ƒ‰์ด ์‚ด์ง์ด๋ผ๋„ ๋‹ฌ๋ผ์ง€๋ฉด ๋ฐ”๋€ ๋ถ€๋ถ„์„ ๋นจ๊ฐ„ ์˜์—ญ์œผ๋กœ ์งš์–ด ์ค๋‹ˆ๋‹ค.

๋ˆ„๊ฐ€ยท์–ธ์ œ ์“ฐ๋‚˜์š”#

  • ์›น ํ™”๋ฉด์„ ๋ฐฐํฌํ•˜๊ธฐ ์ง์ „, "์˜ˆ์ „ ํ™”๋ฉด์ด ๋‚˜๋„ ๋ชจ๋ฅด๊ฒŒ ๊นจ์ง€์ง€ ์•Š์•˜๋‚˜" ํ™•์ธํ•˜๊ณ  ์‹ถ์€ ๊ฐœ๋ฐœ์žยทQA
  • ๋””์ž์ธ ์‹œ์Šคํ…œ(CoUI)์ด๋‚˜ ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์†๋ณธ ๋’ค, ๋‹ค๋ฅธ ํŽ˜์ด์ง€๊ฐ€ ์ค„์ค„์ด ํ‹€์–ด์ง€์ง€ ์•Š์•˜๋Š”์ง€ ์ ๊ฒ€ํ•  ๋•Œ
  • ๋””์ž์ธ์„ ์˜๋„์ ์œผ๋กœ ๋ฐ”๊พผ ๋’ค, "์ด์ œ ์ด ๋ชจ์Šต์ด ์ •๋‹ต"์ด๋ผ๊ณ  ๊ธฐ์ค€ ํ™”๋ฉด์„ ์ƒˆ๋กœ ๊ฐฑ์‹ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ

๋ฌด์—‡์„ ํ•ด์ฃผ๋‚˜์š”#

  • ์ง€์ •ํ•œ ํŽ˜์ด์ง€๋“ค์„ ์—ฌ๋Ÿฌ ํ™”๋ฉด ํฌ๊ธฐ(๋ชจ๋ฐ”์ผยทํƒœ๋ธ”๋ฆฟยทPC)๋กœ ์ž๋™ ์ดฌ์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ์ค€ ํ™”๋ฉด๊ณผ ๋น„๊ตํ•ด ๊ฐ ํŽ˜์ด์ง€๋ฅผ pass(ํ†ต๊ณผ) / within-tolerance(ํ—ˆ์šฉ ๋ฒ”์œ„ ๋‚ด ์ฐจ์ด) / fail(ํ‹€์–ด์ง) / new(๊ธฐ์ค€ ์—†์Œ)์œผ๋กœ ๋ถ„๋ฅ˜ํ•ฉ๋‹ˆ๋‹ค.
  • ํ‹€์–ด์ง„ ํŽ˜์ด์ง€๋Š” ๊ธฐ์ค€ | ์‹ค์ œ | ์ฐจ์ด ๊ฐ•์กฐ 3์žฅ์ด ๋‚˜๋ž€ํžˆ ๋ถ™์€ ๋น„๊ต ์ด๋ฏธ์ง€๋ฅผ .claude/docs/jaspr-web/regression-<์‹œ๊ฐ>/diffs/ ํด๋”์— ์ €์žฅํ•˜๊ณ , ์–ด๋А ์˜์—ญ์ด ์–ผ๋งˆ๋‚˜ ๋ฐ”๋€Œ์—ˆ๋Š”์ง€ ์š”์•ฝ์„ ํ•จ๊ป˜ ๋‚จ๊น๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ์“ฐ๋‚˜์š”#

/jaspr-web regression \
  --routes=/,/components/button,/components/input,/live-preview-poc \
  --base-url=https://coui.cocode.im \
  --tolerance=pixel=2,color_delta_e=3,percent=0.5
  • --routes (ํ•„์ˆ˜): ๊ฒ€์‚ฌํ•  ํŽ˜์ด์ง€ ๊ฒฝ๋กœ๋“ค์„ ์‰ผํ‘œ๋กœ ๋‚˜์—ดํ•˜๊ฑฐ๋‚˜ @<ํŒŒ์ผ> ํ˜•ํƒœ๋กœ YAML ๋ชฉ๋ก์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • --base-url: ์–ด๋А ์‚ฌ์ดํŠธ ์ฃผ์†Œ์—์„œ ์ฐ์„์ง€ (์ƒ๋žตํ•˜๋ฉด ํ˜„์žฌ ๋ธŒ๋žœ์น˜์˜ ๋ฐฐํฌ ๋Œ€์ƒ์—์„œ ์ถ”์ •).
  • --tolerance: ์–ด๋А ์ •๋„ ์ฐจ์ด๊นŒ์ง€ ๋ด์ค„์ง€ ํ—ˆ์šฉ ์˜ค์ฐจ (ํ”ฝ์…€ยท์ƒ‰ ์ฐจ์ดยท์ „์ฒด ๋น„์œจ).
  • --update-baseline=true: ๋””์ž์ธ์„ ์ผ๋ถ€๋Ÿฌ ๋ฐ”๊ฟจ์„ ๋•Œ, ์ƒˆ ํ™”๋ฉด์„ ์ •๋‹ต(๊ธฐ์ค€)์œผ๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค.
  • --keep-animations: ํ‰์†Œ์—” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋„๊ณ  ์ฐ์ง€๋งŒ, ์ด ์˜ต์…˜์„ ์ฃผ๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์•ˆ์—์„œ ๋ฌด์Šจ ์ผ์ด ๋ฒŒ์–ด์ง€๋‚˜์š”#

ํŽ˜์ด์ง€์™€ ํ™”๋ฉด ํฌ๊ธฐ ์กฐํ•ฉ๋งˆ๋‹ค ๋‹ค์Œ์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

  1. ํ•ด๋‹น ํŽ˜์ด์ง€ ์ฃผ์†Œ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋„คํŠธ์›Œํฌ๊ฐ€ ์ž ์ž ํ•ด์งˆ ๋•Œ๊นŒ์ง€(networkidle) ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
  3. ํŽ˜์ด์ง€ ์ „์ฒด๋ฅผ ํ•œ ์žฅ์œผ๋กœ ์ดฌ์˜ํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ธฐ์ค€ ํ™”๋ฉด์ด ์žˆ์œผ๋ฉด ํ”ฝ์…€ ๋‹จ์œ„๋กœ ๋น„๊ตํ•ด ํ†ต๊ณผ/ํ—ˆ์šฉ ๋ฒ”์œ„/ํ‹€์–ด์ง์œผ๋กœ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.
  5. ๊ธฐ์ค€ ํ™”๋ฉด์ด ์—†์œผ๋ฉด new(์ƒˆ ํ™”๋ฉด)๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

โš™๏ธ ์ƒ์„ธ ์˜ต์…˜ยท์‹คํ–‰ ๋ช…์„ธ (๊ฐœ๋ฐœ์ž / AI ์—์ด์ „ํŠธ์šฉ)

Parameters#

ParameterRequiredDescriptionDefault
--routesโœ…Comma-separated route paths, or @<file> for a YAML listโ€”
--base-urlโŒOrigin (e.g. https://coui.cocode.im)inferred from current branch's deploy target
--baseline-dirโŒPath to the baseline screenshots dir.claude/docs/jaspr-web/baseline/
--toleranceโŒpixel=N,color_delta_e=N,percent=Npixel=1,color_delta_e=2,percent=0.1
--viewportโŒWxH (defaults to a list: 390x844, 768x1024, 1280x800, 1920x1080)multi-viewport
--update-baselineโŒOverwrite baseline with the new screenshots (use after an intentional design change)false

Loop#

For each (route, viewport):

  1. Navigate to <base-url><route>.
  2. Wait for networkidle.
  3. browser_take_screenshot --full-page=true.
  4. If baseline exists: pixel-diff using pixelmatch-style algorithm at the given tolerances; classify as pass / within-tolerance / fail.
  5. If baseline missing: classify as new.

Failure Output#

For each failing route, the agent writes a 3-up image (baseline | actual | diff-overlay) under .claude/docs/jaspr-web/regression-<ts>/diffs/, with a YAML entry pinpointing the changed region's bounding box.

- route: /components/button
  viewport: 1280x800
  changed_regions:
    - { x: 240, y: 412, width: 96, height: 36, severity: major }
  diff_pct: 1.8%
  notes:  " Possible padding regression on PrimaryButton "

Example#

/jaspr-web regression \
  --routes=/,/components/button,/components/input,/live-preview-poc \
  --base-url=https://coui.cocode.im \
  --tolerance=pixel=2,color_delta_e=3,percent=0.5

Pairing with CI#

Wire into .github/workflows/*.yml by passing --baseline-dir=$(git rev-parse --show-toplevel)/test/baseline and committing the baseline screenshots. On intentional design updates, run the command locally with --update-baseline=true and commit the refresh.

Caveats#

  • Flutter Web canvas regions are hard to diff cleanly (font rendering can differ by GPU). Bump color_delta_e for routes that include Flutter embeds, or mask the canvas before diffing (--mask=flt-glass-pane).
  • Animations should be disabled before screenshot. The command auto-injects * { animation: none !important; transition: none !important; } via addStyleTag unless --keep-animations is passed.