Why trace a command instead of drawing the stack
Most Playwright architecture diagrams show you the same thing: a row of boxes from your test file to the browser, with arrows between them. You can memorise it in a minute, recite it in an interview, and still have no idea why your test just timed out.
The trace above takes the other approach. It follows a single command down through the layers and back, and at each hop it shows three things a static diagram cannot: the actual protocol message on the wire, the elapsed time, and the specific way that layer fails. That last column is the point of the whole exercise — architecture is only useful when it turns an error message into a diagnosis.
The five layers, briefly
- Your test — a Node.js file. Almost nothing happens here; a locator is just a description.
- Client API —
@playwright/test, which serialises your call into JSON-RPC. Everything crossing this line must be serialisable, which is the whole explanation for howpage.evaluate()behaves. - Driver — a separate Node process owning the browser connection. It runs the retry loops and enforces the timeouts.
- Browser protocol — CDP for Chromium, Juggler for Firefox, the Inspector Protocol for WebKit. The driver normalises all three, which is why your test code never changes across engines.
- Page & renderer — where the selector engine actually runs, where the actionability checks are evaluated, and where your app lives.
The three ideas the trace is really teaching
1. Auto-waiting is a loop, not a sleep
Step through the locator.click() flow and watch the bracketed section. The driver resolves the selector inside the page, runs five actionability checks, and — if any fail — throws the result away and does it all again. There is no poll interval to tune and no sleep anywhere in it.
Two consequences worth internalising. First, this is why a locator survives a React re-render while an ElementHandle from page.$() goes stale: the locator re-resolves on every pass, the handle points at a node that no longer exists. Second, every "Timeout 30000ms exceeded" failure is that loop never passing — so the useful move is reading which check was failing, not raising the timeout.
2. Where you put the await decides whether the test is flaky
The assertion flow exists for one comparison:
// Polls until it matches or the expect timeout expires
await expect(locator).toHaveText('Saved');
// Reads once, immediately. Fails if the UI needed another 40ms.
expect(await locator.textContent()).toBe('Saved');
Identical intent, completely different reliability. The first sends the expectation across the wire so the comparison retries near the DOM; the second pulls a value back into Node and compares it exactly once. This is the most common flakiness bug in real Playwright codebases, and it is invisible in a layer diagram.
3. Route handlers run in Node, and the page waits
The network-mocking flow is the only one that runs mostly upward. The browser pauses a matching request, sends an event up to the driver, which calls your handler in the test process — with full Node available, so you can read a fixture from disk or hit a real API. The whole time, the request is frozen.
That framing explains the failure mode people find hardest to debug: a handler that throws, or that never calls fulfill/abort/continue, leaves the page hanging until the test times out. Not an error — a hang.
How to use this before an interview
Turn off Protocol payloads and step through a flow trying to narrate each hop out loud. Where you stall is what you don't actually know yet. Then turn payloads back on and check yourself.
The "Say this in the interview" line under each flow is the compressed version — one sentence per command, the level of answer that signals you have debugged this rather than read about it. Pair it with the Playwright Most Asked question set, where the auto-waiting, locator, and mocking questions all come up directly.
A note on the timings
The millisecond figures are illustrative orders of magnitude for a local run, not measurements — they exist to show where time concentrates. The interesting shape is that in the click flow, almost all of it sits in the actionability loop waiting for the app, and almost none in the protocol hops. Playwright's overhead is rarely your slow test; your application usually is.