Files
heygen-com--hyperframes/packages/studio/src/utils/globalTimeCompiler.test.ts
T
wehub-resource-sync 85453da49f
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docs / Validate docs (push) Has been cancelled
Sync skills to ClawHub / Publish changed skills (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:58:35 +08:00

170 lines
4.8 KiB
TypeScript

import { describe, expect, test } from "vitest";
import {
absoluteToPercentage,
absoluteToPercentageForAnimation,
findTweenAtTime,
isTimeWithinTween,
percentageToAbsolute,
percentageToAbsoluteForAnimation,
resolveTweenDuration,
resolveTweenStart,
} from "./globalTimeCompiler";
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
function makeAnim(overrides: Partial<GsapAnimation> = {}): GsapAnimation {
return {
id: "#el-to-0",
targetSelector: "#el",
method: "to",
position: 0,
properties: { x: 100 },
...overrides,
};
}
describe("absoluteToPercentage", () => {
test("mid-point of a tween", () => {
expect(absoluteToPercentage(0.5, 0, 2)).toBe(25);
});
test("tween with offset start", () => {
expect(absoluteToPercentage(1.0, 0.5, 1)).toBe(50);
});
test("clamps below tween start to 0%", () => {
expect(absoluteToPercentage(-1, 0, 2)).toBe(0);
});
test("clamps past tween end to 100%", () => {
expect(absoluteToPercentage(5, 0, 2)).toBe(100);
});
test("zero duration returns 0", () => {
expect(absoluteToPercentage(1, 0, 0)).toBe(0);
});
});
describe("percentageToAbsolute", () => {
test("converts percentage back to absolute time", () => {
expect(percentageToAbsolute(50, 0.5, 1)).toBe(1.0);
});
test("0% returns tween start", () => {
expect(percentageToAbsolute(0, 2, 3)).toBe(2);
});
test("100% returns tween end", () => {
expect(percentageToAbsolute(100, 2, 3)).toBe(5);
});
});
describe("isTimeWithinTween", () => {
test("time inside returns true", () => {
expect(isTimeWithinTween(0.5, 0, 2)).toBe(true);
});
test("time at start returns true", () => {
expect(isTimeWithinTween(0, 0, 2)).toBe(true);
});
test("time at end returns true", () => {
expect(isTimeWithinTween(2, 0, 2)).toBe(true);
});
test("time before returns false", () => {
expect(isTimeWithinTween(-0.1, 0, 2)).toBe(false);
});
test("time after returns false", () => {
expect(isTimeWithinTween(2.1, 0, 2)).toBe(false);
});
});
describe("resolveTweenStart", () => {
test("numeric position", () => {
expect(resolveTweenStart(makeAnim({ position: 1.5 }))).toBe(1.5);
});
test("parseable string position", () => {
expect(resolveTweenStart(makeAnim({ position: "2.5" }))).toBe(2.5);
});
test("unparseable string position returns null", () => {
expect(resolveTweenStart(makeAnim({ position: "myLabel" }))).toBeNull();
});
test("relative position +=0.5 returns null", () => {
expect(resolveTweenStart(makeAnim({ position: "+=0.5" }))).toBeNull();
});
});
describe("resolveTweenDuration", () => {
test("explicit duration", () => {
expect(resolveTweenDuration(makeAnim({ duration: 2 }))).toBe(2);
});
test("missing duration defaults to GSAP default (0.5)", () => {
expect(resolveTweenDuration(makeAnim({ duration: undefined }))).toBe(0.5);
});
});
describe("findTweenAtTime", () => {
const anims = [
makeAnim({ id: "#el-to-0", position: 0, duration: 0.5 }),
makeAnim({ id: "#el-to-1", position: 1, duration: 1 }),
makeAnim({
id: "#other-to-0",
targetSelector: "#other",
position: 0,
duration: 2,
}),
];
test("finds tween at time within range", () => {
expect(findTweenAtTime(0.3, anims, "#el")?.id).toBe("#el-to-0");
});
test("finds second tween", () => {
expect(findTweenAtTime(1.5, anims, "#el")?.id).toBe("#el-to-1");
});
test("returns null for gap between tweens", () => {
expect(findTweenAtTime(0.7, anims, "#el")).toBeNull();
});
test("filters by selector", () => {
expect(findTweenAtTime(0.3, anims, "#other")?.id).toBe("#other-to-0");
});
test("returns null for unmatched selector", () => {
expect(findTweenAtTime(0.3, anims, "#missing")).toBeNull();
});
test("skips tweens with unresolvable string positions", () => {
const withLabel = [makeAnim({ id: "#el-to-0", position: "myLabel", duration: 1 })];
expect(findTweenAtTime(0.5, withLabel, "#el")).toBeNull();
});
});
describe("animation-level helpers", () => {
const anim = makeAnim({ position: 0.5, duration: 2 });
test("absoluteToPercentageForAnimation", () => {
expect(absoluteToPercentageForAnimation(1.5, anim)).toBe(50);
});
test("absoluteToPercentageForAnimation returns null for string position", () => {
const labelAnim = makeAnim({ position: "label" });
expect(absoluteToPercentageForAnimation(0.5, labelAnim)).toBeNull();
});
test("percentageToAbsoluteForAnimation", () => {
expect(percentageToAbsoluteForAnimation(50, anim)).toBe(1.5);
});
test("percentageToAbsoluteForAnimation returns null for string position", () => {
const labelAnim = makeAnim({ position: "+=1" });
expect(percentageToAbsoluteForAnimation(50, labelAnim)).toBeNull();
});
});