Open History to see the last commit
1// @effect-diagnostics nodeBuiltinImport:off - Stands in for an Electron webContents.
2import { assert, describe, it } from "@effect/vitest";
3import * as NodeEvents from "node:events";
4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";
6
7import * as DesktopWindow from "../window/DesktopWindow.ts";
8import * as ElectronWindow from "../electron/ElectronWindow.ts";
9import { WEB_LINK_OPEN_CHANNEL } from "../ipc/channels.ts";
10import * as DesktopWebLinks from "./DesktopWebLinks.ts";
11
12const makeWindow = () => {
13 const sent: Array<string> = [];
14 const revealed: Array<unknown> = [];
15 const webContents = Object.assign(new NodeEvents.EventEmitter(), {
16 isDestroyed: () => false,
17 send: (channel: string, url: string) => {
18 if (channel === WEB_LINK_OPEN_CHANNEL) sent.push(url);
19 },
20 });
21 const window = { webContents } as unknown as Electron.BrowserWindow;
22 const reload = () =>
23 webContents.emit("did-start-navigation", { isMainFrame: true, isSameDocument: false });
24 const layer = DesktopWebLinks.layer.pipe(
25 Layer.provide(
26 Layer.succeed(DesktopWindow.DesktopWindow, {
27 activate: Effect.sync(() => void revealed.push(window)),
28 } as unknown as DesktopWindow.DesktopWindow["Service"]),
29 ),
30 Layer.provide(
31 Layer.succeed(
32 ElectronWindow.ElectronWindow,
33 ElectronWindow.ElectronWindow.of({
34 currentMainOrFirst: Effect.succeedSome(window),
35 reveal: (target: Electron.BrowserWindow) => Effect.sync(() => void revealed.push(target)),
36 } as unknown as ElectronWindow.ElectronWindow["Service"]),
37 ),
38 ),
39 );
40 return { sent, revealed, layer, reload };
41};
42
43describe("DesktopWebLinks", () => {
44 it.effect("holds links until the renderer listens, then delivers them in order", () => {
45 const { sent, revealed, layer } = makeWindow();
46 return Effect.gen(function* () {
47 const webLinks = yield* DesktopWebLinks.DesktopWebLinks;
48 yield* webLinks.receive("https://example.com/first");
49 yield* webLinks.receive("https://example.com/second");
50 assert.deepStrictEqual(sent, []);
51
52 yield* webLinks.setRendererReady(true);
53 assert.deepStrictEqual(sent, ["https://example.com/first", "https://example.com/second"]);
54 assert.strictEqual(revealed.length, 1);
55
56 yield* webLinks.receive("https://example.com/third");
57 assert.deepStrictEqual(sent.at(-1), "https://example.com/third");
58
59 yield* webLinks.setRendererReady(false);
60 yield* webLinks.receive("https://example.com/fourth");
61 assert.strictEqual(sent.length, 3);
62 }).pipe(Effect.provide(layer));
63 });
64
65 it.effect("holds links that arrive while the web app reloads until it listens again", () => {
66 const { sent, layer, reload } = makeWindow();
67 return Effect.gen(function* () {
68 const webLinks = yield* DesktopWebLinks.DesktopWebLinks;
69 yield* webLinks.setRendererReady(true);
70 reload();
71 yield* webLinks.receive("https://example.com/during-reload");
72 assert.deepStrictEqual(sent, []);
73
74 yield* webLinks.setRendererReady(true);
75 assert.deepStrictEqual(sent, ["https://example.com/during-reload"]);
76 }).pipe(Effect.provide(layer));
77 });
78});