Skip to content
Chapter 90Lesson 4

Quiz - E2E on money paths only

Quiz progress

0 / 0

Your invoice app already has an integration test proving the Stripe webhook flips the plan in Postgres, and a component test proving the billing page renders the “Pro” badge when passed a Pro plan. A teammate wants to also add a Playwright test for the full upgrade. Does this one earn its weight?

Yes — only the browser can prove the session survives the redirect out to Stripe and back, and that the UI flips after the out-of-band webhook lands; that composition is what neither cheaper test sees.

No — the integration test plus the component test already compose to cover this, so the Playwright test only adds cost and flake.

No — checkout touches a third party Playwright can’t drive deterministically, so it belongs at the seam, not in the browser.

A small team on this stack has a disciplined integration suite and Sentry-led production observability, and ships its entire first year with zero Playwright tests. How should you read that?

It’s the correct default — the seam suite catches the clustered bugs, observability catches the unknowns, and manual smoke covers the rest until the runtime cost is worth paying.

It’s a coverage gap they’re behind on — the four money paths should have been in place from day one and the team is carrying hidden risk.

pnpm create playwright scaffolds a config with retries: 2, but the course overrides it to retries: process.env.CI ? 1 : 0. Why prefer one CI retry over the scaffold’s two?

One re-run is enough to tell a flake apart from a real failure; more retries start hiding real bugs behind a green check.

Two retries triple the CI runtime, and one retry is the cap that keeps the suite under the two-minute budget.

trace: 'on-first-retry' only captures a trace on the first retry, so any retry past the first records nothing useful.

Why does the E2E suite need a separate saas_e2e Postgres with a full reset between runs, instead of reusing the integration suite’s per-worker DB with a transaction rollback per test?

Playwright drives the server in a different process, so the test has no handle on the server’s transaction and can’t open-then-roll-back around a request — isolation has to move to a full reset between runs.

Playwright runs tests fully in parallel, and transaction rollback isn’t safe under parallel workers, so a reset is the only parallel-safe option.

A production build can’t connect to a per-worker test database, so E2E needs a single long-lived database that survives the whole run.

This assertion is in a merged spec and the test is passing, but a reviewer flags it as dangerous:

expect(page.getByRole('heading', { name: /dashboard/i })).toBeVisible();

What’s wrong?

The missing await — the web-first matcher returns an unawaited promise, so the test moves past it without ever checking the condition and passes silently.

toBeVisible doesn’t auto-wait, so it needs a preceding await page.waitForSelector(...) to avoid racing the redirect.

getByRole with a regex name can match more than one heading, so the assertion is ambiguous and should use getByText.

The Stripe Checkout spec fills the card fields with page.frameLocator('iframe[name^="__privateStripeFrame"]').getByLabel(/card number/i). Why reach inside a frameLocator here when every other path uses plain page locators?

Stripe nests its card fields in iframes the page doesn’t own, and a normal locator can’t see across that boundary — frameLocator scopes into the frame, where you still pin to role and label, never CSS.

frameLocator is how Playwright drives a third-party origin; any locator on checkout.stripe.com must go through it because the page is cross-origin.

Stripe’s fields load asynchronously, and frameLocator is the only locator that auto-waits for late-rendered inputs.

In the invoice value-loop spec, each test names its record invoice-${test.info().title}-${Date.now()} and asserts on that exact row, with no afterEach cleanup. Why this shape on a shared seeded org?

Parallel workers all write to the one saas_e2e org, so a unique id per test prevents row collisions, and the next db:e2e:reset is the canonical clean — deferred cleanup, not per-test deletes.

A timestamped id forces Playwright to create a fresh database per test, which is what guarantees isolation under fullyParallel.

Skipping afterEach keeps the test faster; the unique id is just a readable label so failures are easier to find in the report.

Your app’s primary sign-in is “Continue with Google.” For the per-PR Playwright suite, what’s the recommended way to cover it?

Drive the flow up to the redirect and assert the redirect URL your app built is correct — right client id, scopes, callback — and leave the full provider round-trip to an occasional manual pass.

Automate a real Google test account through the consent screen so the per-PR suite exercises the genuine round-trip.

Skip OAuth entirely in E2E and rely only on the integration test for the token exchange.

Quiz complete

Score by topic