1import { assert, describe, it } from "vite-plus/test";
2
3import { verifyPreloadBundle } from "./verify-preload-bundle.mjs";
4
5const validPreload = `
6 const electron = require("electron");
7 const PICK_FOLDER_CHANNEL = "desktop:pick-folder";
8 electron.contextBridge.exposeInMainWorld("__clerk_internal_electron_passkeys", {});
9 electron.contextBridge.exposeInMainWorld("desktopBridge", {
10 getClientPlatform: () => process.platform,
11 getLocalEnvironmentBootstraps: () => [],
12 getPathForFile: () => "",
13 pickFolder: (options) => electron.ipcRenderer.invoke(PICK_FOLDER_CHANNEL, options),
14 });
15`;
16
17describe("desktop preload bundle verifier", () => {
18 it("rejects required API names that only appear in strings", () => {
19 assert.throws(
20 () =>
21 verifyPreloadBundle(`
22 "desktopBridge getClientPlatform getLocalEnvironmentBootstraps pickFolder";
23 "__clerk_internal_electron_passkeys";
24 require("electron");
25 `),
26 /missing executable APIs/,
27 );
28 });
29
30 it("rejects a required API whose exposed value is not callable", () => {
31 assert.throws(
32 () =>
33 verifyPreloadBundle(
34 validPreload.replace(
35 "getClientPlatform: () => process.platform,",
36 "getClientPlatform: undefined,",
37 ),
38 ),
39 /missing executable APIs: getClientPlatform/,
40 );
41 });
42
43 it("accepts a required API exposed through a function alias", () => {
44 assert.doesNotThrow(() =>
45 verifyPreloadBundle(`
46 const readClientPlatform = () => process.platform;
47 ${validPreload.replace(
48 "getClientPlatform: () => process.platform,",
49 "getClientPlatform: readClientPlatform,",
50 )}
51 `),
52 );
53 });
54
55 it("rejects dynamic imports with comments before the opening parenthesis", () => {
56 assert.throws(
57 () =>
58 verifyPreloadBundle(`${validPreload}\nimport /* @vite-ignore */("unsupported-module");`),
59 /dynamic import\(\)/,
60 );
61 });
62
63 it("ignores import-like text in strings", () => {
64 assert.doesNotThrow(() =>
65 verifyPreloadBundle(`${validPreload}\nconst message = 'import /* comment */("module")';`),
66 );
67 });
68
69 it("rejects unsupported require calls with comments before the opening parenthesis", () => {
70 assert.throws(
71 () => verifyPreloadBundle(`${validPreload}\nrequire /* @__PURE__ */ ("node:fs");`),
72 /unsupported sandbox imports: node:fs/,
73 );
74 });
75
76 it("rejects unsupported optional require calls", () => {
77 assert.throws(
78 () => verifyPreloadBundle(`${validPreload}\nrequire?.("node:fs");`),
79 /unsupported sandbox imports: node:fs/,
80 );
81 });
82
83 it("accepts Electron sandbox module aliases", () => {
84 assert.doesNotThrow(() =>
85 verifyPreloadBundle(`
86 ${validPreload}
87 require("electron/common");
88 require("electron/renderer");
89 require("node:events");
90 require("node:timers");
91 require("node:url");
92 `),
93 );
94 });
95
96 it("ignores require-like text in strings and comments", () => {
97 assert.doesNotThrow(() =>
98 verifyPreloadBundle(`
99 ${validPreload}
100 const message = 'require("node:fs")';
101 // require("node:path")
102 `),
103 );
104 });
105});