Initial
This commit is contained in:
commit
b43955e0d9
162 changed files with 15425 additions and 0 deletions
81
tests/unit/timeline.test.ts
Normal file
81
tests/unit/timeline.test.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue