Flaky-Test Diagnosis, Accessibility-Aware Testing, and Maintainable Architecture
Bringing this course's tools together: a real diagnostic process for flakiness, accessibility as a natural side effect of Playwright's own locator philosophy, and the structural choices that keep a growing suite maintainable.
What you'll learn
- Apply a systematic process for diagnosing a specific flaky test, rather than guessing
- Explain why role-based locators and axe-core-driven accessibility checks are naturally complementary in Playwright
- Identify the structural choices (folder layout, shared config, avoiding test interdependence) that keep a growing suite maintainable
Prerequisites
Explanation
Diagnosing a specific flaky test systematically, rather than guessing, means gathering real evidence in order: first, reproduce it — run the specific test repeatedly, ideally with --repeat-each locally, to confirm it's genuinely intermittent and not a one-off environmental fluke; second, capture a trace on the failing runs and read it — does the failure happen at a consistent step, or a different one each time (a consistent step points to a specific race condition; a varying step suggests broader timing sensitivity or test-data collision); third, check for the well-known usual suspects covered throughout this course — an ambiguous locator matching more than one element depending on timing, unawaited async work, colliding test data between parallel runs, or a genuine race condition in the application itself. Reaching for "just add a retry" or "just add a wait" before this diagnostic process, rather than after it's actually pointed at a specific cause, is treating the symptom without knowing what's actually wrong.
Accessibility-aware testing in Playwright isn't a separate, bolted-on feature — it emerges naturally from the locator philosophy this course opened with: a suite built on getByRole/getByLabel locators already exercises the accessibility tree on every single run, since those locators only find elements that expose a real, discoverable role and accessible name in the first place. @axe-core/playwright (used by this platform's own tests/e2e/accessibility.spec.ts suite) adds a complementary, distinct layer: an automated scan for a broader set of WCAG violations (color contrast, missing landmarks, invalid ARIA usage) that role-based locators alone don't check for — await new AxeBuilder({ page }).analyze() — the two approaches genuinely reinforce each other rather than duplicating effort.
Maintainable test architecture, drawing together every tool this course has covered: a clear folder structure separating page objects/helpers from test files; shared, centralized configuration (one playwright.config.ts, not scattered per-file settings) so a change applies consistently everywhere; and critically, no test depending on another test's side effects or execution order — each test must be independently runnable, in any order, in isolation, which is precisely what this course's context-per-test isolation, unique test-data generation, and API-based setup were all building toward from the very first lesson. A suite where tests secretly depend on running in a specific sequence isn't really taking advantage of Playwright's actual isolation guarantees — it's fighting against them, and it will eventually fail in confusing, hard-to-reproduce ways the moment execution order changes for any reason (parallelism, test filtering, retries).
Example
Modeling the systematic flaky-test diagnostic process as a decision function, and the role-locator/axe-scan complementary relationship.
function diagnoseFlaky(observations) {
// observations: { reproduced, failureStepConsistent, ambiguousLocator, uncontrolledTestData }
if (!observations.reproduced) return "not confirmed flaky yet -- reproduce first";
if (observations.ambiguousLocator) return "likely cause: ambiguous locator matching multiple elements";
if (observations.uncontrolledTestData) return "likely cause: colliding test data between parallel runs";
if (observations.failureStepConsistent) return "likely cause: a specific race condition at a consistent step";
return "inconsistent failure step -- broader timing sensitivity, needs deeper trace analysis";
}
console.log(diagnoseFlaky({ reproduced: true, failureStepConsistent: true, ambiguousLocator: true, uncontrolledTestData: false }));
// "likely cause: ambiguous locator matching multiple elements" -- checked before the vaguer "consistent step" conclusion
function coverageLayers(usesRoleLocators, usesAxeScan) {
const layers = [];
if (usesRoleLocators) layers.push("accessible-by-construction (getByRole/getByLabel require a real role/name)");
if (usesAxeScan) layers.push("automated WCAG scan (contrast, landmarks, ARIA validity)");
return layers;
}
console.log(coverageLayers(true, true)); // both layers -- genuinely complementary, not redundantTry it yourself
Call diagnoseFlaky with reproduced:false and confirm it correctly refuses to guess a cause before reproduction is confirmed.
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
Write diagnoseFlaky(observations) implementing the exact priority order from this lesson: not reproduced -> 'reproduce first'; ambiguous locator -> that cause; uncontrolled test data -> that cause; consistent failure step -> race condition at that step; otherwise -> 'needs deeper trace analysis'.
Checks: requires reproduction before diagnosing · identifies an ambiguous locator as the cause when present · identifies colliding test data when it's the relevant cause · falls back to requesting deeper analysis when nothing specific is identified
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Write hasTestInterdependence(tests) where tests is an array of {name, dependsOnTestName} objects (dependsOnTestName is null if independent). Return true if ANY test has a non-null dependsOnTestName -- modeling a maintainability check that would flag a suite secretly relying on execution order.
Checks: detects a genuine test dependency · confirms fully independent tests as safe · handles an empty test list
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Adding a retry or a wait to a flaky test before actually diagnosing its cause -- this can mask the real problem (a race condition, an ambiguous locator, colliding test data) instead of fixing it, and the underlying bug can still surface in production.
- Treating axe-core scans and role-based locators as redundant with each other -- they check genuinely different things (a broader automated WCAG scan versus locators that only find elements with real accessible roles/names in the first place); a mature suite uses both.
- Letting a later test rely on state left behind by an earlier one (a shared, uncleaned fixture, a specific execution order) -- this fights against Playwright's actual isolation guarantees and produces confusing failures the moment execution order changes for any reason.
Knowledge check
Takeaway
Diagnose flakiness by reproducing it and checking known causes in order, not by reflexively adding retries or waits; treat role-based locators and automated accessibility scans as complementary, not redundant; and keep every test genuinely independent of execution order, which is what all of this course's isolation techniques were building toward.
Summary
Flaky-test diagnosis: reproduce, capture and read a trace, check known causes (ambiguous locators, colliding test data, race conditions) in order — before reaching for retries or waits. Role-based locators and axe-core scans check different, complementary accessibility concerns. Maintainable architecture means centralized config, clear structure, and zero test interdependence on execution order.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.