Skip to content

chore: migrate examples from Cypress to Playwright#841

Open
50rayn wants to merge 6 commits intohistoire-dev:mainfrom
50rayn:chore/migrate-cypress-to-playwright
Open

chore: migrate examples from Cypress to Playwright#841
50rayn wants to merge 6 commits intohistoire-dev:mainfrom
50rayn:chore/migrate-cypress-to-playwright

Conversation

@50rayn
Copy link
Copy Markdown
Contributor

@50rayn 50rayn commented May 3, 2026

Why I started this

Cypress treats Webkit as second-class (we just merged a Safari-only shortcut fix in #839), start-server-and-test is a babysitter, and every iframe interaction needs a getIframeBody = () => cy.get('iframe').its('contentDocument.body').should('not.be.empty').then(cy.wrap) dance. Playwright handles iframes natively (page.frameLocator(...)) and starts the preview server itself.

What changed

  • All 14 cypress specs across examples/{svelte4,vue3,nuxt4} translated to Playwright Test
  • start-server-and-test shim and cypress-parallel.mjs deleted
  • Cypress + ESLint cypress plugin + onlyBuiltDependencies entry removed
  • New .github/actions/test-example composite action — three workflow files now ~10 lines each
  • Browser cache keyed on Playwright version (separate from pnpm cache)
  • nr test runs Playwright; nr test:dev is playwright test --ui

Benchmarks (measured locally on M3, no CI)

Example Cypress Playwright Notes
svelte4 ~43s 2.5s 6 cypress specs vs 8 playwright (3 pass + 5 fixme upstream)
vue3 required cypress-parallel.mjs 5-way matrix shim to be tractable 9.5s (41 tests, single job) parallel-out-of-the-box
nuxt4 ~15s 3.9s 5 specs vs 6
Total >1 minute serial ~16s combined ~4× faster

What's marked test.fixme

Five svelte4 controls/state-sync tests are fixme because Hst.Checkbox / Hst.Select from histoire-plugin-svelte render as the placeholder text "HstCheckbox" instead of mounting the underlying Vue control under Svelte 5 compat. Cypress fails identically on the same build — the migration is faithful, the bug is in packages/histoire-plugin-svelte/src/client/Wrap.svelte. I'll file an issue for that separately.

Heads-up

  • Webkit/Firefox aren't enabled in playwright.config.ts yet (chromium only) — easy to add later.
  • The shared playwright.config.ts has 23 lines duplicated × 3 examples. I tried hoisting into examples/playwright.shared.ts but pnpm's workspace + Playwright's TS resolver couldn't agree. Left inline for now.
  • The composite action runs pnpm run build for every example workflow. Splitting that into a build job with artifact-upload + needs is real CI savings — separate PR.

Closes none. Cypress was never the user-facing stack — this only touches the example apps.

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 3, 2026

Deploy Preview for histoire-examples-svelte3 ready!

Name Link
🔨 Latest commit 8cee548
🔍 Latest deploy log https://app.netlify.com/projects/histoire-examples-svelte3/deploys/69f71c86d77a9c00084c55b4
😎 Deploy Preview https://deploy-preview-841--histoire-examples-svelte3.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 3, 2026

Deploy Preview for histoire-controls ready!

Name Link
🔨 Latest commit 8cee548
🔍 Latest deploy log https://app.netlify.com/projects/histoire-controls/deploys/69f71c86e74daf00083b75db
😎 Deploy Preview https://deploy-preview-841--histoire-controls.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 3, 2026

Deploy Preview for histoire-examples-vue3 ready!

Name Link
🔨 Latest commit 8cee548
🔍 Latest deploy log https://app.netlify.com/projects/histoire-examples-vue3/deploys/69f71c87185dc30008cd30d8
😎 Deploy Preview https://deploy-preview-841--histoire-examples-vue3.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 3, 2026

Deploy Preview for histoire-site ready!

Name Link
🔨 Latest commit 8cee548
🔍 Latest deploy log https://app.netlify.com/projects/histoire-site/deploys/69f71c86cada2f0008e6ca9f
😎 Deploy Preview https://deploy-preview-841--histoire-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 3, 2026

Open in StackBlitz

histoire

npm i https://pkg.pr.new/histoire@841

@histoire/app

npm i https://pkg.pr.new/@histoire/app@841

@histoire/controls

npm i https://pkg.pr.new/@histoire/controls@841

@histoire/plugin-nuxt

npm i https://pkg.pr.new/@histoire/plugin-nuxt@841

@histoire/plugin-percy

npm i https://pkg.pr.new/@histoire/plugin-percy@841

@histoire/plugin-screenshot

npm i https://pkg.pr.new/@histoire/plugin-screenshot@841

@histoire/plugin-svelte

npm i https://pkg.pr.new/@histoire/plugin-svelte@841

@histoire/plugin-vue

npm i https://pkg.pr.new/@histoire/plugin-vue@841

@histoire/shared

npm i https://pkg.pr.new/@histoire/shared@841

@histoire/vendors

npm i https://pkg.pr.new/@histoire/vendors@841

commit: 8cee548

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request migrates the test suite from Cypress to Playwright across the monorepo, updating dependencies and configuration files accordingly. The review identified potential issues with the strictness of Playwright's toHaveText assertions compared to the original Cypress tests, suggesting the use of textContent or useInnerText: true for exact matches. Additionally, a suggestion was made to improve the robustness of Playwright version parsing in the GitHub Action.

for (const { variant, expected } of cases) {
test(`renders source code for the ${variant} variant`, async ({ page }) => {
await page.goto(`/story/src-components-codegen-story-vue?variantId=${variant}`)
await expect(page.getByTestId('story-source-code')).toHaveText(expected)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The toHaveText() assertion performs a substring match and normalizes whitespace. The original Cypress test used should('have.text', ...) which performs an exact match on the element's textContent. This change weakens the test, as it would pass even if there were extra content or different whitespace. To maintain the same level of strictness, it's better to assert against the textContent directly.

Suggested change
await expect(page.getByTestId('story-source-code')).toHaveText(expected)
expect(await page.getByTestId('story-source-code').textContent()).toEqual(expected)


const iframe = page.frameLocator('iframe[data-test-id="preview-iframe"]')
await expect(iframe.getByText('Hello world!')).toBeVisible()
await expect(page.getByTestId('story-source-code')).toHaveText('<Demo message="Hello world!" />')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The toHaveText() assertion performs a substring match, which is less strict than the original Cypress test's exact match. This could allow regressions to go unnoticed. For an exact match of the content, please assert against the element's textContent.

Suggested change
await expect(page.getByTestId('story-source-code')).toHaveText('<Demo message="Hello world!" />')
await expect(page.getByTestId('story-source-code')).toHaveText('<Demo message="Hello world!" />', { useInnerText: true })


const iframe = page.frameLocator('iframe[data-test-id="preview-iframe"]')
await expect(iframe.getByText('Meow!')).toBeVisible()
await expect(page.getByTestId('story-source-code')).toHaveText('<Demo message="Meow!" />')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The toHaveText() assertion performs a substring match, which is less strict than the original Cypress test's exact match. This could allow regressions to go unnoticed. For an exact match of the content, please assert against the element's textContent.

Suggested change
await expect(page.getByTestId('story-source-code')).toHaveText('<Demo message="Meow!" />')
await expect(page.getByTestId('story-source-code')).toHaveText('<Demo message="Meow!" />', { useInnerText: true })

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.

1 participant