mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-12-12 09:52:37 +00:00
[tests] migrate from jest to vitest (#3940)
This is a big change, but I think it's a good move, as `vitest` is much more modern than `jest`. I'm excited about the UI watch feature (run `npm run test:ui`), for example - it's really helpful and saves time when debugging tests. I had to adjust a few tests because they had time related issues, but basically we are now testing the same things - even a bit better and less flaky (I hope). What do you think?
This commit is contained in:
committed by
GitHub
parent
b542f33a0a
commit
462abf7027
@@ -20,16 +20,41 @@ var indexData = [];
|
||||
var cssData = [];
|
||||
|
||||
exports.startApplication = async (configFilename, exec) => {
|
||||
jest.resetModules();
|
||||
vi.resetModules();
|
||||
|
||||
// Clear Node's require cache for config and app files to prevent stale configs and middlewares
|
||||
Object.keys(require.cache).forEach((key) => {
|
||||
if (
|
||||
key.includes("/tests/configs/")
|
||||
|| key.includes("/config/config")
|
||||
|| key.includes("/js/app.js")
|
||||
|| key.includes("/js/server.js")
|
||||
) {
|
||||
delete require.cache[key];
|
||||
}
|
||||
});
|
||||
|
||||
if (global.app) {
|
||||
await this.stopApplication();
|
||||
}
|
||||
|
||||
// Use fixed port 8080 (tests run sequentially, no conflicts)
|
||||
const port = 8080;
|
||||
global.testPort = port;
|
||||
|
||||
// Set config sample for use in test
|
||||
let configPath;
|
||||
if (configFilename === "") {
|
||||
process.env.MM_CONFIG_FILE = "config/config.js";
|
||||
configPath = "config/config.js";
|
||||
} else {
|
||||
process.env.MM_CONFIG_FILE = configFilename;
|
||||
configPath = configFilename;
|
||||
}
|
||||
|
||||
process.env.MM_CONFIG_FILE = configPath;
|
||||
|
||||
// Override port in config - MUST be set before app loads
|
||||
process.env.MM_PORT = port.toString();
|
||||
|
||||
process.env.mmTestMode = "true";
|
||||
process.setMaxListeners(0);
|
||||
if (exec) exec;
|
||||
@@ -38,24 +63,30 @@ exports.startApplication = async (configFilename, exec) => {
|
||||
return global.app.start();
|
||||
};
|
||||
|
||||
exports.stopApplication = async (waitTime = 10) => {
|
||||
exports.stopApplication = async (waitTime = 100) => {
|
||||
if (global.window) {
|
||||
// no closing causes jest errors and memory leaks
|
||||
// no closing causes test errors and memory leaks
|
||||
global.window.close();
|
||||
delete global.window;
|
||||
// give above closing some extra time to finish
|
||||
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||
}
|
||||
|
||||
if (!global.app) {
|
||||
delete global.testPort;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
await global.app.stop();
|
||||
delete global.app;
|
||||
delete global.testPort;
|
||||
|
||||
// Small delay to ensure clean shutdown
|
||||
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||
};
|
||||
|
||||
exports.getDocument = () => {
|
||||
return new Promise((resolve) => {
|
||||
const url = `http://${config.address || "localhost"}:${config.port || "8080"}`;
|
||||
const port = global.testPort || config.port || 8080;
|
||||
const url = `http://${config.address || "localhost"}:${port}`;
|
||||
jsdom.JSDOM.fromURL(url, { resources: "usable", runScripts: "dangerously" }).then((dom) => {
|
||||
dom.window.name = "jsdom";
|
||||
global.window = dom.window;
|
||||
|
||||
@@ -10,7 +10,8 @@ describe("ipWhitelist directive configuration", () => {
|
||||
});
|
||||
|
||||
it("should reject request with 403 (Forbidden)", async () => {
|
||||
const res = await fetch("http://localhost:8181");
|
||||
const port = global.testPort || 8080;
|
||||
const res = await fetch(`http://localhost:${port}`);
|
||||
expect(res.status).toBe(403);
|
||||
});
|
||||
});
|
||||
@@ -24,7 +25,8 @@ describe("ipWhitelist directive configuration", () => {
|
||||
});
|
||||
|
||||
it("should allow request with 200 (OK)", async () => {
|
||||
const res = await fetch("http://localhost:8282");
|
||||
const port = global.testPort || 8080;
|
||||
const res = await fetch(`http://localhost:${port}`);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,7 +10,8 @@ describe("port directive configuration", () => {
|
||||
});
|
||||
|
||||
it("should return 200", async () => {
|
||||
const res = await fetch("http://localhost:8090");
|
||||
const port = global.testPort || 8080;
|
||||
const res = await fetch(`http://localhost:${port}`);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
});
|
||||
@@ -24,7 +25,8 @@ describe("port directive configuration", () => {
|
||||
});
|
||||
|
||||
it("should return 200", async () => {
|
||||
const res = await fetch("http://localhost:8100");
|
||||
const port = global.testPort || 8080;
|
||||
const res = await fetch(`http://localhost:${port}`);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,14 +4,18 @@ const delay = (time) => {
|
||||
|
||||
const runConfigCheck = async () => {
|
||||
const serverProcess = await require("node:child_process").spawnSync("node", ["--run", "config:check"], { env: process.env });
|
||||
expect(serverProcess.stderr.toString()).toBe("");
|
||||
return await serverProcess.status;
|
||||
};
|
||||
|
||||
describe("App environment", () => {
|
||||
let serverProcess;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Use fixed port 8080 (tests run sequentially)
|
||||
const testPort = 8080;
|
||||
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/default.js";
|
||||
process.env.MM_PORT = testPort.toString();
|
||||
serverProcess = await require("node:child_process").spawn("node", ["--run", "server"], { env: process.env, detached: true });
|
||||
// we have to wait until the server is started
|
||||
await delay(2000);
|
||||
|
||||
@@ -15,7 +15,8 @@ describe("templated config with port variable", () => {
|
||||
});
|
||||
|
||||
it("should return 200", async () => {
|
||||
const res = await fetch("http://localhost:8090");
|
||||
const port = global.testPort || 8080;
|
||||
const res = await fetch(`http://localhost:${port}`);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ function createTranslationTestEnvironment () {
|
||||
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
|
||||
const dom = new JSDOM("", { url: "http://localhost:3000", runScripts: "outside-only" });
|
||||
|
||||
dom.window.Log = { log: jest.fn(), error: jest.fn() };
|
||||
dom.window.Log = { log: vi.fn(), error: vi.fn() };
|
||||
dom.window.translations = translations;
|
||||
dom.window.eval(translatorJs);
|
||||
|
||||
@@ -75,7 +75,7 @@ describe("translations", () => {
|
||||
it("should load translation file", async () => {
|
||||
const { Translator, Module, config } = dom.window;
|
||||
config.language = "en";
|
||||
Translator.load = jest.fn().mockImplementation((_m, _f, _fb) => null);
|
||||
Translator.load = vi.fn().mockImplementation((_m, _f, _fb) => null);
|
||||
|
||||
Module.register("name", { getTranslations: () => translations });
|
||||
const MMM = Module.create("name");
|
||||
@@ -88,7 +88,7 @@ describe("translations", () => {
|
||||
|
||||
it("should load translation + fallback file", async () => {
|
||||
const { Translator, Module } = dom.window;
|
||||
Translator.load = jest.fn().mockImplementation((_m, _f, _fb) => null);
|
||||
Translator.load = vi.fn().mockImplementation((_m, _f, _fb) => null);
|
||||
|
||||
Module.register("name", { getTranslations: () => translations });
|
||||
const MMM = Module.create("name");
|
||||
@@ -103,7 +103,7 @@ describe("translations", () => {
|
||||
it("should load translation fallback file", async () => {
|
||||
const { Translator, Module, config } = dom.window;
|
||||
config.language = "--";
|
||||
Translator.load = jest.fn().mockImplementation((_m, _f, _fb) => null);
|
||||
Translator.load = vi.fn().mockImplementation((_m, _f, _fb) => null);
|
||||
|
||||
Module.register("name", { getTranslations: () => translations });
|
||||
const MMM = Module.create("name");
|
||||
@@ -116,7 +116,7 @@ describe("translations", () => {
|
||||
|
||||
it("should load no file", async () => {
|
||||
const { Translator, Module } = dom.window;
|
||||
Translator.load = jest.fn();
|
||||
Translator.load = vi.fn();
|
||||
|
||||
Module.register("name", {});
|
||||
const MMM = Module.create("name");
|
||||
|
||||
Reference in New Issue
Block a user