import { chapterAnchors, chapterFraction, chapterIndexAt, desktopFractionAt, getProjectVideo, getShowcaseAssets, mobileFractionAt, SHOWCASE, type ShowcaseConfig, } from "./project-showcase"; /** * Testes de caminhos-base de lib/project-showcase.ts (complemento de project-showcase.test.ts): * getProjectVideo (id da vitrine x id fora dela x chaves herdadas de Object, nos dois aparelhos) e os trechos * de chapterAnchors/interpolate/chapterFraction que o arquivo principal não exercita. */ function config( chapters: ShowcaseConfig["chapters"], durations = { desktop: 10, mobile: 20 }, ): ShowcaseConfig { return { id: "fixture", accent: "#fff", durations, weight: 1, chapters }; } describe("getProjectVideo", () => { it.each(SHOWCASE.map(({ id }) => id))( "path: showcase project %s -> assets for the requested device", (id) => { expect(getProjectVideo(id, "desktop")).toEqual( getShowcaseAssets(id, "desktop"), ); expect(getProjectVideo(id, "mobile")).toEqual( getShowcaseAssets(id, "mobile"), ); expect(getProjectVideo(id)).toEqual(getShowcaseAssets(id, "desktop")); }, ); it.each([ "", "nao-existe", "constructor", "__proto__", "toString", "SEV-MODAINTIMA", ])( "path: id %j is not a showcase project -> undefined for both devices", (id) => { expect(getProjectVideo(id)).toBeUndefined(); expect(getProjectVideo(id, "mobile")).toBeUndefined(); }, ); it("path: the two devices differ in size and in poster, not in the project folder", () => { const desktop = getProjectVideo("nutriscan", "desktop"); const mobile = getProjectVideo("nutriscan", "mobile"); expect(desktop).toMatchObject({ width: 1440, height: 900 }); expect(mobile).toMatchObject({ width: 390, height: 844 }); expect(desktop?.poster).toBe("/videos/nutriscan/desktop.webp"); expect(mobile?.poster).toBe("/videos/nutriscan/mobile.webp"); }); }); describe("chapterAnchors", () => { it("path: chapters that advance on both videos -> one anchor each between [0,0] and [1,1]", () => { const anchors = chapterAnchors( config([ { label: "A", desktop: 2, mobile: 4 }, { label: "B", desktop: 5, mobile: 10 }, ]), ); expect(anchors).toEqual([ [0, 0], [0.2, 0.2], [0.5, 0.5], [1, 1], ]); }); it("path: a chapter at second 0 on both videos -> no duplicate of the origin", () => { const anchors = chapterAnchors( config([ { label: "Abertura", desktop: 0, mobile: 0 }, { label: "B", desktop: 5, mobile: 10 }, ]), ); expect(anchors).toEqual([ [0, 0], [0.5, 0.5], [1, 1], ]); }); it("path: a chapter that does not advance on the desktop video -> skipped", () => { const anchors = chapterAnchors( config([ { label: "A", desktop: 4, mobile: 4 }, { label: "B", desktop: 4, mobile: 12 }, ]), ); expect(anchors).toEqual([ [0, 0], [0.4, 0.2], [1, 1], ]); }); it("path: a chapter that does not advance on the mobile video -> skipped", () => { const anchors = chapterAnchors( config([ { label: "A", desktop: 4, mobile: 10 }, { label: "B", desktop: 8, mobile: 10 }, ]), ); expect(anchors).toEqual([ [0, 0], [0.4, 0.5], [1, 1], ]); }); }); describe("mobileFractionAt / desktopFractionAt (interpolation)", () => { const sample = config([ { label: "A", desktop: 2, mobile: 10 }, { label: "B", desktop: 8, mobile: 15 }, ]); it.each([ [-1, 0], [0, 0], [0.2, 0.5], [0.5, 0.5 + (0.3 / 0.6) * 0.25], [0.8, 0.75], [1, 1], [2, 1], ])( "path: desktop fraction %f -> mobile fraction %f", (fraction, expected) => { expect(mobileFractionAt(sample, fraction)).toBeCloseTo(expected, 9); }, ); it("path: desktopFractionAt is the inverse on the anchors", () => { expect(desktopFractionAt(sample, 0.5)).toBeCloseTo(0.2, 9); expect(desktopFractionAt(sample, 0.75)).toBeCloseTo(0.8, 9); expect(desktopFractionAt(sample, 0)).toBe(0); expect(desktopFractionAt(sample, 1)).toBe(1); }); it("path: a chapter right at the end makes a zero-length span -> no division by zero", () => { const flat = config([{ label: "Fim", desktop: 10, mobile: 20 }]); expect(mobileFractionAt(flat, 1)).toBe(1); expect(Number.isFinite(mobileFractionAt(flat, 0.999))).toBe(true); expect(Number.isFinite(desktopFractionAt(flat, 1))).toBe(true); }); }); describe("chapterIndexAt / chapterFraction", () => { const sample = config([ { label: "A", desktop: 0, mobile: 0 }, { label: "B", desktop: 4, mobile: 8 }, { label: "C", desktop: 8, mobile: 16 }, ]); it.each([ [-5, 0], [0, 0], [0.399, 0], [0.4, 1], [0.7999, 1], [0.8, 2], [1, 2], [9, 2], ])("path: fraction %f -> chapter %i", (fraction, expected) => { expect(chapterIndexAt(sample, fraction)).toBe(expected); }); it("path: chapter index in range -> start fraction on each video", () => { expect(chapterFraction(sample, 1, "desktop")).toBeCloseTo(0.4, 9); expect(chapterFraction(sample, 1, "mobile")).toBeCloseTo(0.4, 9); expect(chapterFraction(sample, 2, "desktop")).toBeCloseTo(0.8, 9); }); it.each([-1, 3, 99])( "path: chapter index %i does not exist -> 0", (index) => { expect(chapterFraction(sample, index, "desktop")).toBe(0); expect(chapterFraction(sample, index, "mobile")).toBe(0); }, ); });