playwright-pnpm-workspace
Purpose
luna.mbt root pins @playwright/test@^1.58.2, but astra/package.json and sol/package.json independently pin ^1.59.1. Running pnpm exec playwright from the repo root resolves the older root-level version, while spec files imported from astra/e2e/ or sol/e2e/ resolve the newer per-package one. Playwright crashes with "did not expect test.describe()" because the registered test type and the discovered file disagree on which copy of @playwright/test they're holding.
This skill records which command to use for which directory and avoids burning a CI cycle on a version-skew bug.
When to use
- Adding or running a playwright config under
astra/e2e/orsol/e2e/ - Seeing
Playwright Test did not expect test.describe() to be called hereat test discovery - Adjusting
@playwright/testversions across the monorepo - Wiring a new
just test-…recipe that drives playwright
Workflow
Pick the runner based on where the spec lives
| Specs in | Use this command | Why |
|---|---|---|
| luna/e2e/** | pnpm exec playwright … (from repo root) | luna/ is not a separate workspace package; tests resolve through root's @playwright/test@1.58.2. |
| astra/e2e/** | cd astra && pnpm exec playwright … or pnpm -F @mizchi/astra-e2e exec playwright … | astra/package.json pins 1.59.1; root's 1.58.2 will crash. |
| sol/e2e/** | pnpm -F @luna_ui/sol-workspace exec playwright … | sol/package.json pins 1.59.1 too. cd sol is unreliable here because zsh redirects sol to a sibling repo via hash -d. |
Wired examples in justfile:
test-deployed-luna:
pnpm playwright test --config luna/e2e/deployed/playwright.config.mts
test-deployed-website:
cd astra && pnpm exec playwright test --config e2e/deployed/playwright.config.mts
test-sol-chaos:
pnpm -F @luna_ui/sol-workspace exec playwright test --config "$(pwd)/sol/e2e/playwright-sol-app-chaos.config.mts"
The $(pwd)/... absolute path on test-sol-chaos is intentional — pnpm -F runs in the workspace's own cwd, so a relative config path would resolve wrong.
Adding a new playwright config
- Decide which package owns the spec (root / astra / sol). The package that owns it sets which
@playwright/testversion applies. - If the new config lives under an existing playwright config's
testDir, add the new path to the existing config'stestIgnoreso the original suite doesn't accidentally pick it up. - Add a
just test-…recipe matching the runner table above. - Run locally before pushing. CI cycles on this kind of bug are expensive (only luna-e2e fails, the rest pass — easy to misdiagnose).
Symptoms of skew
Playwright Test did not expect test.describe() to be called here— you're running with the wrong@playwright/testfor the test file.Error: No tests foundafter the above — same root cause; playwright bailed before discovery completed.- A test suite under
astra/e2e/deployed/passes locally but theluna-e2eCI job fails referencing the same file — the localhost playwright config is also picking up the deployed/ specs because of glob-greedytestMatch. AddtestIgnore: ["**/deployed/**"].
Pitfalls
cd solin zsh on this machine redirects to~/ghq/github.com/mizchi/sol.mbt(a sibling repo), notluna.mbt/sol/. Usepnpm -Finstead, or absolute paths.testMatchis rooted attestDirbut**globs cross subdirectories. A new sibling dir under an existingtestDirwill be picked up unless explicitly ignored.- Don't unify versions casually. Bumping root to 1.59.1 looks tempting, but
vitest-browser(root devDep) currently pulls in@vitest/browser-playwright@4.0.18which has its own playwright peer constraint. Check the unmet-peer warnings before dragging the root version forward. pnpm -Fruns in the package's cwd. Relative--configpaths won't resolve as you expect when the package is nested. Pass an absolute path ($(pwd)/sol/e2e/...) orcdinto the package first.
Related
luna/e2e/playwright.config.mts,astra/e2e/playwright.config.mts,sol/e2e/playwright.config.mts— the three roots; each ignores**/deployed/**(and luna's also ignores**/visual-snapshots.test.tsin CI).justfile— the canonical recipes.