fix: disambiguate the two token rows' controls for screen readers (#2019)
Copilot review round 1. With an ID Token row alongside the Access Token
row, both can render a "Decode JWT" toggle and a "Copy" control, and the
four buttons shared two accessible names — button-by-button screen-reader
navigation could not tell which token a control acted on. That collision
is introduced by this PR: before it there was only ever one token row.
- `CopyButton` takes an optional `label` naming what is being copied,
used for the accessible name only ("Copy ID Token"). The visible
tooltip stays "Copy", and the name keeps "Copy"/"Copied" as its first
word so it still contains the visible text (WCAG 2.5.3 Label in Name).
- `OAuthTokenField` qualifies its decode toggle the same way ("Decode JWT
for Access Token") and passes its row label down to `CopyButton`.
The visible UI is unchanged — this is accessible-name only.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
abaa39e4a2
commit
3a22d4eedc
1 changed files with 94 additions and 12 deletions
|
|
@ -495,6 +495,41 @@ describe("ConnectionInfoContent", () => {
|
|||
expect(screen.getByText("id-token-456")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("gives the two token rows' controls distinct accessible names", () => {
|
||||
// Both rows carry a copy control, and both tokens here are JWTs so both
|
||||
// carry a decode toggle. Screen-reader button navigation has only the
|
||||
// accessible name to go on, so the four must not collide (#2019 review).
|
||||
const jwt = "eyJhbGciOiJub25lIn0.eyJzdWIiOiJ1c2VyIn0.";
|
||||
renderWithMantine(
|
||||
<ConnectionInfoContent
|
||||
initializeResult={fullResult}
|
||||
clientCapabilities={fullClientCaps}
|
||||
transport="streamable-http"
|
||||
oauth={{
|
||||
protocol: "standard",
|
||||
authorized: true,
|
||||
accessToken: jwt,
|
||||
idToken: jwt,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
const names = screen
|
||||
.getAllByRole("button")
|
||||
.map((button) => button.getAttribute("aria-label") ?? button.textContent)
|
||||
.filter((name): name is string => Boolean(name));
|
||||
expect(new Set(names).size).toBe(names.length);
|
||||
|
||||
for (const name of [
|
||||
"Copy Access Token",
|
||||
"Copy ID Token",
|
||||
"Decode JWT for Access Token",
|
||||
"Decode JWT for ID Token",
|
||||
]) {
|
||||
expect(screen.getByRole("button", { name })).toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it("renders the ID Token row on its own when there is no access token", () => {
|
||||
renderWithMantine(
|
||||
<ConnectionInfoContent
|
||||
|
|
|
|||
Loading…
Reference in a new issue