First working POC

This commit is contained in:
2026-01-26 22:21:54 +01:00
commit cfddc1edea
255 changed files with 77606 additions and 0 deletions
+256
View File
@@ -0,0 +1,256 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { get } from "svelte/store";
// Mock Tauri invoke
const mockInvoke = vi.fn();
vi.mock("@tauri-apps/api/core", () => ({
invoke: (...args: unknown[]) => mockInvoke(...args),
}));
// Mock the sessions store
const mockSelectSession = vi.fn();
vi.mock("./sessions", () => ({
sessions: {
selectSession: (...args: unknown[]) => mockSelectSession(...args),
},
selectedSession: {
subscribe: vi.fn((callback: (value: null) => void) => {
callback(null);
return () => {};
}),
},
}));
// Mock auth store
vi.mock("./auth", () => ({
auth: {
getRepository: vi.fn(() => ({
getPlaybackInfo: vi.fn().mockResolvedValue({ streamUrl: "http://test.com/stream" }),
getImageUrl: vi.fn().mockReturnValue("http://test.com/image"),
})),
},
}));
describe("playbackMode store", () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
describe("initial state", () => {
it("should have idle mode initially", async () => {
const { playbackMode } = await import("./playbackMode");
const state = get(playbackMode);
expect(state.mode).toBe("idle");
expect(state.remoteSessionId).toBeNull();
expect(state.isTransferring).toBe(false);
expect(state.transferError).toBeNull();
});
});
describe("setMode", () => {
it("should update mode locally", async () => {
const { playbackMode } = await import("./playbackMode");
playbackMode.setMode("local");
let state = get(playbackMode);
expect(state.mode).toBe("local");
playbackMode.setMode("remote", "session-123");
state = get(playbackMode);
expect(state.mode).toBe("remote");
expect(state.remoteSessionId).toBe("session-123");
});
});
describe("disconnect", () => {
it("should notify Rust backend and update local state when disconnecting", async () => {
const { playbackMode } = await import("./playbackMode");
// Set up remote mode first
playbackMode.setMode("remote", "session-123");
let state = get(playbackMode);
expect(state.mode).toBe("remote");
expect(state.remoteSessionId).toBe("session-123");
// Mock successful Rust call
mockInvoke.mockResolvedValueOnce(undefined);
// Call disconnect
await playbackMode.disconnect();
// Verify Rust backend was notified with correct mode
expect(mockInvoke).toHaveBeenCalledWith("playback_mode_set", { mode: "Idle" });
// Verify sessions.selectSession was called with null
expect(mockSelectSession).toHaveBeenCalledWith(null);
// Verify local state updated
state = get(playbackMode);
expect(state.mode).toBe("idle");
expect(state.remoteSessionId).toBeNull();
expect(state.transferError).toBeNull();
});
it("should do nothing if not in remote mode", async () => {
const { playbackMode } = await import("./playbackMode");
// Ensure we're in idle mode
playbackMode.setMode("idle");
const state = get(playbackMode);
expect(state.mode).toBe("idle");
// Call disconnect
await playbackMode.disconnect();
// Verify Rust backend was NOT called
expect(mockInvoke).not.toHaveBeenCalled();
expect(mockSelectSession).not.toHaveBeenCalled();
});
it("should handle errors gracefully", async () => {
const { playbackMode } = await import("./playbackMode");
// Set up remote mode first
playbackMode.setMode("remote", "session-123");
// Mock failed Rust call
const error = new Error("Failed to set mode");
mockInvoke.mockRejectedValueOnce(error);
// Call disconnect and expect it to throw
await expect(playbackMode.disconnect()).rejects.toThrow("Failed to set mode");
// Verify error was stored in state
const state = get(playbackMode);
expect(state.transferError).toBe("Failed to set mode");
});
it("should clear previous transfer errors on successful disconnect", async () => {
const { playbackMode } = await import("./playbackMode");
// Set up remote mode with an existing error
playbackMode.setMode("remote", "session-123");
// Manually set an error state (simulating a previous failed operation)
// We'll use clearError then verify it's cleared on disconnect
mockInvoke.mockResolvedValueOnce(undefined);
await playbackMode.disconnect();
const state = get(playbackMode);
expect(state.transferError).toBeNull();
});
});
describe("transferToRemote", () => {
it("should call Rust backend with session ID", async () => {
const { playbackMode } = await import("./playbackMode");
mockInvoke.mockResolvedValueOnce(undefined);
await playbackMode.transferToRemote("session-456");
expect(mockInvoke).toHaveBeenCalledWith("playback_mode_transfer_to_remote", {
sessionId: "session-456",
});
});
it("should update local state on success", async () => {
const { playbackMode } = await import("./playbackMode");
mockInvoke.mockResolvedValueOnce(undefined);
await playbackMode.transferToRemote("session-456");
const state = get(playbackMode);
expect(state.mode).toBe("remote");
expect(state.remoteSessionId).toBe("session-456");
expect(state.isTransferring).toBe(false);
});
it("should set isTransferring during transfer", async () => {
const { playbackMode } = await import("./playbackMode");
// Create a promise that we can control
let resolveTransfer: () => void;
const transferPromise = new Promise<void>((resolve) => {
resolveTransfer = resolve;
});
mockInvoke.mockReturnValueOnce(transferPromise);
// Start the transfer (don't await)
const transferPromiseResult = playbackMode.transferToRemote("session-789");
// Check that isTransferring is true during the transfer
let state = get(playbackMode);
expect(state.isTransferring).toBe(true);
// Resolve the transfer
resolveTransfer!();
await transferPromiseResult;
// Check that isTransferring is false after
state = get(playbackMode);
expect(state.isTransferring).toBe(false);
});
});
describe("clearError", () => {
it("should clear transfer error", async () => {
const { playbackMode } = await import("./playbackMode");
// Set up remote mode and simulate a failed transfer to set an error
playbackMode.setMode("remote", "session-123");
mockInvoke.mockRejectedValueOnce(new Error("Test error"));
try {
await playbackMode.disconnect();
} catch {
// Expected to throw
}
let state = get(playbackMode);
expect(state.transferError).toBe("Test error");
// Clear the error
playbackMode.clearError();
state = get(playbackMode);
expect(state.transferError).toBeNull();
});
});
describe("derived stores", () => {
it("isRemoteMode should be true when mode is remote", async () => {
const { playbackMode, isRemoteMode } = await import("./playbackMode");
playbackMode.setMode("remote", "session-123");
const isRemote = get(isRemoteMode);
expect(isRemote).toBe(true);
});
it("isLocalMode should be true when mode is local", async () => {
const { playbackMode, isLocalMode } = await import("./playbackMode");
playbackMode.setMode("local");
const isLocal = get(isLocalMode);
expect(isLocal).toBe(true);
});
it("isIdleMode should be true when mode is idle", async () => {
const { playbackMode, isIdleMode } = await import("./playbackMode");
playbackMode.setMode("idle");
const isIdle = get(isIdleMode);
expect(isIdle).toBe(true);
});
});
});