140 lines · 4.0 KB · TypeScript
RawDownload
import { describe, expect, it } from "@effect/vitest";import * as DateTime from "effect/DateTime";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import { HttpClient } from "effect/unstable/http"; import type { RelayAgentActivityAggregateState } from "@t3tools/contracts/relay";import { EnvironmentId, ThreadId } from "@t3tools/contracts";import * as ApnsClient from "./ApnsClient.ts"; const TestLayer = ApnsClient.layer.pipe(  Layer.provide(    Layer.succeed(      HttpClient.HttpClient,      HttpClient.make(() => Effect.die("unexpected APNs HTTP request")),    ),  ),); describe("ApnsClient", () => {  const now = DateTime.makeUnsafe(0);  const state: RelayAgentActivityAggregateState = {    title: "T3 Code",    subtitle: "Agent work in progress",    activeCount: 1,    updatedAt: DateTime.formatIso(now),    activities: [      {        environmentId: EnvironmentId.make("env"),        threadId: ThreadId.make("thread"),        projectTitle: "Project",        threadTitle: "Thread",        modelTitle: "gpt-5.4",        phase: "running" as const,        status: "Working",        updatedAt: DateTime.formatIso(now),        deepLink: "/",      },    ],  };   it.effect("requests an update push token when remotely starting a Live Activity", () =>    Effect.gen(function* () {      const apns = yield* ApnsClient.ApnsClient;      const request = apns.makeLiveActivityRequest({        event: "start",        token: "token",        state,        nowEpochSeconds: Math.floor(now.epochMilliseconds / 1_000),        nowIso: DateTime.formatIso(now),      });       expect(request.priority).toBe("10");      expect(request.payload).toMatchObject({        aps: {          event: "start",          "attributes-type": "LiveActivityAttributes",          "input-push-token": 1,          "content-state": {            name: "AgentActivity",          },        },      });    }).pipe(Effect.provide(TestLayer)),  );   it.effect("builds a low-priority update payload", () =>    Effect.gen(function* () {      const apns = yield* ApnsClient.ApnsClient;      const request = apns.makeLiveActivityRequest({        event: "update",        token: "token",        state,        nowEpochSeconds: Math.floor(now.epochMilliseconds / 1_000),        nowIso: DateTime.formatIso(now),      });       expect(request.priority).toBe("5");      expect(request.payload).toMatchObject({        aps: {          event: "update",          "content-state": {            name: "AgentActivity",          },        },      });    }).pipe(Effect.provide(TestLayer)),  );   it.effect("builds an end payload with a dismissal date", () =>    Effect.gen(function* () {      const apns = yield* ApnsClient.ApnsClient;      const request = apns.makeLiveActivityRequest({        event: "end",        token: "token",        state,        nowEpochSeconds: Math.floor(now.epochMilliseconds / 1_000),        nowIso: DateTime.formatIso(now),      });       expect(request.priority).toBe("10");      expect(request.payload).toMatchObject({        aps: {          event: "end",          "dismissal-date": 300,        },      });    }).pipe(Effect.provide(TestLayer)),  );   it.effect("builds a standard APNs alert payload with routing metadata", () =>    Effect.gen(function* () {      const apns = yield* ApnsClient.ApnsClient;      const request = apns.makePushNotificationRequest({        token: "push-token",        notification: {          title: "Thread",          body: "Input: Project",          environmentId: "env",          threadId: "thread",          deepLink: "/threads/env/thread",        },      });       expect(request.priority).toBe("10");      expect(request.payload).toMatchObject({        aps: {          alert: {            title: "Thread",            body: "Input: Project",          },          sound: "default",        },        environmentId: "env",        threadId: "thread",        deepLink: "/threads/env/thread",      });    }).pipe(Effect.provide(TestLayer)),  );});