Files
coder/site/src/pages/CreateTokenPage/CreateTokenPage.test.tsx
T
Andrew Aquino e8489d556e test: await copy created token button before clicking (#26174)
fixes DEVEX-375

Replaces `getByRole` with async `findByRole`, which returns a promise /
rejects if no matching element is found after a default timeout of
1000ms

Co-written with Coder Agents. Relevant chat responses:

[I couldn't repro locally, so I inquired if there was a commit/PR that
fixed the flake within the past 3 weeks]

>No, this flake has not been fixed. There have been zero commits to
`CreateTokenPage`, `CopyButton`, `CodeExample`, or `useClipboard.ts`
since the failing CI run (13bf0e11f1, May 20).

>`getByRole` is synchronous, so it doesn't wait for the success modal
(containing the "Copy code" button) to render after the `createToken()`
mutation resolves. When the mutation is slow, the DOM still shows the
form (Cancel / Create token), and the query fails.
2026-06-11 16:36:16 -07:00

106 lines
2.9 KiB
TypeScript

import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { API } from "#/api/api";
import { HTTP_FALLBACK_DATA_ID } from "#/hooks/useClipboard";
import {
renderWithAuth,
waitForLoaderToBeRemoved,
} from "#/testHelpers/renderHelpers";
import CreateTokenPage from "./CreateTokenPage";
import { NANO_HOUR } from "./utils";
describe("TokenPage", () => {
const originalExecCommand = document.execCommand;
const originalNavigator = navigator;
afterEach(() => {
document.execCommand = originalExecCommand;
vi.restoreAllMocks();
});
const createToken = async () => {
vi.spyOn(API, "getTokenConfig").mockResolvedValue({
max_token_lifetime: 90 * 24 * NANO_HOUR,
});
vi.spyOn(API, "createToken").mockResolvedValueOnce({
key: "abcd",
});
const { container } = renderWithAuth(<CreateTokenPage />, {
route: "/settings/tokens/new",
path: "/settings/tokens/new",
});
await waitForLoaderToBeRemoved();
const form = container.querySelector("form") as HTMLFormElement;
await userEvent.type(screen.getByLabelText(/Name/), "my-token");
await userEvent.click(
within(form).getByRole("button", { name: /create token/i }),
);
};
it("shows the success modal", async () => {
// When
await createToken();
// Then
expect(screen.getByText("abcd")).toBeInTheDocument();
});
it("selects only the created token from the success modal", async () => {
await createToken();
const tokenContainer = screen.getByText("abcd").closest("div");
expect(tokenContainer).toBeInTheDocument();
const selectedRange = document.createRange();
selectedRange.selectNodeContents(tokenContainer as HTMLElement);
const selection = window.getSelection();
selection?.removeAllRanges();
selection?.addRange(selectedRange);
expect(selection?.toString().trim()).toBe("abcd");
selection?.removeAllRanges();
});
it("copies the created token from the success modal when clipboard fallback is used", async () => {
const mockClipboard: Clipboard = {
...originalNavigator.clipboard,
writeText: vi.fn().mockRejectedValue(new Error("Clipboard unavailable")),
};
vi.spyOn(window, "navigator", "get").mockImplementation(() => ({
...originalNavigator,
clipboard: mockClipboard,
}));
let copiedText = "";
document.execCommand = vi.fn((commandId) => {
const dummyInput = document.querySelector(
`input[data-testid=${HTTP_FALLBACK_DATA_ID}]`,
);
const inputCanReceiveDialogFocus =
commandId === "copy" &&
dummyInput instanceof HTMLInputElement &&
dummyInput.closest('[role="dialog"]') !== null &&
document.activeElement === dummyInput;
if (!inputCanReceiveDialogFocus) {
return false;
}
copiedText = dummyInput.value;
return true;
});
await createToken();
await userEvent.click(
await screen.findByRole("button", { name: "Copy code" }),
);
await waitFor(() => {
expect(copiedText).toBe("abcd");
});
});
});