Skip to content

refactor: migrate tests from cypress to playwright - #11089

Open
robert-hebel-sb wants to merge 14 commits into
mainfrom
chore/playwright-migration
Open

robert-hebel-sb wants to merge 14 commits into
mainfrom
chore/playwright-migration

Conversation

@robert-hebel-sb

@robert-hebel-sb robert-hebel-sb commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Description

Replaces the Cypress end-to-end suite with an equivalent Playwright suite written entirely in TypeScript.

  • Specs: all 112 Cypress specs from test/e2e-cypress/e2e/{a11y,bugs,features,security} are ported 1:1 to test/e2e-playwright/**/*.spec.ts (634 tests, same titles and assertions). Existing it.skip tests remain skipped.
  • Config and support:
    • playwright.config.ts starts the webpack dev-e2e server (:3230) and the mock API (:3204), and uses Chromium only.
    • The OAuth2 test server (:3231) is started in global setup.
    • A strict test/e2e-playwright/tsconfig.json covers specs and config.
    • A shared test fixture provides a small swaggerUi helper.
    • Uncaught page exceptions are logged via console.error and fail the test during fixture teardown. This matches the old Cypress behavior: its uncaught:exception handler returned true, and only returning false suppresses the failure.
  • Moved assets: static/ moved to test/e2e-playwright/static/ and webpack/dev-e2e.js points at it. The OAuth2 server and the multiple-examples helper are ported to TypeScript.
  • Scripts: cy:* replaced by e2e, e2e:ui, e2e:headed, e2e:report, e2e:server, e2e:mock-api, e2e:typecheck. npm test now runs e2e.
  • CI: the build job also runs npm run e2e:typecheck (strict tsc over the Playwright tests, since Playwright does not type-check). The e2e-tests job installs Chromium, caches ~/.cache/ms-playwright, runs 4 shards (--shard=N/4), and uploads the HTML report and traces on failure.
  • Dependencies:
    • Added: @playwright/test 1.63.0 and @types/cors 2.8.19. @types/cors is needed to type the ported OAuth2 server under strict. @axe-core/playwright is not needed because the Cypress a11y specs never used axe.
    • Removed: cypress and start-server-and-test.
  • Docs: README, CLAUDE.md, docs/development/scripts.md and the .claude guidance docs updated.

