What does the withdrawal of @playwright/experimental-ct-react mean for a suite that imports mount from it?
answer
- The package name was the warning
- Experimental means no stability promise
- Support moved into the main test package
- Imports and registration change, assertions do not
- Pinning delays rather than fixes
basics
~20 sThose packages were shipped as experimental, named so precisely to withhold a stability promise, and Playwright 1.63 no longer ships them. A suite importing from them has to move to the component support in @playwright/test.
solid answer
~40 s`@playwright/experimental-ct-react` and `@playwright/experimental-ct-vue` carried their status in the package name: an experimental package makes no compatibility promise and can change shape or disappear between releases, and these did. As of Playwright 1.63 the component capability lives in `@playwright/test` itself, where a test mounts a registered story rather than importing the component class into the spec. For a design-system suite that means the imports change, the runner configuration changes, and each spec has to point at a registered story instead of a direct import — while the assertions themselves, being ordinary `Locator` and `expect` calls, mostly survive untouched. The strategic reading matters more than the mechanics: the withdrawal is what an experimental dependency is allowed to do, so the lesson is to keep the blast radius small rather than to avoid such packages forever.
code
bash · 1 linegrep -rln "@playwright/experimental-ct-" . --include="*.ts" --include="*.tsx" --include="*.json"go deeper
Recognise the package name for what it says: an experimental package can change or disappear, and these two did. Component support now comes from the main test package instead.
Explain what moves and what does not. Imports, component registration and runner configuration change, while the Locator queries and expect assertions in the body of each spec survive untouched.
Demonstrate a migration you could actually run: inventory by import, configuration first, one spec converted with identical assertions, then batches that keep the suite green.
Own the adoption rule behind the incident. Decide where experimental tooling may be depended on, how many import sites are acceptable, and what the rehearsed exit looks like before the next withdrawal.
## The name was the contract `@playwright/experimental-ct-react` and `@playwright/experimental-ct-vue` did not become risky later; they announced it in the package name every time someone typed an import. **Experimental** meant the API could change shape between minor releases, that behaviour was not covered by the compatibility expectations attached to the stable surface such as `page` and `locator`, and that the package could be withdrawn entirely. That is exactly what happened: the per-framework `experimental-ct-*` packages are gone, and in Playwright 1.63 component support lives in `@playwright/test` itself, where a test mounts a component that has been registered as a story rather than importing the component into the spec file. ## What actually breaks, and what does not The damage is concentrated at the edges of the spec, not in its body. | Layer of the suite | Survives the withdrawal? | |---|---| | Import of `mount` from a framework package | No — it moves to `@playwright/test` | | Direct import of the component into the spec | No — the component is referenced as a registered story | | Runner configuration and harness files | No — the retired setup's own config and `playwright/` entry files go away | | `Locator` queries and `expect` assertions | Yes — ordinary Playwright API, untouched | | The reasoning about what the component should do | Yes — the tests still describe the same behaviour | That asymmetry is the good news. The part of a component suite that took judgement to write — which roles to query, which states to cover, which layout facts matter — is written against Playwright's stable API and moves across intact. The part that breaks is the wiring, and wiring is mechanical. ## A sane migration order 1. **Inventory by import.** Grep the suite for the retired package names; that list is the true scope, and it is usually a config file plus one import line per spec. 2. **Move the runner configuration first**, so a single command tells you the harness builds at all, before any spec is touched. 3. **Register the components as stories** — one entry per component and per interesting variant of the design-system package: the date picker, the data grid, the toast. 4. **Convert one spec end to end** and keep its assertions byte-identical, so a failure means the migration and not the component. 5. **Convert the rest in batches**, keeping the suite green between batches rather than landing one enormous change. ## What to take from it beyond the mechanics - **A package name that says experimental is a schedule, not a mood.** Read it as a promise that some future release will cost you a day. - **Keep the blast radius small.** If the experimental import appears in one helper that your specs call, a withdrawal is a one-file change; if it appears in three hundred specs, it is a project. - **Pinning is a delay, not a fix.** Freezing the runner on an older line keeps the suite compiling while it stops receiving engine updates, and the migration still waits at the end of it. - **Portable assertions are the hedge.** Because the assertions are plain `Locator` and `expect` calls, they were never hostage to the mounting package, and that is what makes the exit cheap. - **Experimental is often still worth adopting.** The judgement is not "never depend on it" but "depend on it where you can leave": few import sites, no bespoke abstractions layered on top, and a rehearsed exit. ## Why this belongs to the limits of a mount Every other boundary of a mounted run is structural — there is no app server, no router, no second component on the page. This one is a boundary of a different kind: **the maturity of the capability itself**. A team that builds a large part of its confidence on a component runner is also taking on the churn of that runner, and the withdrawn `experimental-ct-*` packages are the concrete evidence of what that churn looks like. Factoring that in is part of the honest reckoning: the mount buys real CSS and real clicks today, and it also buys a migration when the tooling underneath moves. Sizing that second cost — how many files would have to change, and how long the team would be red — is the difference between adopting a capability and being surprised by it.
- How would you scope the migration off the retired packages for a design-system suite?Inventory the specs by import, move the runner configuration first, then convert component by component: register each component as a story, switch the import to `@playwright/test`, and keep the assertions byte-identical so any failure points at the migration rather than the component.
- What would make you accept an experimental dependency in a test suite anyway?A small blast radius. Few files import it, the assertions stay written against the stable API, and the value is available now rather than in a year. The commitment worth making is a rehearsed exit, not a version pin.
saying these in an interview costs you the question
- Treating an experimental package as a stable dependency
- Assuming a version pin is a fix rather than a delay
- Believing the withdrawal removed component testing altogether
- Expecting the migration to be free because a codemod exists
- Thinking experimental only meant fewer features