import { afterEach, describe, expect, test, vi } from "vitest"; import { createMarketApiClient, mapAuthorAseInfoResponse } from "../src/content/market/api-client"; import { normalizeRateValue } from "../src/shared/normalize-rate-value"; describe("market api client", () => { afterEach(() => { vi.useRealTimers(); }); test("normalizes known rate shapes", () => { expect(normalizeRateValue("<0.02%")).toBe("<0.02%"); expect(normalizeRateValue("0.02 - 0.1%")).toBe("0.02% - 0.1%"); }); test("maps the known author ase info response fields", () => { expect( mapAuthorAseInfoResponse({ data: { avg_search_after_view_rate: "<0.02%", personal_avg_search_after_view_rate: "0.02 - 0.1%" } }) ).toEqual({ rates: { personalVideoAfterSearchRate: "0.02% - 0.1%", singleVideoAfterSearchRate: "<0.02%" }, success: true }); }); test("returns bad-response when either target field is missing", () => { expect( mapAuthorAseInfoResponse({ data: { avg_search_after_view_rate: "<0.02%" } }) ).toEqual({ reason: "bad-response", success: false }); }); test("issues fetch with credentials include and a timeout signal", async () => { const fetchImpl = vi.fn(async () => ({ json: async () => ({ data: { avg_search_after_view_rate: "<0.02%", personal_avg_search_after_view_rate: "0.02 - 0.1%" } }), ok: true })); const client = createMarketApiClient({ baseUrl: "https://xingtu.cn", fetchImpl, timeoutMs: 8000 }); const result = await client.loadAuthorAseInfo("6629661559960371207"); expect(fetchImpl).toHaveBeenCalledWith( "https://xingtu.cn/gw/api/aggregator/get_author_ase_info?author_id=6629661559960371207&range=30", expect.objectContaining({ credentials: "include", method: "GET", signal: expect.any(AbortSignal) }) ); expect(result).toMatchObject({ success: true }); }); test("returns timeout when the request is aborted by the timeout budget", async () => { vi.useFakeTimers(); const fetchImpl = vi.fn( (_input: string, init?: RequestInit) => new Promise((_resolve, reject) => { init?.signal?.addEventListener("abort", () => { reject(Object.assign(new Error("aborted"), { name: "AbortError" })); }); }) ); const client = createMarketApiClient({ baseUrl: "https://xingtu.cn", fetchImpl, timeoutMs: 25 }); const resultPromise = client.loadAuthorAseInfo("6629661559960371207"); await vi.advanceTimersByTimeAsync(25); await expect(resultPromise).resolves.toEqual({ reason: "timeout", success: false }); }); test("returns request-failed for non-ok responses", async () => { const fetchImpl = vi.fn(async () => ({ json: async () => ({}), ok: false })); const client = createMarketApiClient({ baseUrl: "https://xingtu.cn", fetchImpl, timeoutMs: 8000 }); await expect( client.loadAuthorAseInfo("6629661559960371207") ).resolves.toEqual({ reason: "request-failed", success: false }); }); });