Notable translation decisions:

  • cy.wait(ms) was replaced by web-first assertions (or expect.poll) throughout, except bugs/5138, which keeps a fixed 3s wait because it checks that the title stays stable over time.
  • Cypress .type() special sequences ({selectall}, {{}, {enter}, {leftarrow}) were translated explicitly.
  • cy.intercept / cy.stub became page.route / exposeFunction + addInitScript.
  • Two oas31 specs had two tests with identical titles (Playwright rejects duplicates). The second was renamed to describe

Tests that were passing vacuously in Cypress (the check ran before the page rendered):

  • info: the fixture info-openAPI30.yaml declared openapi: 3.1.0, so the 3.1-only summary was rendered. The fixture now declares 3.0.0.
  • license: "should render nothing if both URL & SPDX exists" never matched the app. selectLicenseUrl deliberately prer`. The test is renamed to "should prefer the URL over the SPDX identifier if both exist" and asserts that.

Motivation and Context

How Has This Been Tested?

  • npm run e2e (full Playwright suite): all green.
  • Flake check in CI mode (CI=true --repeat-each=3 --workers=2 --retries=0): 1887 passed, 15 skipped, 0 failures.
  • After merging main: full suite again, 631 passed, 3 skipped, 0 failed.
  • npm run lint (0 errors, no warnings in the new files; the remaining 36 warnings pre-exist), npm run test:unit, npm run build, npm run test:artifact.
  • The workflow YAML parses, but actionlint was not available locally, so the CI job has not been run on GitHub yet.

Known gaps, carried over rather than fixed:

  • Several Cypress negative assertions (not.exist right after an action) were already weak and were ported as is.
  • Some specs only check element presence rather than content (for example request-body-upload-file never uploads a file

Screenshots (if appropriate):

N/A

Checklist

My PR contains...

  • No code changes (src/ is unmodified: changes to documentation, CI, metadata, etc.)
  • Dependency changes (any modification to dependencies in package.json)
  • Bug fixes (non-breaking change which fixes an issue)
  • Improvements (misc. changes to existing features)
  • Features (non-breaking change which adds functionality)

My changes...

  • are breaking changes to a public API (config options, System API, major UI change, etc).
  • are breaking changes to a private API (Redux, component props, utility functions, etc.).
  • are breaking changes to a developer API (npm script behavior changes, new dev system dependencies, etc).
  • are not breaking changes.

Documentation

  • My changes do not require a change to the project documentation.
  • My changes require a change to the project documentation.
  • If yes to above: I have updated the documentation accordingly.

Automated tests

  • My changes can not or do not need to be tested.
  • My changes can and should be tested by unit and/or integration tests.
  • If yes to above: I have added tests to cover my changes.
  • If yes to above: I have taken care to cover edge cases in my tests.
  • All new and existing tests passed.

robert-hebel-sb and others added 11 commits September 30, 2026 16:14
Add @playwright/test and @types/cors (pinned), playwright.config.ts, a
strict tsconfig scoped to test/e2e-playwright, a shared `test` fixture,
and TS ports of the OAuth2 test server and multiple-examples helper.
Move static/ and fixtures/ to test/e2e-playwright and point the dev-e2e
webpack server at the new location. Replace cy:* scripts with e2e:*.
Migrate deep-linking and security/oauth2 specs as proof.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Includes the deep-linking and security/oauth2 proof specs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
info and license each carry one test.fixme: the Cypress versions of those
assertions passed vacuously (checked before render) and the app/fixture
behave differently from what the tests claim.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Install chromium, cache ~/.cache/ms-playwright, shard with --shard=N/4 and
upload the HTML report and traces on failure. Drop the Cypress cache.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remove cypress and start-server-and-test, cypress.config.js, the remaining
Cypress files and the temporary migration inventory. Update README,
CLAUDE.md, docs/development and .claude guidance for Playwright.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
info-openAPI30.yaml declared openapi 3.1.0, so the 3.1-only summary was
rendered; declare 3.0.0 and wait for render before asserting absence.
The license test claimed nothing renders when url and identifier are both
set, but the app lets url win; assert that instead. bugs/5138 uses a real
3s wait again, matching the original cy.wait(3000).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

# Conflicts:
#	package-lock.json
@robert-hebel-sb
robert-hebel-sb requested a balanced review from Copilot October 8, 2026 09:06
Comment thread test/e2e-playwright/features/oas-badge.spec.ts Fixed
Comment thread test/e2e-playwright/support/oauth2-server/index.ts Dismissed
Comment thread test/e2e-playwright/support/oauth2-server/index.ts Dismissed

Copilot AI 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.

🟡 Changes recommended

Uncaught browser exceptions no longer fail tests, allowing application crashes to pass unnoticed.

1 open finding
What changed in this PR

Migrates the end-to-end test infrastructure from Cypress to TypeScript-based Playwright.

Changes:

  • Ports Cypress specifications, fixtures, static assets, and OAuth support.
  • Adds Playwright configuration, sharded CI execution, and updated npm scripts.
  • Updates documentation and removes Cypress infrastructure.
File Description
playwright.config.ts Configures Playwright, servers, retries, and Chromium.
test/​e2e-playwright/​** Adds ported specifications, fixtures, support utilities, and assets.
test/​e2e-cypress/​** Removes the former Cypress suite.
.github/​workflows/​nodejs.yml Adds sharded Playwright CI execution and artifacts.
webpack/​dev-e2e.js Serves Playwright test assets.
package.json /​ package-lock.json Replaces Cypress dependencies and scripts.
Documentation and metadata files Updates testing instructions and path references.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread test/e2e-playwright/support/fixtures.ts Outdated
robert-hebel-sb and others added 2 commits October 8, 2026 11:15
Cypress only suppresses an uncaught:exception when the handler returns
false; the old handler returned true, so such exceptions failed tests.
Collect weberror events and fail during fixture teardown to keep that
behavior. The full suite passes with this in place.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Addresses the CodeQL incomplete string escaping alert.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Copilot AI 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.

🟡 Changes recommended

The strict Playwright TypeScript project is not type-checked in CI, and documented page-error behavior contradicts its implementation.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread test/e2e-playwright/support/fixtures.ts
Playwright transpiles TypeScript without type-checking and ESLint does
not either, so add an e2e:typecheck script and run it in the build job.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Copilot AI 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.

🔵 Needs a closer look

The broad 634-test runner migration and CI orchestration changes require final human confirmation of behavioral parity.

1 open finding

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

@aslushnikov

aslushnikov commented Oct 16, 2026 •

Copy link
Copy Markdown

@robert-hebel-sb @cka121 @glowcloud if you folks are interested in a tests dashboard for Playwright, I'd be happy to provide you one for free as part of the "Flakiness.io Open Source" program. Other big projects like WordPress or Nuxt are already part of it.

Let me know if you're interested!

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.

4 participants