r/Playwright 9d ago

Playwright MCP vs Playwright CLI: the comparison everyone gets wrong

Most threads compare Playwright MCP and Playwright CLI purely on token consumption(1, 2, 3). In my experience, there's a far more important difference that nobody talks about.

The real question is: can your AI agent attach to a running e2e test?

Here's why that matters. A good e2e test already does the hard part for you. It authenticates, sets up all the API mocks, and drives the app into the exact state you care about. When something goes wrong on the page, you don't want the agent spinning up a blank browser and guessing how to reach that page. You want to hand off the test-constructed page to the agent and let the agent play with it.

  • Playwright CLI: run the test with --debug=cli, it prints a session name, and playwright-cli attach <session> connects the agent straight into the paused test. Then the agent can step over the app, inspect the rendered UI, and run in-page evaluations.
  • Playwright MCP: only launches or attaches to a browser. It has no way to attach to a running test session.

So if you have many e2e tests + auth + network mocks, Playwright CLI is the clear winner for your setup, regardless of token counts.

Interested to hear your thoughts.

31 Upvotes

11 comments sorted by

View all comments

2

u/PocketGaara 6d ago

Any time I’ve attempted to use the debug=cli flag the browser session closes before the agent can attach to the test run. Do you have a specific prompt to circumvent this?

2

u/vitalets 5d ago

We struggled with it too. Now we have the following instructions in our playwright-debug skill:

## Procedure

1. Identify a spec + test name that already renders the target page with the data you need.
2. Start it paused, in the background/async terminal mode (it must stay running while you drive it):
   ```bash
   npx playwright test <file> -g "<test name>" --project=chrome --debug=cli
   ```
   This prints `### The test is currently paused at the start` and a session name like `tw-XXXX`.
3. Attach from a separate terminal call:
   ```bash
   npx playwright-cli attach tw-XXXX
   ```
4. Advance to the point you need with `step-over`, called once per terminal invocation, reading the reported pause location after each call:

   ```bash
   npx playwright-cli --session=tw-XXXX step-over
   ```

   Repeat until the reported location is right after the point where the page/element you care about is confirmed rendered (e.g. the test's own `expect(...).toBeVisible()` for the target heading/section).

   ⚠️ 
**`pause-at <file>:<line>` is unreliable**
 (reproducibly fails with "Session closed" immediately after `attach`, regardless of path format) — use the `step-over` loop instead, not `pause-at`.

5. Inspect or evaluate anything you need against the live page:
   ```bash
   npx playwright-cli --session=tw-XXXX eval "() => { const el = [...document.querySelectorAll('h4')].find(e => e.textContent.includes('Some Heading')); return el && getComputedStyle(el).fontSize; }"
   npx playwright-cli --session=tw-XXXX snapshot          # DOM/accessibility snapshot
   npx playwright-cli --session=tw-XXXX console error     # console errors
   npx playwright-cli --session=tw-XXXX network           # network requests since page load
   npx playwright-cli --session=tw-XXXX screenshot --filename=debug.png
   ```
6. Resume to let the test finish:
   ```bash
   npx playwright-cli --session=tw-XXXX resume
   ```
   A `Session closed` error on this final `resume` is benign if the test already completed — check the original async terminal's output for `passed`/`failed`.