import { describe, expect, it } from "vitest"; import { events } from "./events.generated.js"; import { connections, workflow } from "./workflow.js"; const declarations = { calendar: connections.calendar({ targets: { meetings: { description: "Watch upcoming meetings", permissions: "read", multiple: true, }, followUps: { description: "Create follow-ups", permissions: "read_write", multiple: false, }, }, }), }; describe("Calendar trigger targets", () => { it("serializes all Calendar trigger targets from the single declared connection", () => { const definition = workflow({ name: "Watch meetings", description: "Watch the calendars selected for meetings", connections: declarations, triggers: ({ events, connections }) => [ events.calendarEventCreated({ calendars: connections.calendar.targets.meetings }), events.calendarEventUpdated({ calendars: connections.calendar.targets.meetings }), events.calendarEventCanceled({ calendars: connections.calendar.targets.meetings }), ], handler() {}, }); expect(JSON.parse(JSON.stringify(definition.config)).triggers).toEqual([ { type: "calendar.event.created", connectionKey: "calendar", calendarTarget: "meetings", }, { type: "calendar.event.updated", connectionKey: "calendar", calendarTarget: "meetings", }, { type: "calendar.event.canceled", connectionKey: "calendar", calendarTarget: "meetings", }, ]); }); it("can watch the same writable target used for event creation", () => { const definition = workflow({ name: "Watch follow-ups", description: "Read access is included in a writable target", connections: declarations, triggers: ({ events, connections }) => [ events.calendarEventCreated({ calendars: connections.calendar.targets.followUps }), ], handler() {}, }); expect(definition.config.triggers).toEqual([ { type: "calendar.event.created", connectionKey: "calendar", calendarTarget: "followUps", }, ]); }); it.each(["missing", "constructor", "__proto__"])("rejects undeclared target %s", (target) => { expect(() => workflow({ name: "Invalid target", description: "Do not fall back to all calendars", connections: declarations, triggers: [ events.calendarEventCreated({ calendars: { connectionKey: "calendar", target }, }), ], handler() {}, }), ).toThrow("requires a declared Calendar target"); }); it.each([ { type: "calendar.event.created" }, { type: "calendar.event.updated", connectionKey: "calendar" }, { type: "calendar.event.canceled", connectionKey: "calendar", calendarTarget: "" }, { type: "calendar.event.created", calendarTarget: "meetings" }, { type: "calendar.event.created", connectionKey: "calendar", calendarTarget: { accountId: "account", calendarId: "primary" }, }, ])("rejects missing or raw Calendar targets from JavaScript: %j", (trigger) => { expect(() => Reflect.apply(workflow, undefined, [ { name: "Invalid trigger", description: "No separate picker", connections: declarations, triggers: [trigger], handler() {}, }, ]), ).toThrow("requires a declared Calendar target"); }); it("rejects a Calendar trigger bound to another provider", () => { expect(() => workflow({ name: "Wrong provider", description: "Targets belong to Calendar", connections: { ...declarations, inbox: connections.mail() }, triggers: [ events.calendarEventCreated({ calendars: { connectionKey: "inbox", target: "meetings" }, }), ], handler() {}, }), ).toThrow("requires a declared calendar connection"); }); it("does not allow a second Calendar connection for trigger setup", () => { expect(() => workflow({ name: "Duplicate connection", description: "Connect Calendar once", connections: { ...declarations, another: declarations.calendar }, triggers: ({ events, connections }) => [ events.calendarEventCreated({ calendars: connections.calendar.targets.meetings, }), ], handler() {}, }), ).toThrow("Declare one Calendar connection"); }); it("keeps one declaration per event type and connection even with different targets", () => { expect(() => workflow({ name: "Duplicate event", description: "Use one multi-calendar target", connections: declarations, triggers: ({ events, connections }) => [ events.calendarEventCreated({ calendars: connections.calendar.targets.meetings, }), events.calendarEventCreated({ calendars: connections.calendar.targets.followUps, }), ], handler() {}, }), ).toThrow("Duplicate connection trigger"); }); });