123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
import { getFollowedChannels } from "../../src/lib/twitch";
|
|
|
|
describe("getFollowedChannels pagination + enrichment", () => {
|
|
beforeEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("returns only online channels with profile images and viewer counts", async () => {
|
|
// We'll simulate multiple fetch responses depending on the URL
|
|
const fetchMock: any = vi.fn().mockImplementation(async (input: any) => {
|
|
const url =
|
|
typeof input === "string" ? input : input.url?.toString() || "";
|
|
|
|
if (url.includes("/channels/followed")) {
|
|
// Serve two pages: first with cursor, second without
|
|
if (!fetchMock.page1Served) {
|
|
fetchMock.page1Served = true;
|
|
return {
|
|
ok: true,
|
|
json: async () => ({
|
|
data: [
|
|
{
|
|
broadcaster_id: "10",
|
|
broadcaster_login: "ch10",
|
|
broadcaster_name: "Ch10",
|
|
game_name: "Game1",
|
|
thumbnail_url: "thumb1",
|
|
},
|
|
{
|
|
broadcaster_id: "20",
|
|
broadcaster_login: "ch20",
|
|
broadcaster_name: "Ch20",
|
|
game_name: "Game2",
|
|
thumbnail_url: "thumb2",
|
|
},
|
|
],
|
|
pagination: { cursor: "CURSOR1" },
|
|
}),
|
|
};
|
|
}
|
|
|
|
// second page
|
|
return {
|
|
ok: true,
|
|
json: async () => ({
|
|
data: [
|
|
{
|
|
broadcaster_id: "30",
|
|
broadcaster_login: "ch30",
|
|
broadcaster_name: "Ch30",
|
|
game_name: "Game3",
|
|
thumbnail_url: "thumb3",
|
|
},
|
|
],
|
|
pagination: {},
|
|
}),
|
|
};
|
|
}
|
|
|
|
if (url.includes("/users?")) {
|
|
// User profile enrichment
|
|
return {
|
|
ok: true,
|
|
json: async () => ({
|
|
data: [
|
|
{ id: "10", profile_image_url: "p10" },
|
|
{ id: "20", profile_image_url: "p20" },
|
|
{ id: "30", profile_image_url: "p30" },
|
|
],
|
|
}),
|
|
};
|
|
}
|
|
|
|
if (url.includes("/streams?")) {
|
|
// Streams: only user 20 is live
|
|
return {
|
|
ok: true,
|
|
json: async () => ({
|
|
data: [
|
|
{
|
|
user_id: "20",
|
|
viewer_count: 50,
|
|
title: "Live Now",
|
|
started_at: "2024-01-01T00:00:00Z",
|
|
},
|
|
],
|
|
}),
|
|
};
|
|
}
|
|
|
|
// default
|
|
return { ok: false, status: 404 };
|
|
});
|
|
|
|
vi.stubGlobal("fetch", fetchMock as any);
|
|
|
|
const result = await getFollowedChannels("token", "client", "me");
|
|
|
|
// Only channel with id '20' should be online
|
|
expect(result).toHaveLength(1);
|
|
const ch = result[0];
|
|
expect(ch.id).toBe("20");
|
|
expect(ch.profileImageUrl).toBe("p20");
|
|
expect(ch.viewerCount).toBe(50);
|
|
});
|
|
|
|
it("throws when channels endpoint returns 401 Unauthorized", async () => {
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn().mockResolvedValue({ ok: false, status: 401 }),
|
|
);
|
|
|
|
await expect(getFollowedChannels("token", "client", "me")).rejects.toThrow(
|
|
"Twitch API error: 401 - Unauthorized. Token may be expired or invalid.",
|
|
);
|
|
});
|
|
});
|