import { describe, expect, test } from "bun:test"; import { createGeneration } from "./v3-generation.js"; import { eventViewActivatedSchema as legacyEventViewActivatedSchema } from "./view-host-lifecycle-events.js"; import { buildEventViewActivated, buildEventViewActivationDecided, buildEventViewAllocationFailed, buildEventViewClosed, buildEventViewCloseFailed, buildEventViewPrerendered, eventViewActivatedSchema, eventViewActivationDecidedSchema, eventViewAllocationFailedSchema, eventViewClosedSchema, eventViewCloseFailedSchema, eventViewPrerenderedSchema, } from "./view-host-lifecycle-events-v3.js"; describe("view host lifecycle events", () => { test("keeps the published lifecycle event union unchanged", () => { expect( legacyEventViewActivatedSchema.safeParse({ t: "getuserfeedback:event:viewActivationDecided", gen: createGeneration(2), viewId: "view-a", activationAttemptId: "activation-a", allowed: true, }).success, ).toBe(false); }); test("builds a correlated activation decision", () => { const event = buildEventViewActivationDecided({ gen: 2, viewId: "view-a", activationAttemptId: "activation-a", allowed: false, }); expect(eventViewActivationDecidedSchema.parse(event)).toEqual({ t: "getuserfeedback:event:viewActivationDecided", gen: createGeneration(2), viewId: "view-a", activationAttemptId: "activation-a", allowed: false, }); }); test("builds the activated event accepted by core", () => { const event = buildEventViewActivated({ gen: 2, viewId: "view-a", }); expect(eventViewActivatedSchema.parse(event)).toEqual({ t: "getuserfeedback:event:viewActivated", gen: createGeneration(2), viewId: "view-a", }); }); test("builds the prerendered event accepted by core", () => { const event = buildEventViewPrerendered({ gen: 2, viewId: "view-a", }); expect(eventViewPrerenderedSchema.parse(event)).toEqual({ t: "getuserfeedback:event:viewPrerendered", gen: createGeneration(2), viewId: "view-a", }); }); test("builds closed events with and without optional metadata", () => { expect( eventViewClosedSchema.parse( buildEventViewClosed({ gen: createGeneration(3), viewId: "view-a", }), ), ).toEqual({ t: "getuserfeedback:event:viewClosed", gen: createGeneration(3), viewId: "view-a", reason: undefined, }); expect( eventViewClosedSchema.parse( buildEventViewClosed({ gen: 3, viewId: "view-a", reason: "user", lifetimeMs: 250, }), ), ).toMatchObject({ reason: "user", lifetimeMs: 250, }); }); test("keeps lifecycle event validation strict", () => { const gen = createGeneration(0); expect( eventViewPrerenderedSchema.safeParse({ t: "getuserfeedback:event:viewPrerendered", gen, viewId: " ", }).success, ).toBe(false); expect( eventViewActivatedSchema.safeParse({ t: "getuserfeedback:event:viewActivated", gen, viewId: "view-a", extra: true, }).success, ).toBe(false); expect( eventViewClosedSchema.safeParse({ t: "getuserfeedback:event:viewClosed", gen, viewId: "view-a", reason: "dismissed", }).success, ).toBe(false); expect( eventViewClosedSchema.safeParse({ t: "getuserfeedback:event:viewClosed", gen, viewId: "view-a", lifetimeMs: -1, }).success, ).toBe(false); expect( eventViewPrerenderedSchema.safeParse({ t: "getuserfeedback:event:viewPrerendered", gen, viewId: "view-a", extra: true, }).success, ).toBe(false); }); test("builds and validates allocation failures", () => { const event = buildEventViewAllocationFailed({ gen: 4, viewId: "view-a", flowRunId: "run-a", }); expect(eventViewAllocationFailedSchema.parse(event)).toEqual(event); }); test("builds and validates retry-correlated close failures", () => { const event = buildEventViewCloseFailed({ gen: 4, viewId: "view-a", closeAttemptId: "attempt-a", reason: "close-failed", message: "host close rejected", }); expect(eventViewCloseFailedSchema.parse(event)).toEqual(event); expect( eventViewCloseFailedSchema.safeParse({ ...event, reason: "already-absent", }).success, ).toBe(false); }); });