import { describe, expect, test } from "bun:test"; import { INSTANT_WIDGET_LAYOUT_SIZE_TRANSITION, isWidgetLayoutCubicBezier, toInstantWidgetLayoutSizeUpdate, toTimedWidgetLayoutSizeTransition, toTimedWidgetLayoutSizeUpdate, } from "./widget-layout-size-update.js"; describe("widget layout size update", () => { test("wraps a host size in the current instant transition contract", () => { expect( toInstantWidgetLayoutSizeUpdate({ width: 320, height: 240 }), ).toEqual({ size: { width: 320, height: 240 }, transition: { kind: "instant", durationMs: 0, }, }); }); test("shares the zero-duration transition constant", () => { expect( toInstantWidgetLayoutSizeUpdate({ width: 1, height: 1 }).transition, ).toBe(INSTANT_WIDGET_LAYOUT_SIZE_TRANSITION); }); test("keeps the existing size update contract instant-only", () => { const update = toInstantWidgetLayoutSizeUpdate({ width: 320, height: 240 }); expect(update.transition.kind).toBe("instant"); }); test("wraps a host size in the timed transition contract", () => { expect( toTimedWidgetLayoutSizeUpdate({ size: { width: 320, height: 240 }, durationMs: 180, easing: [0.2, 0, 0, 1], }), ).toEqual({ size: { width: 320, height: 240 }, transition: { kind: "timed", durationMs: 180, easing: { kind: "cubic-bezier", points: [0.2, 0, 0, 1], }, }, }); }); test("accepts cubic-bezier y control point overshoot", () => { expect(isWidgetLayoutCubicBezier([0.34, -0.2, 0.64, 1.35])).toBe(true); expect( toTimedWidgetLayoutSizeTransition({ durationMs: 220, easing: [0.34, -0.2, 0.64, 1.35], }).easing.points, ).toEqual([0.34, -0.2, 0.64, 1.35]); }); test("fails closed for non-array cubic-bezier input", () => { expect(isWidgetLayoutCubicBezier(null)).toBe(false); expect(isWidgetLayoutCubicBezier({ 0: 0.2, 1: 0, 2: 0, 3: 1 })).toBe(false); expect(isWidgetLayoutCubicBezier("0.2,0,0,1")).toBe(false); }); test("rejects cubic-bezier x control points outside normalized time", () => { expect(isWidgetLayoutCubicBezier([-0.01, 0, 0.5, 1])).toBe(false); expect(isWidgetLayoutCubicBezier([0.5, 0, 1.01, 1])).toBe(false); expect(() => toTimedWidgetLayoutSizeTransition({ durationMs: 220, easing: [-0.01, 0, 0.5, 1], }), ).toThrow(RangeError); }); test("rejects invalid timed transition duration", () => { expect(() => toTimedWidgetLayoutSizeTransition({ durationMs: 0, easing: [0.2, 0, 0, 1], }), ).toThrow(RangeError); }); });