React Forum
Blog & Guide Responses
Oct 15, 2022 · 04:00 AM

Playwright Intro - discussion (2022-10-15)

Started by Priya Liao
externaltestingplaywrighte2eroutesdebugging

We’re trying to get serious about “route-flow” tests: not just clicking around, but asserting that posture/contract markers make the behavior explainable.

Read the docs

How do you scope Playwright tests in a React app so they’re high-signal and not a flaky mess? Do you render explicit markers (lane/posture/version) to assert on, or do you rely purely on user-visible text? What’s your strategy for debugging failures (screenshots, traces, DOM markers)?

Comments (10)

Back to latest
Maya Henson
Oct 15, 2022 · 04:06 AM

The best e2e tests assert on one thing: that the user can complete a flow. Everything else is a trap.

Dmitri Kline
Oct 15, 2022 · 04:14 AM

Markers are worth it if they’re honest and few.

We assert on a small set of route posture markers and treat them as part of the contract surface.

Related: Testing and Debugging and Performance and Rendering Best Practices.

Salma Qureshi
Oct 15, 2022 · 04:22 AM

A route-flow test that stays stable is usually “assert a marker, then assert one outcome”:

ts
import { test, expect } from '@playwright/test';

test('checkout route court posture', async ({ page }) => {
  await page.goto('/checkout');
  await expect(page.locator('[data-court]')).toHaveAttribute('data-court', 'dual');
  await page.getByLabel('Email').fill('a@b.com');
  await expect(page.getByText(/valid/i)).toBeVisible();
});
Keira Santos
Oct 15, 2022 · 04:31 AM

Counterpoint: markers can make teams stop caring about real user semantics.

If you only assert on data-*, you can ship something unusable that still “passes” because the marker says it’s fine.

Priya Liao
Oct 15, 2022 · 04:36 AM

100% agree. We use markers to *explain* behavior, not replace it.

The test still asserts a user-visible outcome; the marker is what makes failures debuggable.

Keira Santos
Oct 15, 2022 · 04:39 AM

That’s a good framing. Marker as narration, not as success criteria.

Hana Saito
Oct 15, 2022 · 04:47 AM

Big flake killer for us: never “wait for time”, always “wait for state”. If the UI has a visible status marker, the test can wait on that instead of guessing.

ts
await page.goto('/search');
await expect(page.locator('[data-status]')).toHaveAttribute('data-status', 'ready');
await expect(page.getByRole('heading', { name: /results/i })).toBeVisible();
Camille Duarte
Oct 15, 2022 · 04:56 AM

Traces are nice, but screenshots are still the fastest triage artifact if the UI is self-describing.

If the screenshot can’t prove posture/state, you end up reading logs anyway.

Noah Vance
Oct 15, 2022 · 05:07 AM

We reduced flake by cutting hidden sync effects.

A lot of e2e instability was “DOM changed after render because an effect settled state”.

Soren Malik
Oct 15, 2022 · 05:21 AM

One more: be intentional about selectors. If you assert on fragile CSS structure, your tests become a styling tax.

Either use roles/labels or a few explicit data-* markers with meaning.

Inez Park
Oct 15, 2022 · 05:32 AM

If a test fails and the screenshot doesn’t tell you what happened, your UI isn’t a contract surface yet.

Benji Rios
Oct 15, 2022 · 05:44 AM

We treat Playwright as “route truth enforcement”.

If a contract marker changes, a route-flow test should fail loudly so the team updates the story intentionally.