Skip to content

🤖 ci: migrate visual regression testing from Chromatic to Coder Pixel#3736

Merged
ibetitsmike merged 10 commits into
mainfrom
mike/pixel-visual-regression
Jul 17, 2026
Merged

🤖 ci: migrate visual regression testing from Chromatic to Coder Pixel#3736
ibetitsmike merged 10 commits into
mainfrom
mike/pixel-visual-regression

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates visual regression testing from Chromatic to Coder Pixel (@coder/pixel-storybook 0.2.1 uploading to pixel.coder.com), removing the Chromatic workflow, config, and all story-level Chromatic parameters. The pipeline is verified end-to-end: PR builds upload 331 snapshots to the mux Pixel project and post a Pixel / Review commit status.

Background

We are moving off Chromatic to the Coder Pixel platform, mirroring what coder/coder did in its CI. One deliberate divergence: coder/coder pins @coder/pixel-storybook@0.1.3, which has no theme/viewport matrix support. This repo relies heavily on dual-theme smoke modes and pinned mobile/wide viewports, so we target 0.2.x, which supports parameters.pixel.matrix (themes x named viewports) and maps cleanly onto the previous Chromatic modes.

Implementation

  • CI: chromatic.yml replaced by pixel.yml. The job skips the snapshot step when PIXEL_KEY is unset, only applies the fork guard to pull_request events (push and workflow_dispatch always run), reports the PR head SHA via PIXEL_COMMIT so the Pixel / Review status lands on the PR, and sets PIXEL_AUTO_REVIEW=true on main pushes so trunk builds become baselines without manual review.
  • Config: pixel.jsonc with the mux project ID and a default chrome/laptop (1200px) dark-theme matrix; one snapshot per story unless a story opts into more.
  • Stories (~40 files): parameters.chromatic becomes parameters.pixel. Shared constants collapse to PIXEL_DUAL_THEME and PIXEL_DISABLED in src/browser/stories/meta.tsx. Chromatic delay values are dropped because Pixel auto-stabilizes (fonts, network, DOM idle) with a 5s budget. Numeric viewports map to Pixel's named widths (phone 390, laptop 1200, desktop 1900); the 440px iPhone 17 Pro Max story frame clamps to min(100vw, 440px) so the phone capture is not clipped. Snapshot-runtime detection switches from Chromatic UA sniffing to the window.__PIXEL__ flag the CLI injects; production code inlines the check so the devDependency stays out of the bundle.
  • Contract tests: tests/ui/storybook/budget.test.ts now estimates Pixel cross-product matrices (rebaselined 293 to 305 because paired dark-desktop/light-mobile Chromatic modes became full theme x viewport grids); coverage.test.ts enforces the same dual-theme smoke contracts against parameters.pixel.
  • PR tooling: scripts/lib/pr_check_filters.sh and the wait/extract scripts now ignore the persistent Pixel / Review status instead of Chromatic statuses.
  • Docs/skills: AGENTS.md responsive-validation rule rewritten for Pixel matrix variants; generate-readme-screenshots skill updated.
  • Flake: the nix offline-cache hash is refreshed for the new dependency.

Validation

  • The Pixel job ran against this PR: Snapshot step succeeded, 331 snapshots uploaded with status=complete, and the Pixel / Review status appears on the head commit (pending human review in the dashboard, non-blocking).
  • Built Storybook locally and ran a Playwright crawl through Pixel's discovery path: 316 stories found, 47 excluded, 56 dual-theme, 38 viewport-pinned, zero leftover parameters.chromatic.
Issues found and fixed during CI iteration
  • The plan ToC play assertion raced the container-query layout settle under CI load: @storybook/test's waitFor defaults to a 1s timeout (the preview's configure({ asyncUtilTimeout }) targets the storybook/test module, not @storybook/test). Now uses an explicit 10s timeout and reports viewport/container widths on failure.
  • The workflow_dispatch trigger was initially skipped by the fork guard (Codex finding); the guard now only applies to pull_request events.
  • The 17 Pro Max fixed 440px frame overflowed Pixel's 390px phone viewport (Codex finding); clamped with min(100vw, ...).

