test(FN-4951): complete Step 5 — cover clipboard fallback and toast paths

Fusion-Task-Id: FN-4951
Fusion-Task-Lineage: 25de66db-c8cf-463b-86f2-efff1bc22683
This commit is contained in:
gsxdsm
2026-05-18 02:58:10 -07:00
parent 21d17e4005
commit b8f4042be4
2 changed files with 120 additions and 3 deletions

View File

@@ -842,6 +842,7 @@ describe("ModelOnboardingModal", () => {
it("renders github copilot device-code panel in onboarding", async () => {
const writeText = vi.fn().mockResolvedValue(undefined);
const addToast = vi.fn();
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: { writeText },
@@ -869,7 +870,7 @@ describe("ModelOnboardingModal", () => {
const mockWindowOpen = vi.fn();
vi.spyOn(window, "open").mockImplementation(mockWindowOpen);
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={vi.fn()} projectId="proj_123" />);
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={addToast} projectId="proj_123" />);
await waitFor(() => {
expect(screen.getByRole("button", { name: /Advanced provider settings/ })).toBeTruthy();
@@ -888,10 +889,72 @@ describe("ModelOnboardingModal", () => {
fireEvent.click(within(copilotCard).getByRole("button", { name: "Copy code" }));
expect(writeText).toHaveBeenCalledWith("ABCD-1234");
expect(writeText).toHaveBeenCalledTimes(2);
expect(addToast).toHaveBeenCalledWith("Copied code to clipboard", "success");
fireEvent.click(within(copilotCard).getByRole("button", { name: "Open GitHub" }));
expect(mockWindowOpen).toHaveBeenCalledWith("https://github.com/login/device", "_blank");
});
it("uses execCommand fallback in onboarding when clipboard API is unavailable", async () => {
const addToast = vi.fn();
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: undefined,
});
const execSpy = vi.spyOn(document, "execCommand").mockReturnValue(true);
mockFetchAuthStatus
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth" }] })
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth", loginInProgress: true }] });
mockLoginProvider.mockResolvedValueOnce({
url: "https://auth.example.com/login",
deviceCode: { userCode: "ABCD-1234", verificationUri: "https://github.com/login/device" },
});
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={addToast} projectId="proj_123" />);
await waitFor(() => {
expect(screen.getByRole("button", { name: /Advanced provider settings/ })).toBeTruthy();
});
fireEvent.click(screen.getByRole("button", { name: /Advanced provider settings/ }));
const copilotCard = await screen.findByTestId("onboarding-provider-card-github-copilot");
fireEvent.click(within(copilotCard).getByRole("button", { name: "Login" }));
await within(copilotCard).findByText("ABCD-1234");
fireEvent.click(within(copilotCard).getByRole("button", { name: "Copy code" }));
expect(execSpy).toHaveBeenCalledWith("copy");
expect(addToast).toHaveBeenCalledWith(expect.stringContaining("Copied"), "success");
});
it("shows error toast in onboarding when clipboard and fallback fail", async () => {
const addToast = vi.fn();
const writeText = vi.fn().mockRejectedValue(new Error("NotAllowedError"));
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: { writeText },
});
vi.spyOn(document, "execCommand").mockReturnValue(false);
mockFetchAuthStatus
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth" }] })
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth", loginInProgress: true }] });
mockLoginProvider.mockResolvedValueOnce({
url: "https://auth.example.com/login",
deviceCode: { userCode: "ABCD-1234", verificationUri: "https://github.com/login/device" },
});
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={addToast} projectId="proj_123" />);
await waitFor(() => {
expect(screen.getByRole("button", { name: /Advanced provider settings/ })).toBeTruthy();
});
fireEvent.click(screen.getByRole("button", { name: /Advanced provider settings/ }));
const copilotCard = await screen.findByTestId("onboarding-provider-card-github-copilot");
fireEvent.click(within(copilotCard).getByRole("button", { name: "Login" }));
await within(copilotCard).findByText("ABCD-1234");
fireEvent.click(within(copilotCard).getByRole("button", { name: "Copy code" }));
expect(addToast).toHaveBeenCalledWith(expect.stringContaining("manually"), "error");
});
it("keeps OpenAI Codex manual-code UX available in onboarding", async () => {

View File

@@ -1937,8 +1937,9 @@ describe("SettingsModal", () => {
});
});
it.skip("renders github copilot device code panel and handles copy/open actions", async () => {
it("renders github copilot device code panel and handles copy/open actions", async () => {
const writeText = vi.fn().mockResolvedValue(undefined);
const addToast = vi.fn();
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: { writeText },
@@ -1964,7 +1965,7 @@ describe("SettingsModal", () => {
},
});
renderModal();
render(<SettingsModal onClose={noop} addToast={addToast} />);
await waitForSettingsModalReady();
const copilotCard = screen.getByTestId("auth-provider-icon-github-copilot").closest(".auth-provider-card") as HTMLElement;
@@ -1979,6 +1980,7 @@ describe("SettingsModal", () => {
await userEvent.click(within(copilotCard).getByRole("button", { name: "Copy code" }));
expect(writeText).toHaveBeenCalledWith("ABCD-1234");
expect(writeText).toHaveBeenCalledTimes(2);
expect(addToast).toHaveBeenCalledWith("Copied code to clipboard", "success");
await userEvent.click(within(copilotCard).getByRole("button", { name: "Open GitHub" }));
expect(openSpy).toHaveBeenCalledWith("https://github.com/login/device", "_blank");
@@ -1988,6 +1990,58 @@ describe("SettingsModal", () => {
}, { timeout: 5000 });
});
it("uses execCommand fallback when clipboard API is unavailable", async () => {
const addToast = vi.fn();
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: undefined,
});
const execSpy = vi.spyOn(document, "execCommand").mockReturnValue(true);
mockFetchAuthStatus
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth" }] })
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth", loginInProgress: true }] });
mockLoginProvider.mockResolvedValueOnce({
url: "https://auth.example.com/login",
deviceCode: { userCode: "ABCD-1234", verificationUri: "https://github.com/login/device" },
});
render(<SettingsModal onClose={noop} addToast={addToast} />);
await waitForSettingsModalReady();
const copilotCard = screen.getByTestId("auth-provider-icon-github-copilot").closest(".auth-provider-card") as HTMLElement;
await userEvent.click(within(copilotCard).getByRole("button", { name: "Login" }));
await within(copilotCard).findByText("ABCD-1234");
await userEvent.click(within(copilotCard).getByRole("button", { name: "Copy code" }));
expect(execSpy).toHaveBeenCalledWith("copy");
expect(addToast).toHaveBeenCalledWith(expect.stringContaining("Copied"), "success");
});
it("shows error toast when clipboard API and fallback both fail", async () => {
const addToast = vi.fn();
const writeText = vi.fn().mockRejectedValue(new Error("NotAllowedError"));
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: { writeText },
});
vi.spyOn(document, "execCommand").mockReturnValue(false);
mockFetchAuthStatus
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth" }] })
.mockResolvedValueOnce({ providers: [{ id: "github-copilot", name: "GitHub Copilot", authenticated: false, type: "oauth", loginInProgress: true }] });
mockLoginProvider.mockResolvedValueOnce({
url: "https://auth.example.com/login",
deviceCode: { userCode: "ABCD-1234", verificationUri: "https://github.com/login/device" },
});
render(<SettingsModal onClose={noop} addToast={addToast} />);
await waitForSettingsModalReady();
const copilotCard = screen.getByTestId("auth-provider-icon-github-copilot").closest(".auth-provider-card") as HTMLElement;
await userEvent.click(within(copilotCard).getByRole("button", { name: "Login" }));
await within(copilotCard).findByText("ABCD-1234");
await userEvent.click(within(copilotCard).getByRole("button", { name: "Copy code" }));
expect(addToast).toHaveBeenCalledWith(expect.stringContaining("manually"), "error");
});
it("scrolls settings content to top after API key save succeeds", async () => {
mockFetchAuthStatus.mockResolvedValueOnce({
providers: [{ id: "openai", name: "OpenAI", authenticated: false, type: "api_key" }],