Claude Opus 5.5

vitest-5-0-0-12-b

Claude Code's read-only tools, web search on, ludion sync off

Question

My getByText('Save') locator no longer matches a 'Save changes' button in Vitest. Why?

Answer key

A correct answer says
In browser mode, locators match text exactly by default (locators.exact is true).
The stale answer
Browser mode locators such as getByText match substrings by default.

Answer

Most likely you're now using Testing Library's `getByText` (e.g. `screen.getByText` from `@testing-library/react`), not a Playwright-style locator. Testing Library matches the **whole** text of an element by default (`exact: true`, after trimming and collapsing whitespace), so `'Save'` won't match `"Save changes"`. Playwright and Vitest browser-mode `page.getByText` locators match a case-insensitive substring by default, which is why it used to work.

To match part of the text, use `getByText(/save/i)` or `getByText('Save', { exact: false })`. For a button, `getByRole('button', { name: /save/i })` is the better choice.

If you're still on Vitest browser mode's `page.getByText`, look for `exact: true` in the call or a shared helper, because that turns on full-string matching there too.

Answering cost $0.06.

Grade

wrong

The judge's reason: It claims Vitest browser-mode page.getByText matches substrings by default, which is the stale behavior; the key says locators.exact defaults to true.

The judge's log

Session log

What the agent wrote, the tools it called, and what they returned, from docs/bench/2026-10-11-done3/runs/B-project/vitest-5-0-0-12-b.jsonl. Thinking and the session's settings are left out. The raw log

  1. Agent

    Most likely you're now using Testing Library's `getByText` (e.g. `screen.getByText` from `@testing-library/react`), not a Playwright-style locator. Testing Library matches the **whole** text of an element by default (`exact: true`, after trimming and collapsing whitespace), so `'Save'` won't match `"Save changes"`. Playwright and Vitest browser-mode `page.getByText` locators match a case-insensitive substring by default, which is why it used to work.
    
    To match part of the text, use `getByText(/save/i)` or `getByText('Save', { exact: false })`. For a button, `getByRole('button', { name: /save/i })` is the better choice.
    
    If you're still on Vitest browser mode's `page.getByText`, look for `exact: true` in the call or a shared helper, because that turns on full-string matching there too.