200 lines · 7.1 KB · TypeScript
RawDownload
import { assert, describe, it } from "@effect/vitest";import * as Cause from "effect/Cause";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import { beforeEach, vi } from "vite-plus/test"; const { createClerkBridgeMock, storageAdapter, storageMock } = vi.hoisted(() => ({  createClerkBridgeMock: vi.fn(),  storageAdapter: {    getItem: vi.fn(),    setItem: vi.fn(),    removeItem: vi.fn(),  },  storageMock: vi.fn(),})); vi.mock("@clerk/electron", () => ({  createClerkBridge: createClerkBridgeMock,})); vi.mock("@clerk/electron/storage", () => ({  storage: storageMock,})); import * as Exit from "effect/Exit";import * as FileSystem from "effect/FileSystem";import * as ElectronApp from "../electron/ElectronApp.ts";import * as ElectronWindow from "../electron/ElectronWindow.ts";import * as DesktopClerk from "./DesktopClerk.ts";import * as DesktopEnvironment from "./DesktopEnvironment.ts"; const makeDesktopClerkLayer = (isDevelopment = true, events: string[] = []) => {  const environment = DesktopEnvironment.DesktopEnvironment.of({    stateDir: "/tmp/t3-state",    isDevelopment,    appDataDirectory: "/tmp/app-data",    userDataDirName: isDevelopment ? "t3code-dev" : "t3code",    legacyUserDataDirName: isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)",    path: { join: (...parts: ReadonlyArray<string>) => parts.join("/") },  } as unknown as DesktopEnvironment.DesktopEnvironment["Service"]);   const electronApp = {    setPath: (name: string, value: string) =>      Effect.sync(() => {        events.push(`setPath:${name}:${value}`);      }),  } as unknown as ElectronApp.ElectronApp["Service"];   return DesktopClerk.layer.pipe(    Layer.provide(      Layer.mergeAll(        Layer.succeed(DesktopEnvironment.DesktopEnvironment, environment),        Layer.succeed(ElectronApp.ElectronApp, electronApp),        FileSystem.layerNoop({ exists: () => Effect.succeed(false) }),      ),    ),  );}; describe("DesktopClerk", () => {  beforeEach(() => {    createClerkBridgeMock.mockReset();    storageMock.mockReset();  });   it.effect("acquires and releases the SDK bridge with the layer", () => {    const cleanup = vi.fn();    const events: string[] = [];    storageMock.mockReturnValue(storageAdapter);    createClerkBridgeMock.mockImplementation(() => {      events.push("createClerkBridge");      return { cleanup, isPrimaryInstance: true };    });     return Effect.gen(function* () {      yield* Effect.scoped(Layer.build(makeDesktopClerkLayer(true, events)));       assert.deepEqual(createClerkBridgeMock.mock.calls, [        [          {            storage: storageAdapter,            passkeys: true,            renderer: { scheme: "t3code-dev", host: "app" },          },        ],      ]);      assert.equal(cleanup.mock.calls.length, 1);      // The bridge acquires Electron's single-instance lock at creation, and      // the lock both lives in and creates the userData directory — so the      // real path must be set before the bridge exists.      assert.deepEqual(events, ["setPath:userData:/tmp/app-data/t3code-dev", "createClerkBridge"]);      storageMock.mockClear();      createClerkBridgeMock.mockClear();    });  });   it.effect("preserves bridge initialization failures", () => {    const cause = new Error("bridge initialization failed");    storageMock.mockReturnValue(storageAdapter);    createClerkBridgeMock.mockImplementationOnce(() => {      throw cause;    });     return Effect.gen(function* () {      const error = yield* Effect.scoped(Layer.build(makeDesktopClerkLayer())).pipe(Effect.flip);       assert.instanceOf(error, DesktopClerk.DesktopClerkBridgeInitializationError);      assert.equal(error.stateDir, "/tmp/t3-state");      assert.equal(error.isDevelopment, true);      assert.strictEqual(error.cause, cause);      assert.equal(        error.message,        'Failed to initialize the desktop Clerk bridge for state directory "/tmp/t3-state" (development: true).',      );    });  });   it.effect("preserves bridge cleanup failures", () => {    const cause = new Error("bridge cleanup failed");    storageMock.mockReturnValue(storageAdapter);    createClerkBridgeMock.mockReturnValue({      cleanup: () => {        throw cause;      },    });     return Effect.gen(function* () {      const exit = yield* Effect.exit(Effect.scoped(Layer.build(makeDesktopClerkLayer(false))));       assert.equal(exit._tag, "Failure");      if (exit._tag === "Failure") {        const error = Cause.squash(exit.cause);        assert.instanceOf(error, DesktopClerk.DesktopClerkBridgeCleanupError);        assert.equal(error.stateDir, "/tmp/t3-state");        assert.equal(error.isDevelopment, false);        assert.strictEqual(error.cause, cause);        assert.equal(          error.message,          'Failed to clean up the desktop Clerk bridge for state directory "/tmp/t3-state" (development: false).',        );      }    });  });   it.effect("registers the second-instance handler in the primary instance", () => {    storageMock.mockReturnValue(storageAdapter);    createClerkBridgeMock.mockReturnValue({ cleanup: vi.fn(), isPrimaryInstance: true });    const quit = vi.fn();    const registeredEvents: string[] = [];    const electronApp = {      quit: Effect.sync(quit),      on: (eventName: string) =>        Effect.sync(() => {          registeredEvents.push(eventName);        }),    } as unknown as ElectronApp.ElectronApp["Service"];    const electronWindow = {} as ElectronWindow.ElectronWindow["Service"];     return Effect.gen(function* () {      const clerk = yield* DesktopClerk.DesktopClerk;      const exit = yield* Effect.exit(Effect.scoped(clerk.configure));       assert.isTrue(Exit.isSuccess(exit));      assert.equal(quit.mock.calls.length, 0);      assert.deepEqual(registeredEvents, ["second-instance"]);    }).pipe(      Effect.provide(makeDesktopClerkLayer()),      Effect.provideService(ElectronApp.ElectronApp, electronApp),      Effect.provideService(ElectronWindow.ElectronWindow, electronWindow),    );  });   it.effect("quits and interrupts startup in a secondary instance", () => {    storageMock.mockReturnValue(storageAdapter);    createClerkBridgeMock.mockReturnValue({ cleanup: vi.fn(), isPrimaryInstance: false });    const quit = vi.fn();    const registeredEvents: string[] = [];    const electronApp = {      quit: Effect.sync(quit),      on: (eventName: string) =>        Effect.sync(() => {          registeredEvents.push(eventName);        }),    } as unknown as ElectronApp.ElectronApp["Service"];    const electronWindow = {} as ElectronWindow.ElectronWindow["Service"];     return Effect.gen(function* () {      const clerk = yield* DesktopClerk.DesktopClerk;      const exit = yield* Effect.exit(Effect.scoped(clerk.configure));       assert.isTrue(Exit.hasInterrupts(exit));      assert.equal(quit.mock.calls.length, 1);      assert.deepEqual(registeredEvents, []);    }).pipe(      Effect.provide(makeDesktopClerkLayer()),      Effect.provideService(ElectronApp.ElectronApp, electronApp),      Effect.provideService(ElectronWindow.ElectronWindow, electronWindow),    );  });});