import { describe, expect, it } from "@effect/vitest"; import { IntegrationSlug } from "@executor-js/sdk/shared"; import * as Exit from "effect/Exit"; import * as React from "react"; import type { ReactElement, ReactNode } from "react"; import { GoogleServiceResultPanel, googleAddServicesPayload, submitGoogleServicesSelection, type AddGoogleServicesMutation, } from "./AddGoogleSource"; import type { GoogleAddServicesResult } from "../sdk/plugin"; type TestElementProps = { readonly children?: ReactNode; readonly onClick?: (event?: unknown) => void; }; const collectText = (node: ReactNode): string => { if (node === null || node === undefined || typeof node === "boolean") return ""; if (typeof node === "string" || typeof node === "number") return String(node); if (Array.isArray(node)) return node.map(collectText).join(" "); if (React.isValidElement(node)) return collectText(node.props.children); return ""; }; const findElementWithText = ( node: ReactNode, text: string, ): ReactElement | null => { if (node === null || node === undefined || typeof node === "boolean") return null; if (typeof node === "string" || typeof node === "number") return null; if (Array.isArray(node)) { for (const child of node) { const found = findElementWithText(child, text); if (found) return found; } return null; } if (!React.isValidElement(node)) return null; if (collectText(node.props.children).trim() === text) return node; return findElementWithText(node.props.children, text); }; const emptyResult: GoogleAddServicesResult = { added: [], skipped: [], failed: [], }; describe("AddGoogleSource per-service submit", () => { it("submits three checked presets in one addServices call", async () => { const calls: Parameters[0][] = []; const addServices: AddGoogleServicesMutation = (input) => { calls.push(input); return Promise.resolve(Exit.succeed(emptyResult)); }; await submitGoogleServicesSelection(addServices, { presetIds: ["google-calendar", "google-gmail", "google-drive"], }); expect(calls).toHaveLength(1); expect(calls[0]?.payload).toEqual({ services: [ { presetId: "google-calendar" }, { presetId: "google-gmail" }, { presetId: "google-drive" }, ], }); }); it("renders added, skipped, and failed result rows", () => { const result: GoogleAddServicesResult = { added: [ { slug: IntegrationSlug.make("google_calendar"), presetId: "google-calendar", toolCount: 12, }, ], skipped: [ { slug: IntegrationSlug.make("google_gmail"), presetId: "google-gmail", reason: "already_exists", }, ], failed: [ { slug: IntegrationSlug.make("google_drive"), presetId: "google-drive", error: "Discovery fetch failed", }, { slug: IntegrationSlug.make("google_custom"), presetId: "custom", error: "Custom Discovery fetch failed", }, { slug: IntegrationSlug.make("google_tasks"), presetId: "google_tasks", error: "Tasks Discovery fetch failed", }, ], }; const text = collectText( GoogleServiceResultPanel({ result, retryingPresetId: null, onRetry: () => {}, }), ); expect(text).toContain("Google Calendar"); expect(text).toContain("Added"); expect(text).toContain("Gmail"); expect(text).toContain("Already exists"); expect(text).toContain("Google Drive"); expect(text).toContain("Discovery fetch failed"); expect(text).toContain("Custom Discovery URLs"); expect(text).toContain("Custom Discovery fetch failed"); expect(text).toContain("Google Tasks"); expect(text).toContain("Tasks Discovery fetch failed"); expect(text).toContain("Retry"); }); it("retry re-submits only the failed presetId", async () => { let retryPresetId: string | null = null; const result: GoogleAddServicesResult = { added: [], skipped: [], failed: [ { slug: IntegrationSlug.make("google_drive"), presetId: "google-drive", error: "Discovery fetch failed", }, ], }; const retry = findElementWithText( GoogleServiceResultPanel({ result, retryingPresetId: null, onRetry: (presetId: string) => { retryPresetId = presetId; }, }), "Retry", ); retry?.props.onClick?.(); const calls: Parameters[0][] = []; const addServices: AddGoogleServicesMutation = (input) => { calls.push(input); return Promise.resolve(Exit.succeed(emptyResult)); }; await submitGoogleServicesSelection(addServices, { presetIds: retryPresetId ? [retryPresetId] : [], }); expect(calls).toHaveLength(1); expect(calls[0]?.payload).toEqual({ services: [{ presetId: "google-drive" }], }); }); it("passes name and slug overrides for a single selected service", () => { expect( googleAddServicesPayload({ presetIds: ["google-calendar"], identityOverride: { slug: "team_calendar", name: "Team Calendar", }, }), ).toEqual({ services: [ { presetId: "google-calendar", slug: "team_calendar", name: "Team Calendar", }, ], }); }); it("submits custom Discovery URLs without generic identity overrides", () => { expect( googleAddServicesPayload({ presetIds: ["google-calendar"], custom: { urls: ["https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest"], }, baseUrl: " https://proxy.example ", }), ).toEqual({ services: [ { presetId: "google-calendar" }, { custom: { urls: ["https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest"], }, }, ], baseUrl: "https://proxy.example", }); }); it("passes explicit custom Discovery URL identity overrides when supplied", () => { expect( googleAddServicesPayload({ presetIds: [], custom: { urls: ["https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest"], slug: "team_tasks", name: "Team Tasks", description: "Internal task workflow.", }, }), ).toEqual({ services: [ { custom: { urls: ["https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest"], slug: "team_tasks", name: "Team Tasks", description: "Internal task workflow.", }, }, ], }); }); });