| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| Invoke | /jaspr-web:regression |
| Category | cocode-web |
| Complexity | moderate |
| MCP Servers | playwright |
/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: ํ์์ ์ ๋๋ฉ์ด์ ์ ๋๊ณ ์ฐ์ง๋ง, ์ด ์ต์ ์ ์ฃผ๋ฉด ์ ๋๋ฉ์ด์ ์ ์ ์งํฉ๋๋ค.
์์์ ๋ฌด์จ ์ผ์ด ๋ฒ์ด์ง๋์#
ํ์ด์ง์ ํ๋ฉด ํฌ๊ธฐ ์กฐํฉ๋ง๋ค ๋ค์์ ๋ฐ๋ณตํฉ๋๋ค.
- ํด๋น ํ์ด์ง ์ฃผ์๋ก ์ด๋ํฉ๋๋ค.
- ๋คํธ์ํฌ๊ฐ ์ ์ ํด์ง ๋๊น์ง(
networkidle) ๊ธฐ๋ค๋ฆฝ๋๋ค. - ํ์ด์ง ์ ์ฒด๋ฅผ ํ ์ฅ์ผ๋ก ์ดฌ์ํฉ๋๋ค.
- ๊ธฐ์ค ํ๋ฉด์ด ์์ผ๋ฉด ํฝ์ ๋จ์๋ก ๋น๊ตํด ํต๊ณผ/ํ์ฉ ๋ฒ์/ํ์ด์ง์ผ๋ก ํ์ ํฉ๋๋ค.
- ๊ธฐ์ค ํ๋ฉด์ด ์์ผ๋ฉด
new(์ ํ๋ฉด)๋ก ํ์ํฉ๋๋ค.
โ๏ธ ์์ธ ์ต์ ยท์คํ ๋ช ์ธ (๊ฐ๋ฐ์ / AI ์์ด์ ํธ์ฉ)
Parameters#
| Parameter | Required | Description | Default |
|---|---|---|---|
--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=N | pixel=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):
- Navigate to
<base-url><route>. - Wait for
networkidle. browser_take_screenshot --full-page=true.- If baseline exists: pixel-diff using
pixelmatch-style algorithm at the given tolerances; classify aspass/within-tolerance/fail. - 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.5Pairing 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_efor 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; }viaaddStyleTagunless--keep-animationsis passed.