{"id":"l-tj-4-3","courseId":"testing-javascript","lang":"en","kind":"lesson","summary":"Debug failing Playwright tests with UI mode, the inspector and the trace viewer, then find and remove the usual causes of flakiness instead of retrying them away.","html":"<p>At a previous job we had an end-to-end suite that was red about one run in five. Everyone knew which tests “always do that”, so everyone reran the pipeline. Then one Friday a real checkout bug shipped, because its failing test was one of the ones that “always do that”. A flaky test isn’t a minor annoyance; it trains the whole team to ignore the alarm.</p>\n<p>This lesson has two halves: the tools for seeing why a test failed, and the short list of causes behind almost every flaky test.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Seeing what happened</h2>\n<p><strong>UI mode</strong> is where I spend most of my local debugging time:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> playwright</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> test</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --ui</span></span></code></pre></div>\n<p>It opens a window listing every test. Run one and you get a timeline of its actions; click any step to see a DOM snapshot of the page at that moment, plus console messages, network requests and the test source. It watches files and reruns on save. There’s a locator picker too: hover the snapshot and it suggests a locator.</p>\n<p><strong>The inspector</strong> steps through a test one action at a time in a headed browser:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> playwright</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> test</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> e2e/settle-up.spec.ts</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --debug</span></span></code></pre></div>\n<p>Add <code dir=\"ltr\">await page.pause()</code> in a test to stop at a specific point.</p>\n<p><strong>Traces</strong> are for failures you didn’t see happen, usually in CI. With <code dir=\"ltr\">trace: 'on-first-retry'</code> in the config, Playwright records a trace on the first retry of a failed test: every action, a DOM snapshot before and after it, console output, network calls and the source line. Download the report from CI and open the trace:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> playwright</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> show-report</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">            # HTML report, with traces attached</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> playwright</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> show-trace</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> trace.zip</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">   # a single trace</span></span></code></pre></div>\n<p>Ninety percent of the time, the snapshot at the failing step tells you the answer immediately: a spinner covering the button, an error toast, a different page than expected.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 160\" role=\"img\" aria-labelledby=\"l-tj-4-3-t1\"><defs><marker id=\"arrow-l-tj-4-3-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-tj-4-3-t1\">Four steps: the test fails in CI, Playwright retries it and records a trace, you open the trace and inspect the snapshot, then you fix the cause and confirm with repeat-each.</title>\n  <rect class=\"d-box-warn\" x=\"10\" y=\"40\" width=\"150\" height=\"70\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"85\" y=\"70\" text-anchor=\"middle\">Fails in CI</text>\n  <text class=\"d-label-muted\" x=\"85\" y=\"94\" text-anchor=\"middle\">first attempt</text>\n  <path class=\"d-arrow\" d=\"M160 75 L184 75\" marker-end=\"url(#arrow-l-tj-4-3-1)\"/>\n  <rect class=\"d-box-accent\" x=\"186\" y=\"40\" width=\"150\" height=\"70\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"261\" y=\"70\" text-anchor=\"middle\">Retry + trace</text>\n  <text class=\"d-code\" x=\"261\" y=\"94\" text-anchor=\"middle\">on-first-retry</text>\n  <path class=\"d-arrow\" d=\"M336 75 L360 75\" marker-end=\"url(#arrow-l-tj-4-3-1)\"/>\n  <rect class=\"d-box-primary\" x=\"362\" y=\"40\" width=\"150\" height=\"70\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"437\" y=\"70\" text-anchor=\"middle\">Read the trace</text>\n  <text class=\"d-code\" x=\"437\" y=\"94\" text-anchor=\"middle\">show-trace</text>\n  <path class=\"d-arrow\" d=\"M512 75 L536 75\" marker-end=\"url(#arrow-l-tj-4-3-1)\"/>\n  <rect class=\"d-box-success\" x=\"538\" y=\"40\" width=\"132\" height=\"70\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"604\" y=\"70\" text-anchor=\"middle\">Fix + prove</text>\n  <text class=\"d-code\" x=\"604\" y=\"94\" text-anchor=\"middle\">--repeat-each</text>\n</svg><figcaption>From a CI failure to a fix</figcaption></figure>\n<h2 id=\"sec-2\" tabindex=\"-1\">The usual suspects</h2>\n<p>Almost every flaky end-to-end test I’ve deleted or fixed had one of these causes.</p>\n<p><strong>1. Racing the page.</strong> Fixed sleeps (<code dir=\"ltr\">page.waitForTimeout(2000)</code>), values read once and asserted with a non-retrying matcher (<code dir=\"ltr\">expect(await locator.textContent()).toBe(...)</code>, <code dir=\"ltr\">expect(await locator.count()).toBe(3)</code>), or <code dir=\"ltr\">if (await locator.isVisible())</code> branches that check at one arbitrary instant. Fix: web-first assertions (<code dir=\"ltr\">toHaveText</code>, <code dir=\"ltr\">toHaveCount</code>, <code dir=\"ltr\">toBeVisible</code>) and actions that auto-wait.</p>\n<p><strong>2. Shared data.</strong> Tests that use the same group, the same user or the same seed records, and pass only in a particular order or with one worker. Fix: each test creates its own data, with unique names, through fixtures.</p>\n<p><strong>3. Uncontrolled time and randomness.</strong> “This week” logic that fails on Mondays, time zones that differ between your laptop and the CI runner, animations still running, random ids in assertions. Fix: <code dir=\"ltr\">page.clock</code> to set the time (<code dir=\"ltr\">await page.clock.setFixedTime(new Date('2026-03-04T10:00:00'))</code>), a fixed <code dir=\"ltr\">timezoneId</code> in the config’s <code dir=\"ltr\">use</code> block, and assertions that don’t depend on generated values.</p>\n<p><strong>4. Missing <code dir=\"ltr\">await</code>.</strong> <code dir=\"ltr\">page.getByRole('button', { name: 'Add expense' }).click()</code> without <code dir=\"ltr\">await</code> returns immediately; the next line races the click. Fix: the <code dir=\"ltr\">@typescript-eslint/no-floating-promises</code> lint rule catches these at write time.</p>\n<p>Third-party scripts (analytics, chat widgets, payment iframes) are a fifth, external cause: block them with <code dir=\"ltr\">page.route</code> in tests unless the test is about them.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Turning up retries until the suite is green</span></p>\n<p><code dir=\"ltr\">retries: 2</code> in CI is reasonable as a safety net: Playwright marks a test that failed and then passed as <strong>flaky</strong>, so you know about it. Raising retries to 5 and ignoring the flaky list turns the safety net into a blindfold. Real intermittent bugs (a race in <em>your</em> code, not the test) get retried away too.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Proving the fix</h2>\n<p>A flaky test that passed once proves nothing. Reproduce first, then prove the fix under the same pressure:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">npx</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> playwright</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> test</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> e2e/settle-up.spec.ts</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --repeat-each=30</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --workers=4</span></span></code></pre></div>\n<p>If it fails a few times in 30 before the fix and zero after, you’re done. In CI, <code dir=\"ltr\">--fail-on-flaky-tests</code> turns the flaky label into a failure, which some teams enable once the suite is clean so new flakiness can’t creep back in quietly.</p>\n<p>The exercise shows a test from a real-looking suite with several of these problems. Find them all. That closes the end-to-end section; section 5 steps back to ask how you judge a suite as a whole.</p>\n","toc":[{"id":"sec-1","text":"Seeing what happened","level":2},{"id":"sec-2","text":"The usual suspects","level":2},{"id":"sec-3","text":"Proving the fix","level":2}],"takeaways":["UI mode (<code dir=\"ltr\">npx playwright test --ui</code>) is the fastest local loop: watch mode, a timeline of every action and a DOM snapshot at each step.","With <code dir=\"ltr\">trace: 'on-first-retry'</code>, a test that fails in CI leaves a trace you can open with <code dir=\"ltr\">npx playwright show-trace</code> to replay it step by step.","Most flakiness comes from four causes: fixed sleeps or non-retrying assertions, shared data between tests, uncontrolled time or randomness, and missing <code dir=\"ltr\">await</code>s.","Reproduce flakiness with <code dir=\"ltr\">--repeat-each</code>, fix the cause, and treat tests marked flaky as bugs; retries are a smoke alarm, not a fix."],"further":[{"title":"Playwright — Trace viewer","url":"https://playwright.dev/docs/trace-viewer"},{"title":"Playwright — UI Mode","url":"https://playwright.dev/docs/test-ui-mode"},{"title":"Playwright — Debugging tests","url":"https://playwright.dev/docs/debug"},{"title":"Playwright — Clock","url":"https://playwright.dev/docs/clock"}],"quiz":[{"q":"<p>A test failed once in CI and passed on retry. Your config has <code dir=\"ltr\">trace: 'on-first-retry'</code>. What’s the fastest way to see what the page looked like when it failed?</p>","options":[{"text":"Rerun the CI job until it fails again, watching the logs.","why":"You might wait many runs, and logs don’t show the page; the evidence from the first failure is already there."},{"text":"Add <code dir=\"ltr\">console.log</code> calls around every action and push again.","why":"Logging is slow guesswork compared with a trace that recorded every action, snapshot and request."},{"text":"Download the report artifact and open the trace with <code dir=\"ltr\">npx playwright show-trace</code> (or the HTML report).","why":"Correct. The trace has DOM snapshots before and after each action, console output and network calls, so you can see exactly what the test saw."}],"answer":2},{"q":"<p>Which change fixes a test that sometimes fails on <code dir=\"ltr\">expect(await page.getByRole('listitem').count()).toBe(3)</code>?</p>","options":[{"text":"<code dir=\"ltr\">await expect(page.getByRole('listitem')).toHaveCount(3)</code>","why":"Correct. The web-first assertion re-counts until there are three items or the timeout passes; <code dir=\"ltr\">count()</code> reads once."},{"text":"Add <code dir=\"ltr\">await page.waitForTimeout(1000)</code> before the line.","why":"The sleep makes the test slower everywhere and still fails when CI is slower than one second."},{"text":"Set <code dir=\"ltr\">retries</code> to 3 in the config.","why":"Retries hide the race instead of removing it; the test will still fail sometimes, now more slowly."}],"answer":0},{"q":"<p>A test checks that an expense added today appears under “This week”. It fails every Monday at 00:30 in CI. What’s the most robust fix?</p>","options":[{"text":"Skip the test on Mondays.","why":"That hides a real behaviour you want covered and leaves the time dependency in place."},{"text":"Control time with <code dir=\"ltr\">page.clock</code> (for example <code dir=\"ltr\">setFixedTime</code>) so the test always runs on a known date.","why":"Correct. Pinning the clock makes the result independent of when the suite runs; you can also add a test for the Monday boundary on purpose."},{"text":"Run CI only during working hours.","why":"It moves the failure to whoever runs the suite at night or in another time zone."}],"answer":1},{"q":"<p>Playwright reports a test as “flaky”. What does that label mean?</p>","options":[{"text":"The test is slow and close to its timeout.","why":"Slowness alone isn’t flakiness; Playwright uses a separate “slow” annotation for that."},{"text":"The test was skipped because the browser crashed.","why":"Crashes produce failures or interruptions, not the flaky label."},{"text":"It failed at least once and then passed on a retry within the same run.","why":"Correct. With retries enabled, Playwright distinguishes “passed”, “failed” and “flaky”, so you can find and fix them."}],"answer":2}],"exercise":{"kind":"spot-bug","language":"ts","code":"import { test, expect } from '@playwright/test';\n\ntest('settling up clears the balances', async ({ page }) => {\n  await page.goto('/groups/lisbon-trip');\n  await page.getByLabel('Description').fill('Dinner');\n  await page.getByLabel('Amount').fill('30.00');\n  await page.getByRole('button', { name: 'Add expense' }).click();\n  page.getByRole('button', { name: 'Settle up' }).click();\n  await page.waitForTimeout(2000);\n  const status = await page.getByRole('status').textContent();\n  expect(status).toBe('Everyone is settled up');\n  await expect(page.getByRole('listitem')).toHaveCount(0);\n});","bugLines":[4,8,9,10,11],"title":"Find what makes this test flaky","prompt":"<p>This Playwright test fails about once in ten CI runs, never on the author’s laptop. Select <strong>every line</strong> that makes it flaky or unreliable. (Assume the app itself works.)</p>\n","hints":["Look for a line whose action is never waited for.","Look for a fixed wait, and for a value that is read once instead of asserted with a retrying matcher.","Think about which other tests might use a group with that exact name, at the same time, on four workers."],"explanation":"<p>Five lines cause trouble, for four reasons.</p>\n<ul>\n<li><strong>Line 4</strong> opens a shared, pre-seeded group, <code dir=\"ltr\">lisbon-trip</code>. Any other test that adds expenses to it, in parallel or earlier in the run, changes the balances this test sees. Use a fixture that creates a fresh group per test.</li>\n<li><strong>Line 8</strong> has no <code dir=\"ltr\">await</code>, so the click races the next line. Sometimes the settle-up happens before the status is read, sometimes after.</li>\n<li><strong>Line 9</strong> is a fixed two-second sleep: wasted time on a fast run, not enough on a slow one.</li>\n<li><strong>Lines 10 and 11</strong> read the status once with <code dir=\"ltr\">textContent()</code> and compare it with a plain <code dir=\"ltr\">toBe</code>, so nothing retries if the status updates a moment later.</li>\n</ul>\n<p>The fixed version:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"ts\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">TypeScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">test</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'settling up clears the balances'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">async</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> ({ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">page</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">group</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">goto</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">`/groups/${</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">group</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">.</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">id</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}`</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getByLabel</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Description'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">fill</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Dinner'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getByLabel</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Amount'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">fill</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'30.00'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getByRole</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'button'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, { name: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Add expense'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }).</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">click</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getByRole</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'button'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, { name: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Settle up'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }).</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">click</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">();</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> expect</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getByRole</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'status'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)).</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">toHaveText</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Everyone is settled up'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  await</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> expect</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(page.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getByRole</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'listitem'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)).</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">toHaveCount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">});</span></span></code></pre></div>\n<p>Line 12 was already right: <code dir=\"ltr\">toHaveCount</code> is a web-first assertion that retries.</p>\n","checkLabels":{}},"words":663,"readMinutes":3}