This commit is contained in:
gili8420 2026-08-14 00:01:49 +09:00
commit b43955e0d9
162 changed files with 15425 additions and 0 deletions

View file

@ -0,0 +1,81 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { get } from 'svelte/store';
// Import the store module directly: the feature barrel re-exports .svelte
// components, which the unit runner (no Svelte plugin) cannot transform.
import { timelineStore, positionAt } from '$features/timeline/store';
beforeEach(() => {
timelineStore.pause();
timelineStore.setRange(0, 0);
timelineStore.setSpeed(1);
timelineStore.setMarkers([]);
});
describe('timelineStore', () => {
it('clamps seek to the current range', () => {
timelineStore.setRange(0, 10_000);
timelineStore.seek(99_999);
expect(get(timelineStore).time).toBe(10_000);
timelineStore.seek(-5);
expect(get(timelineStore).time).toBe(0);
});
it('clamps the current time when the range shrinks', () => {
timelineStore.setRange(0, 10_000);
timelineStore.seek(9_000);
timelineStore.setRange(0, 4_000);
expect(get(timelineStore).time).toBe(4_000);
});
it('ignores play when there is no duration', () => {
timelineStore.play();
expect(get(timelineStore).playing).toBe(false);
});
it('plays and pauses when a duration exists', () => {
timelineStore.setRange(0, 10_000);
timelineStore.play();
expect(get(timelineStore).playing).toBe(true);
timelineStore.pause();
expect(get(timelineStore).playing).toBe(false);
});
it('rewinds to min on reset', () => {
timelineStore.setRange(0, 10_000);
timelineStore.seek(7_000);
timelineStore.reset();
expect(get(timelineStore).time).toBe(0);
expect(get(timelineStore).playing).toBe(false);
});
it('stores the playback speed', () => {
timelineStore.setSpeed(5);
expect(get(timelineStore).speed).toBe(5);
});
});
describe('positionAt', () => {
const path: [number, number, ...number[]][] = [
[60, 100],
[62, 102],
[64, 104]
];
it('returns the first point at t=0 and the last at t=duration', () => {
expect(positionAt(path, 0, 1000)).toEqual([60, 100]);
expect(positionAt(path, 1000, 1000)).toEqual([64, 104]);
});
it('interpolates linearly between samples', () => {
// Quarter of the way = halfway along the first segment.
const p = positionAt(path, 250, 1000)!;
expect(p[0]).toBeCloseTo(61, 6);
expect(p[1]).toBeCloseTo(101, 6);
});
it('clamps outside the flight window and handles an empty path', () => {
expect(positionAt(path, -100, 1000)).toEqual([60, 100]);
expect(positionAt(path, 99_999, 1000)).toEqual([64, 104]);
expect(positionAt([], 0, 1000)).toBeNull();
});
});