125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
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
|
|
});
|
|
});
|
|
});
|