Replace the remaining ~155 untyped invoke() calls across stores, services, components, and routes with the generated commands.* wrappers from $lib/api/bindings, so every IPC call is compile-time-checked against the command signatures. - Register repository_get_subtitle_url and repository_get_video_download_url in specta_builder() and the invoke_handler; regenerate bindings.ts. - Source duplicated wire types (AutoplaySettings, CacheConfig, Session, ConnectivityStatus, audio/video settings, etc.) from bindings. - Fix two bugs surfaced by the typed wrappers: - VideoDownloadButton passed an un-awaited Promise as the stream URL. - setAutoplaySettings omitted the required userId argument. - Update unit tests asserting the old invoke(name, args) shape. - Remove the five param-naming guard tests; the compiler and codegen now enforce what they checked. svelte-check: 0 errors. vitest: green. cargo test --lib: green.
191 lines
5.3 KiB
TypeScript
191 lines
5.3 KiB
TypeScript
/**
|
|
* Autoplay API tests
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
import {
|
|
getAutoplaySettings,
|
|
setAutoplaySettings,
|
|
cancelAutoplayCountdown,
|
|
playNextEpisode,
|
|
type AutoplaySettings,
|
|
} from "./autoplay";
|
|
import type { PlayItemRequest } from "./bindings";
|
|
|
|
vi.mock("@tauri-apps/api/core", () => ({
|
|
invoke: vi.fn(async (command: string, args?: any) => {
|
|
if (command === "player_get_autoplay_settings") {
|
|
return {
|
|
enabled: true,
|
|
countdownSeconds: 10,
|
|
maxEpisodes: 5,
|
|
};
|
|
}
|
|
if (command === "player_set_autoplay_settings") {
|
|
return args.settings;
|
|
}
|
|
if (command === "player_cancel_autoplay_countdown") {
|
|
return undefined;
|
|
}
|
|
if (command === "player_play_next_episode") {
|
|
return undefined;
|
|
}
|
|
return null;
|
|
}),
|
|
}));
|
|
|
|
// setAutoplaySettings sources the user id from the auth store
|
|
vi.mock("$lib/stores/auth", () => ({
|
|
auth: { getUserId: () => "user-1" },
|
|
}));
|
|
|
|
// Minimal valid PlayItemRequest for playNextEpisode tests
|
|
function makeItem(overrides: Partial<PlayItemRequest> = {}): PlayItemRequest {
|
|
return {
|
|
id: "item-123",
|
|
title: "Episode 1",
|
|
streamUrl: "http://example/stream",
|
|
videoCodec: "h264",
|
|
needsTranscoding: false,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("autoplay API", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("getAutoplaySettings", () => {
|
|
it("should fetch autoplay settings", async () => {
|
|
const settings = await getAutoplaySettings();
|
|
expect(settings).toHaveProperty("enabled");
|
|
expect(settings).toHaveProperty("countdownSeconds");
|
|
expect(typeof settings.enabled).toBe("boolean");
|
|
expect(typeof settings.countdownSeconds).toBe("number");
|
|
});
|
|
|
|
it("should invoke correct backend command", async () => {
|
|
const { invoke } = await import("@tauri-apps/api/core");
|
|
const invokeSpy = vi.mocked(invoke);
|
|
|
|
await getAutoplaySettings();
|
|
|
|
expect(invokeSpy).toHaveBeenCalledWith("player_get_autoplay_settings");
|
|
});
|
|
});
|
|
|
|
describe("setAutoplaySettings", () => {
|
|
it("should set autoplay settings with enabled true", async () => {
|
|
const settings: AutoplaySettings = {
|
|
enabled: true,
|
|
countdownSeconds: 15,
|
|
maxEpisodes: 5,
|
|
};
|
|
|
|
const result = await setAutoplaySettings(settings);
|
|
|
|
expect(result).toEqual(settings);
|
|
});
|
|
|
|
it("should set autoplay settings with enabled false", async () => {
|
|
const settings: AutoplaySettings = {
|
|
enabled: false,
|
|
countdownSeconds: 10,
|
|
maxEpisodes: 5,
|
|
};
|
|
|
|
const result = await setAutoplaySettings(settings);
|
|
|
|
expect(result.enabled).toBe(false);
|
|
});
|
|
|
|
it("should invoke correct backend command with settings", async () => {
|
|
const { invoke } = await import("@tauri-apps/api/core");
|
|
const invokeSpy = vi.mocked(invoke);
|
|
|
|
const settings: AutoplaySettings = {
|
|
enabled: true,
|
|
countdownSeconds: 20,
|
|
maxEpisodes: 5,
|
|
};
|
|
|
|
await setAutoplaySettings(settings);
|
|
|
|
const call = invokeSpy.mock.calls.find(
|
|
(c) => c[0] === "player_set_autoplay_settings"
|
|
);
|
|
expect(call).toBeDefined();
|
|
expect(call![1]).toEqual({ userId: "user-1", settings });
|
|
});
|
|
|
|
it("should support different countdown values", async () => {
|
|
const countdownValues = [5, 10, 15, 30];
|
|
|
|
for (const countdown of countdownValues) {
|
|
const settings: AutoplaySettings = {
|
|
enabled: true,
|
|
countdownSeconds: countdown,
|
|
maxEpisodes: 5,
|
|
};
|
|
|
|
const result = await setAutoplaySettings(settings);
|
|
expect(result.countdownSeconds).toBe(countdown);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("cancelAutoplayCountdown", () => {
|
|
it("should cancel autoplay countdown", async () => {
|
|
await cancelAutoplayCountdown();
|
|
|
|
const { invoke } = await import("@tauri-apps/api/core");
|
|
const invokeSpy = vi.mocked(invoke);
|
|
|
|
expect(invokeSpy).toHaveBeenCalledWith("player_cancel_autoplay_countdown");
|
|
});
|
|
});
|
|
|
|
describe("playNextEpisode", () => {
|
|
it("should play next episode with item", async () => {
|
|
const mockItem = makeItem();
|
|
|
|
await playNextEpisode(mockItem);
|
|
|
|
const { invoke } = await import("@tauri-apps/api/core");
|
|
const invokeSpy = vi.mocked(invoke);
|
|
|
|
const call = invokeSpy.mock.calls.find(
|
|
(c) => c[0] === "player_play_next_episode"
|
|
);
|
|
expect(call).toBeDefined();
|
|
expect(call![1]).toEqual({ item: mockItem });
|
|
});
|
|
|
|
it("should handle different item types", async () => {
|
|
const items = [
|
|
makeItem({ id: "1", title: "Episode 1" }),
|
|
makeItem({ id: "2", title: "Episode 2" }),
|
|
makeItem({ id: "3", title: "Episode 3" }),
|
|
];
|
|
|
|
for (const item of items) {
|
|
await expect(playNextEpisode(item)).resolves.toBeUndefined();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("autoplay settings structure", () => {
|
|
it("should have enabled boolean property", async () => {
|
|
const settings = await getAutoplaySettings();
|
|
expect(typeof settings.enabled).toBe("boolean");
|
|
});
|
|
|
|
it("should have countdownSeconds number property", async () => {
|
|
const settings = await getAutoplaySettings();
|
|
expect(typeof settings.countdownSeconds).toBe("number");
|
|
expect(settings.countdownSeconds).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
});
|