fix(mcp): point a role name that matches nothing at the node's text

Merged
HA
13d ago
+54-7

What and why

  • observe names a status, an alert, or a list item from its text, so an unlabelled <p role="status">Saved.</p> reads status "Saved.". A role query's name matches only the accessible name, which is empty here, so locate {role: "status", name: "Saved."} correctly finds nothing.
  • The zero-match advice then sent the agent back to the observation for the accessible name, or to exact: false. Neither can work for this node, and the exact: false hint repeated even on a query that already had it.
  • Each locate query now carries its own zero-match advice (packages/e2e/src/mcp/catalog.ts). A role query with a name says that observe can show a node's text in place of its name and prints the getByRole(role).filter({ hasText }) and getByText calls that match that text. The exact: false hint only shows while the query is still exact.
  • Docs: the locate row in docs/reference/mcp.mdx and workflow step 2 in skills/e2e/references/mcp.md. A real accessible name still matches as before, and the content-name policy from #583 is unchanged.

Verified

Ran it locally: yes - unit level, not the MCP server against a browser (no Chromium in my environment)

  • vitest run tests/unit/mcp-session.test.ts: the two new tests fail on main and pass here
mainthis branch
0 nodes match getByRole("status", name: "Saved.").
A test using this locator would fail with LOCATOR_NOT_FOUND. Check the accessible name in the observation (observe), or loosen the match with exact: false.
0 nodes match getByRole("status", name: "Saved.").
A test using this locator would fail with LOCATOR_NOT_FOUND. A role query matches the accessible name only, and observe can show a node's text in its place (a status or alert message, a list item). If "Saved." is that text, use screen.getByRole("status").filter({ hasText: "Saved." }) or screen.getByText("Saved."). Otherwise loosen the match with exact: false.

With exact: false the last sentence is left out.

Checklist

  • Changeset added (pnpm changeset) for any change to a published package, or the change is testbed, docs, or CI only.
  • Breaking change: title carries !, the changeset body names what breaks and what replaces it, and the deprecation warning landed a window earlier (stability policy in CONTRIBUTING.md).
  • Docs updated in the same PR: the docs/**/*.mdx page for the behavior, and skills/e2e/ if the skill describes it.
  • Contract change: emitted .d.ts reviewed, tests/types/sdk-types.ts updated; wire change edits the schema and both fixtures.
  • Engine contract change (e2e/engine): changesets for e2e, @e2e-dev/web, and @e2e-dev/mobile.

Fixes #1090