Files
remanso/src/modules/repo/services/octo.spec.ts
Julien Calixte fc4ed188d7 feat(repo): add Octokit request timeouts and retry UI
Before, every GitHub call awaited indefinitely with no AbortSignal,
so a "lie-fi" connection (technically online, effectively dead) left
FluxNote stuck on the skeleton loader and the freshness badge spinning
forever. Inject an 8s AbortSignal.timeout via octokit.hook.before
(20s override on the recursive tree fetch), classify failures in the
userRepo store as auth vs network, and surface a "Couldn't reach
GitHub" retry button when no cached content is available.
2026-05-16 23:28:11 +02:00

63 lines
1.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
vi.mock("@/modules/user/service/signIn", () => ({
getAccessToken: vi.fn().mockResolvedValue({ token: "test-token" })
}))
import { DEFAULT_OCTOKIT_TIMEOUT_MS, getOctokit } from "./octo"
const okResponse = () =>
new Response("{}", {
status: 200,
headers: { "content-type": "application/json" }
})
describe("getOctokit timeout hook", () => {
beforeEach(() => {
vi.restoreAllMocks()
})
afterEach(() => {
vi.useRealTimers()
vi.restoreAllMocks()
})
it("injects an AbortSignal.timeout into requests by default", async () => {
const timeoutSpy = vi.spyOn(AbortSignal, "timeout")
let receivedSignal: AbortSignal | undefined
const mockFetch = vi.fn(async (_url: string, init: RequestInit) => {
receivedSignal = init.signal ?? undefined
return okResponse()
})
const octokit = await getOctokit()
await octokit.request("GET /user", {
request: { fetch: mockFetch as unknown as typeof fetch }
})
expect(timeoutSpy).toHaveBeenCalledWith(DEFAULT_OCTOKIT_TIMEOUT_MS)
expect(receivedSignal).toBeInstanceOf(AbortSignal)
})
it("respects a caller-provided signal and does not overwrite it", async () => {
const timeoutSpy = vi.spyOn(AbortSignal, "timeout")
const controller = new AbortController()
let receivedSignal: AbortSignal | undefined
const mockFetch = vi.fn(async (_url: string, init: RequestInit) => {
receivedSignal = init.signal ?? undefined
return okResponse()
})
const octokit = await getOctokit()
await octokit.request("GET /user", {
request: {
fetch: mockFetch as unknown as typeof fetch,
signal: controller.signal
}
})
expect(timeoutSpy).not.toHaveBeenCalled()
expect(receivedSignal).toBe(controller.signal)
})
})