Files

192 lines
5.1 KiB
TypeScript
Raw Permalink Normal View History

import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock the videoSession store (playback.ts imports it)
vi.mock('$lib/stores/videoSession.svelte', () => ({
session: {
duration: 120,
currentTime: 0,
fps: 30,
isPlaying: false,
keyframePositions: [],
},
}));
// Mock Tauri window API for fullscreen
const mockTauriWindow = {
isFullscreen: vi.fn().mockResolvedValue(false),
setFullscreen: vi.fn().mockResolvedValue(undefined),
};
vi.mock('@tauri-apps/api/window', () => ({
getCurrentWindow: () => mockTauriWindow,
}));
import {
setVideoElement,
togglePiP,
isPiPActive,
toggleFullscreen,
isFullscreenActive,
setPlaybackRate,
getPlaybackRate,
adjustShuttle,
} from '$lib/transport/playback';
function createMockVideoElement(): HTMLVideoElement {
const el = document.createElement('video');
// PiP
(el as any).requestPictureInPicture = vi.fn().mockResolvedValue({});
// Fullscreen
el.requestFullscreen = vi.fn().mockResolvedValue(undefined);
return el;
}
describe('playback — PiP helpers', () => {
let mockVideo: HTMLVideoElement;
beforeEach(() => {
mockVideo = createMockVideoElement();
setVideoElement(mockVideo);
// Reset PiP state
Object.defineProperty(document, 'pictureInPictureElement', {
value: null,
writable: true,
configurable: true,
});
Object.defineProperty(document, 'pictureInPictureEnabled', {
value: true,
writable: true,
configurable: true,
});
});
it('isPiPActive returns false when no PiP element', () => {
expect(isPiPActive()).toBe(false);
});
it('togglePiP calls requestPictureInPicture', () => {
togglePiP();
expect((mockVideo as any).requestPictureInPicture).toHaveBeenCalled();
});
it('isPiPActive returns true when PiP element exists', () => {
Object.defineProperty(document, 'pictureInPictureElement', {
value: mockVideo,
writable: true,
configurable: true,
});
expect(isPiPActive()).toBe(true);
});
});
describe('playback — fullscreen helpers', () => {
beforeEach(() => {
mockTauriWindow.isFullscreen.mockResolvedValue(false);
mockTauriWindow.setFullscreen.mockResolvedValue(undefined);
});
it('isFullscreenActive returns false when not fullscreen', async () => {
expect(await isFullscreenActive()).toBe(false);
});
it('toggleFullscreen calls setFullscreen(true) when not fullscreen', async () => {
mockTauriWindow.isFullscreen.mockResolvedValue(false);
await toggleFullscreen();
expect(mockTauriWindow.setFullscreen).toHaveBeenCalledWith(true);
});
it('toggleFullscreen calls setFullscreen(false) when fullscreen', async () => {
mockTauriWindow.isFullscreen.mockResolvedValue(true);
await toggleFullscreen();
expect(mockTauriWindow.setFullscreen).toHaveBeenCalledWith(false);
});
it('isFullscreenActive returns true when fullscreen', async () => {
mockTauriWindow.isFullscreen.mockResolvedValue(true);
expect(await isFullscreenActive()).toBe(true);
});
});
describe('playback — playback rate helpers', () => {
let mockVideo: HTMLVideoElement;
beforeEach(() => {
mockVideo = createMockVideoElement();
setVideoElement(mockVideo);
});
it('getPlaybackRate returns 1 by default', () => {
expect(getPlaybackRate()).toBe(1);
});
it('setPlaybackRate changes the video playback rate', () => {
setPlaybackRate(1.5);
expect(mockVideo.playbackRate).toBe(1.5);
});
it('getPlaybackRate returns the current rate', () => {
setPlaybackRate(2);
expect(getPlaybackRate()).toBe(2);
});
it('getPlaybackRate returns 1 when no video element', () => {
setVideoElement(null);
expect(getPlaybackRate()).toBe(1);
});
});
describe('playback — adjustShuttle', () => {
let mockVideo: HTMLVideoElement;
beforeEach(() => {
mockVideo = createMockVideoElement();
setVideoElement(mockVideo);
mockVideo.playbackRate = 1;
Object.defineProperty(mockVideo, 'paused', {
value: true,
writable: true,
configurable: true,
});
mockVideo.play = vi.fn().mockResolvedValue(undefined);
});
it('increases rate by 0.25 when dir is 1', () => {
const result = adjustShuttle(1);
expect(result).toBe(1.25);
expect(mockVideo.playbackRate).toBe(1.25);
});
it('decreases rate by 0.25 when dir is -1', () => {
const result = adjustShuttle(-1);
expect(result).toBe(0.75);
expect(mockVideo.playbackRate).toBe(0.75);
});
it('reads current rate from video element, not external state', () => {
mockVideo.playbackRate = 0.75;
const result = adjustShuttle(1);
expect(result).toBe(1);
});
it('clamps to minimum 0.25', () => {
mockVideo.playbackRate = 0.25;
const result = adjustShuttle(-1);
expect(result).toBe(0.25);
});
it('clamps to maximum 4', () => {
mockVideo.playbackRate = 4;
const result = adjustShuttle(1);
expect(result).toBe(4);
});
it('starts playback if paused', () => {
adjustShuttle(1);
expect(mockVideo.play).toHaveBeenCalled();
});
it('returns 1 when no video element', () => {
setVideoElement(null);
expect(adjustShuttle(1)).toBe(1);
});
});