Inspector
Pause a browser run, inspect the page, and choose better locators while developing tests.
The inspector is a development tool. Use it when you need to understand the live page: what the browser rendered, which element receives the click, why a locator is ambiguous, or what changed after an action.
It is not a CI strategy. On CI, prefer traces and screenshots. Locally, the inspector helps you build the test before you make it headless and repeatable.
When to use it
Use the inspector when:
- a locator matches nothing or too many elements,
- a click targets the wrong visible element,
- a frame or popup boundary is unclear,
- a test passes too quickly to observe,
- you need to inspect browser state before writing assertions.
Tip
Start with the inspector to understand the page, then encode that understanding as semantic locators and assertions. Do not leave the test dependent on manual inspection.
Start the inspector explicitly
Launch through PlaywrightFactory, enable the inspector on the browser builder, then pause at the state you need to examine:
use Playwright\PlaywrightFactory;
$playwright = PlaywrightFactory::create();
$browser = $playwright->chromium()
->withHeadless(false)
->withInspector()
->launch();
$context = $browser->newContext();
$page = $context->newPage();
$page->goto('https://app.example.test/settings');
$page->pause();
pause() blocks automation until you resume the run. Remove it, headed mode, and inspector configuration once the test is stable.
For a headed PHPUnit run without the inspector, pass a config built with PlaywrightConfigBuilder::fromEnv() to the provided test trait, then set PW_HEADLESS=false. The trait does not load that setting automatically.
Inspect locators
The inspector is most useful when improving locators. A good locator should describe the user-facing contract:
$page->getByRole('button', ['name' => 'Create account'])->click();
If the inspector shows that the button has no accessible name, the test has found a product issue. Fix the UI or use a deliberate fallback. Do not jump directly to a brittle CSS selector.
Pause around the uncertain step
When a test has one suspicious action, reduce the problem:
$page->goto('https://app.example.com/settings');
$page->getByRole('button', ['name' => 'Danger zone'])->click();
$page->pause();
$page->getByRole('button', ['name' => 'Delete account'])->click();
Look for:
- an overlay covering the target,
- a disabled control,
- a hidden frame,
- a different URL than expected,
- validation text that explains why the flow stopped.
Move from inspector to artifacts
Once the test is part of the suite, make it debuggable without a desktop:
- record a trace for failing CI runs,
- save screenshots at failure points,
- collect console messages for browser-side errors,
- keep downloaded/generated files when the file is part of the contract.
Warning
A headed browser can make a flaky test look understandable, but it does not make it deterministic. The final test should wait for product state, not for your eyes.
Verification checklist
- The failing step has been isolated.
- Locators were checked against the rendered page.
- The final test can run headless.
- CI has trace or screenshot evidence for the same failure class.
Go next
- Improve the target: Locators
- Follow the complete workflow: Debugging and logging
- Keep evidence for CI: Screenshots, video, and traces
- Fix a timing failure: Timeouts and retries