import { describe, expect, it } from 'vitest';
import { sampleMotion } from '../motion';
describe('sampleMotion', () => {
it('bob: синус по Y, округлён до целого px', () => {
const p = { bob: { amplitude: 2, period: 1 } };
expect(sampleMotion(p, 0).y).toBe(0); // 0
expect(sampleMotion(p, 0.25).y).toBe(2); // пик
expect(sampleMotion(p, 0.75).y).toBe(-2); // низ
// Между узлами — целые: субпиксельного дрожания нет
const mid = sampleMotion(p, 0.05).y;
expect(Number.isInteger(mid)).toBe(true);
});
it('sway: угол в рад, амплитуда соблюдена', () => {
const p = { sway: { amplitude: 0.1, period: 2 } };
expect(sampleMotion(p, 0.5).angle).toBeCloseTo(0.1, 6); // четверть периода = пик
expect(sampleMotion(p, 1.5).angle).toBeCloseTo(-0.1, 6);
expect(sampleMotion(p, 0).angle).toBeCloseTo(0, 6);
});
it('pulse: границы min/max, треугольная волна', () => {
const p = { pulse: { min: 0.4, max: 1, period: 2 } };
expect(sampleMotion(p, 0).alpha).toBeCloseTo(0.4); // старт с минимума
expect(sampleMotion(p, 1).alpha).toBeCloseTo(1); // середина = max
expect(sampleMotion(p, 2).alpha).toBeCloseTo(0.4); // период замкнулся
expect(sampleMotion(p, 1).scale).toBeCloseTo(1);
});
it('blink: строб 0/1 с duty', () => {
const p = { blink: { period: 1, duty: 0.25 } };
expect(sampleMotion(p, 0).alpha).toBe(1);
expect(sampleMotion(p, 0.2).alpha).toBe(1); // внутри duty
expect(sampleMotion(p, 0.5).alpha).toBe(0); // вне duty
expect(sampleMotion(p, 0.95).alpha).toBe(0);
});
it('композиция: bob+sway+pulse+blink независимы', () => {
const p = {
bob: { amplitude: 2, period: 1 },
sway: { amplitude: 0.1, period: 1 },
pulse: { min: 0.5, max: 1, period: 1 },
blink: { period: 1, duty: 1 } // всегда включён
};
const s = sampleMotion(p, 0.25);
expect(s.y).toBe(2);
expect(s.angle).toBeCloseTo(0.1, 6);
expect(s.alpha).toBeCloseTo(0.75, 6); // pulse: tri(0.25)=0.5 → k=0.75, blink=1
});
it('phase сдвигает волну (доля периода)', () => {
const p = { bob: { amplitude: 2, period: 1, phase: 0.25 } };
expect(sampleMotion(p, 0).y).toBe(2); // при t=0 уже пик
});
it('пустые параметры — нейтральная выборка', () => {
const s = sampleMotion({}, 5);
expect(s).toEqual({ y: 0, angle: 0, alpha: 1, scale: 1 });
});
it('волна замкнута на границе периода (без скачка)', () => {
const p = { bob: { amplitude: 3, period: 2 } };
expect(sampleMotion(p, 0).y).toBe(sampleMotion(p, 2).y);
});
});