I have a bit of a dilemma.
I turned on contextIsolation
and turned off nodeIntegration
for my BrowserWindow
and loaded a local html page. (as is recommended by Electron).
This local html page requires a node module, which causes a crash, because Electron can't load a node module in the window since node is disabled:
main.ts:
import { app, BrowserWindow } from "electron";
import * as path from "path";
function createWindow() {
const mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, "preload.js"),
},
});
mainWindow.loadFile(path.join(__dirname, "../index.html"));
mainWindow.webContents.openDevTools();
}
(async () => {
await app.whenReady();
createWindow();
})();
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
index.html:
<body>
<h1>Hello World!</h1>
<script src="./renderer.js"></script>
</body>
renderer.js:
export interface A { }
Uncaught ReferenceError: exports is not defined at renderer.js:2
The specific line that crashes is this:
Object.defineProperty(exports, "__esModule", { value: true });
which exists because of the export
statement.
I can remove the export in this case (and just redefine the interface in the other module that needs it), but then I can't unit test my script.
I'm currently using jasmine-node
for unit testing and I've been requiring the module that I want to test at the top:
import * as Renderer from "./renderer"
This errors out in VSCode with something about how Renderer
isn't a module.
It seems that requiring works (I guess Node can require
non-modules?), but this causes the IIFE to run before my spies are set up.
If Renderer
were a module, I would do:
<script>
require("renderer.js").main();
</script>
And then my unit tests would set up the spies on the module before calling the main method. But since I can't require
in my index.html since I've disabled Node, I have to load the script inline, and so I need some kind of IIFE to replace the main method:
(async () => {
await doSomething();
})();
How can I unit test this non-module then with Jasmine?
My solution ended up being hacky.
First, I had to make my non-module a module, so that I could import it in my specs.
I exported my interface and added a main method:
export interface A { }
export async function main(): Promise<void> {
await doSomething();
}
To avoid the crash I was getting before when I was loading a script with Node disabled, I added this hack to my html page:
<script>var exports = {};</script> // mutes the "exports not defined" error
<script src="./renderer.js"></script>
And then I made my IIFE call my main method if jasmine isn't running.
(async () => {
if (!window.jasmine) {
main();
}
})();
My unit tests meanwhile set up the spies and call the exported main method.