Risks

  • Touch emulation gap: Pixel has no hasTouch, so pointer: coarse mobile affordances (hidden right sidebar, touch action buttons) are no longer visually captured. Phone-width layout coverage remains; the gap is documented in App.phoneViewports.stories.tsx and AGENTS.md.
  • Wide 1600px stories now snapshot at the 1900px desktop viewport (nearest named width); first baselines should be eyeballed in the Pixel dashboard.
  • The first main build after merge auto-approves as baseline; subsequent PRs diff against it. Review state lives in the Pixel dashboard, not a PR bot.

Generated with mux • Model: anthropic:claude-fable-5 • Thinking: xhigh • Cost: $116.77

Replaces the Chromatic workflow with @coder/pixel-storybook 0.2.0 uploading
to pixel.coder.com. Story-level parameters.chromatic (modes/delay/
disableSnapshot/hasTouch) become parameters.pixel (matrix/exclude), runtime
detection switches to window.__PIXEL__, and PR readiness scripts now ignore
the Pixel / Review commit status instead of Chromatic statuses.

The CI job skips cleanly until the PIXEL_KEY secret and a real platform
project ID exist.
Remove redundant migration comments, reuse Pixel's runtime helper, and make snapshot budget estimation cover every matrix axis.

Validation: make typecheck; make fmt-check; bun test ./tests/ui/storybook/budget.test.ts ./tests/ui/storybook/coverage.test.ts

---

_Generated with `mux` • Model: `openai:gpt-5.6-sol` • Thinking: `high`_

<!-- mux-attribution: model=openai:gpt-5.6-sol thinking=high -->
Inline the window.__PIXEL__ check in ChatPane instead of importing the
devDependency's isPixel() helper; stories may import it, shipped code must not.
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@mintlify

mintlify Bot commented Jul 17, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Mux 🟢 Ready View Preview Jul 17, 2026, 5:29 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Hash taken from the Flake Hash Check CI diff (nix unavailable locally).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 309d21d33c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/pixel.yml Outdated
…ssertion

The fork guard's job condition excluded workflow_dispatch events (Codex P2).
The ToC play used @storybook/test's default 1s waitFor timeout because the
preview's asyncUtilTimeout configure() targets the storybook/test module, so
the assertion raced the container-query layout settle under Pixel CI load and
failed the first Pixel build.
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

This reply is from Mux, an AI coding agent acting on Mike's behalf.

Addressed the workflow_dispatch finding in 51e84a4: the fork guard now only applies to pull_request events (github.event_name != 'pull_request' covers push and workflow_dispatch), so manual dispatches run.

@codex review

@Shelnutt2 Shelnutt2 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎉

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 51e84a43ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/stories/App.phoneViewports.stories.tsx
The plan ToC play failure reproduced at 11.3s under Pixel CI despite the 10s
waitFor, so it is a sizing issue, not a race. Include innerWidth/innerHeight
and the transcript container width in the error to identify why the container
query does not match in the Pixel capture environment.
Pixel has no 440px named viewport, so the fixed device frame overflowed the
390px phone capture and clipped the right edge (Codex P2).
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

This reply is from Mux, an AI coding agent acting on Mike's behalf.

Addressed in 67e8bb5: Pixel 0.2.1 only supports named viewports (phone 390 / tablet 744 / laptop 1200 / desktop 1900), so a 440px viewport is not expressible. The 17 Pro Max frame now clamps to min(100vw, 440px): Pixel captures a full uncut 390px-wide phone layout, while local Storybook and the test-runner still render the full 440px device frame.

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 67e8bb5b58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ibetitsmike
ibetitsmike added this pull request to the merge queue Jul 17, 2026
@ibetitsmike
ibetitsmike removed this pull request from the merge queue due to a manual request Jul 17, 2026
@ibetitsmike
ibetitsmike merged commit bb8c975 into main Jul 17, 2026
21 of 22 checks passed
@ibetitsmike
ibetitsmike deleted the mike/pixel-visual-regression branch July 17, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants