diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.test.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.test.ts new file mode 100644 index 00000000000..c8150c176ad --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.test.ts @@ -0,0 +1,100 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test"; + +const hostUrl = "http://host-service"; +const repoPath = "/repos/octocat"; +const setupResult = { + repoPath, + mainWorkspaceId: "workspace-1", +}; +const cloudError = { + url: "https://github.com/octocat/hello.git", + message: "cloud-down", +}; + +const selectDirectoryMock = mock(async () => ({ + canceled: false, + path: repoPath, +})); +const findByPathMock = mock(async () => ({ + candidates: [] as { id: string; name: string }[], + cloudErrors: [] as (typeof cloudError)[], +})); +const setupMock = mock(async () => setupResult); +const createMock = mock(async () => ({ + projectId: "created-project", + repoPath, + mainWorkspaceId: "workspace-created", +})); +const finalizeSetupMock = mock(() => undefined); + +mock.module("react", () => ({ + useCallback: unknown>(callback: T) => + callback, +})); + +mock.module("renderer/lib/electron-trpc", () => ({ + electronTrpc: { + window: { + selectDirectory: { + useMutation: () => ({ mutateAsync: selectDirectoryMock }), + }, + }, + }, +})); + +mock.module("renderer/lib/host-service-client", () => ({ + getHostServiceClientByUrl: () => ({ + project: { + findByPath: { query: findByPathMock }, + setup: { mutate: setupMock }, + create: { mutate: createMock }, + }, + }), +})); + +mock.module("renderer/react-query/projects", () => ({ + useFinalizeProjectSetup: () => finalizeSetupMock, +})); + +mock.module( + "renderer/routes/_authenticated/providers/LocalHostServiceProvider", + () => ({ + useLocalHostService: () => ({ activeHostUrl: hostUrl }), + }), +); + +const { useFolderFirstImport } = await import("./useFolderFirstImport"); + +describe("useFolderFirstImport", () => { + beforeEach(() => { + for (const fn of [ + selectDirectoryMock, + findByPathMock, + setupMock, + createMock, + finalizeSetupMock, + ]) { + fn.mockClear(); + } + findByPathMock.mockResolvedValue({ candidates: [], cloudErrors: [] }); + }); + + it("reports cloud lookup errors instead of creating a duplicate local import when no candidates exist", async () => { + findByPathMock.mockResolvedValue({ + candidates: [], + cloudErrors: [cloudError], + }); + const onError = mock(() => undefined); + + const result = await useFolderFirstImport({ onError }).start(); + + expect(result).toBeNull(); + expect(findByPathMock).toHaveBeenCalledWith({ repoPath }); + expect(onError).toHaveBeenCalledWith( + "Couldn't reach cloud for https://github.com/octocat/hello.git: cloud-down", + ); + expect(createMock).not.toHaveBeenCalled(); + expect(setupMock).not.toHaveBeenCalled(); + expect(finalizeSetupMock).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.ts index 26167172f75..32e2ed88380 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/AddRepositoryModals/hooks/useFolderFirstImport/useFolderFirstImport.ts @@ -49,6 +49,11 @@ export function useFolderFirstImport(options?: { try { const response = await client.project.findByPath.query({ repoPath }); candidates = response.candidates; + if (candidates.length === 0 && response.cloudErrors.length > 0) { + const first = response.cloudErrors[0]; + onError?.(`Couldn't reach cloud for ${first.url}: ${first.message}`); + return null; + } } catch (err) { onError?.(err instanceof Error ? err.message : String(err)); return null;