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:
@@ -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 () => {
|
||||
|
||||
@@ -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" }],
|
||||
|
||||
Reference in New Issue
Block a user