chore: import upstream snapshot with attribution
Enforce Pull-Request Rules / check (push) Has been cancelled
Enforce Pull-Request Rules / check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
const deprecated = require("../../../js/deprecated");
|
||||
|
||||
describe("Deprecated", () => {
|
||||
it("should be an object", () => {
|
||||
expect(typeof deprecated).toBe("object");
|
||||
});
|
||||
|
||||
it("should contain clock array with deprecated options as strings", () => {
|
||||
expect(Array.isArray(["deprecated.clock"])).toBe(true);
|
||||
for (let option of deprecated.configs) {
|
||||
expect(typeof option).toBe("string");
|
||||
}
|
||||
expect(deprecated.clock).toEqual(expect.arrayContaining(["secondsColor"]));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,299 @@
|
||||
const path = require("node:path");
|
||||
const { pathToFileURL } = require("node:url");
|
||||
|
||||
describe("File js/module (cloneObject)", () => {
|
||||
describe("Test function cloneObject", () => {
|
||||
let clone;
|
||||
let Module;
|
||||
let originalWindow;
|
||||
let originalLog;
|
||||
let originalConfig;
|
||||
let originalMM;
|
||||
let originalTranslator;
|
||||
let originalNunjucks;
|
||||
|
||||
beforeAll(async () => {
|
||||
originalWindow = global.window;
|
||||
originalLog = global.Log;
|
||||
originalConfig = global.config;
|
||||
originalMM = global.MM;
|
||||
originalTranslator = global.Translator;
|
||||
originalNunjucks = global.nunjucks;
|
||||
|
||||
global.window = { mmVersion: "2.0.0" };
|
||||
global.Log = { log: () => {}, info: () => {}, warn: () => {}, error: () => {}, debug: () => {} };
|
||||
global.config = { language: "en" };
|
||||
global.MM = {
|
||||
hideModule: () => {},
|
||||
showModule: () => {},
|
||||
sendNotification: () => {},
|
||||
updateDom: () => {}
|
||||
};
|
||||
global.Translator = {
|
||||
load: () => Promise.resolve(),
|
||||
translate: () => ""
|
||||
};
|
||||
global.nunjucks = {
|
||||
Environment () {
|
||||
this.addFilter = () => {};
|
||||
this.renderString = () => "";
|
||||
this.render = (_template, _data, callback) => callback(null, "");
|
||||
},
|
||||
WebLoader () {},
|
||||
runtime: {
|
||||
markSafe: (str) => str
|
||||
}
|
||||
};
|
||||
|
||||
const modulePath = pathToFileURL(path.join(__dirname, "..", "..", "..", "js", "module.js")).href;
|
||||
const loaded = await import(`${modulePath}?test=${Date.now()}`);
|
||||
|
||||
clone = loaded.cloneObject;
|
||||
Module = loaded.Module;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.window = originalWindow;
|
||||
global.Log = originalLog;
|
||||
global.config = originalConfig;
|
||||
global.MM = originalMM;
|
||||
global.Translator = originalTranslator;
|
||||
global.nunjucks = originalNunjucks;
|
||||
});
|
||||
|
||||
it("should clone object", () => {
|
||||
const expected = { name: "Rodrigo", web: "https://rodrigoramirez.com", project: "MagicMirror" };
|
||||
const obj = clone(expected);
|
||||
expect(obj).toEqual(expected);
|
||||
expect(expected === obj).toBe(false);
|
||||
});
|
||||
|
||||
it("should clone array", () => {
|
||||
const expected = [1, null, undefined, "TEST"];
|
||||
const obj = clone(expected);
|
||||
expect(obj).toEqual(expected);
|
||||
expect(expected === obj).toBe(false);
|
||||
});
|
||||
|
||||
it("should clone number", () => {
|
||||
let expected = 1;
|
||||
let obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
|
||||
expected = 1.23;
|
||||
obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should clone string", () => {
|
||||
const expected = "Perfect stranger";
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should clone regex", () => {
|
||||
const expected = /.*Magic/;
|
||||
const obj = clone(expected);
|
||||
expect(obj).toEqual(expected);
|
||||
expect(expected === obj).toBe(false);
|
||||
});
|
||||
|
||||
it("should clone date", () => {
|
||||
const expected = new Date("2026-05-11T20:00:00.000Z");
|
||||
const obj = clone(expected);
|
||||
expect(obj).toEqual(expected);
|
||||
expect(expected === obj).toBe(false);
|
||||
});
|
||||
|
||||
it("should return URL by reference", () => {
|
||||
const expected = new URL("https://magicmirror.builders/path?q=1");
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should return map by reference", () => {
|
||||
const mapValue = { nested: [1, 2, 3] };
|
||||
const expected = new Map([["module", mapValue]]);
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should return set by reference", () => {
|
||||
const setValue = { nested: true };
|
||||
const expected = new Set([setValue]);
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should return class instances by reference", () => {
|
||||
class ModuleDefaults {
|
||||
constructor () {
|
||||
this.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
const expected = new ModuleDefaults();
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should clone undefined", () => {
|
||||
const expected = undefined;
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should clone null", () => {
|
||||
const expected = null;
|
||||
const obj = clone(expected);
|
||||
expect(obj).toBe(expected);
|
||||
});
|
||||
|
||||
it("should clone nested object", () => {
|
||||
const expected = {
|
||||
name: "fewieden",
|
||||
link: "https://github.com/fewieden",
|
||||
versions: ["2.0", "2.1", "2.2"],
|
||||
answerForAllQuestions: 42,
|
||||
properties: {
|
||||
items: [{ foo: "bar" }, { lorem: "ipsum" }],
|
||||
invalid: undefined,
|
||||
nothing: null
|
||||
}
|
||||
};
|
||||
const obj = clone(expected);
|
||||
expect(obj).toEqual(expected);
|
||||
expect(expected === obj).toBe(false);
|
||||
expect(expected.versions === obj.versions).toBe(false);
|
||||
expect(expected.properties === obj.properties).toBe(false);
|
||||
expect(expected.properties.items === obj.properties.items).toBe(false);
|
||||
expect(expected.properties.items[0] === obj.properties.items[0]).toBe(false);
|
||||
expect(expected.properties.items[1] === obj.properties.items[1]).toBe(false);
|
||||
});
|
||||
|
||||
describe("Test Module.create", () => {
|
||||
let info;
|
||||
|
||||
beforeEach(() => {
|
||||
info = global.Log.info;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.Log.info = info;
|
||||
Module.definitions = {};
|
||||
});
|
||||
|
||||
it("should create module instance with dynamic class name", () => {
|
||||
const moduleName = "MMM-TestModule";
|
||||
Module.register(moduleName, {
|
||||
defaults: {}
|
||||
});
|
||||
|
||||
const moduleInstance = Module.create(moduleName);
|
||||
|
||||
expect(moduleInstance.constructor.name).toBe(moduleName);
|
||||
});
|
||||
|
||||
it("should use fallback class name for empty module name", () => {
|
||||
const moduleName = "";
|
||||
Module.register(moduleName, {
|
||||
defaults: {}
|
||||
});
|
||||
|
||||
const moduleInstance = Module.create(moduleName);
|
||||
|
||||
expect(moduleInstance.constructor.name).toBe("AnonymousModule");
|
||||
});
|
||||
|
||||
it("should not throw when init is not a function", () => {
|
||||
const moduleName = "MMM-TestModuleNoInitFunction";
|
||||
Module.register(moduleName, {
|
||||
init: null,
|
||||
defaults: {}
|
||||
});
|
||||
|
||||
expect(() => Module.create(moduleName)).not.toThrow();
|
||||
});
|
||||
|
||||
it("should support lifecycle super call pattern", () => {
|
||||
const moduleName = "MMM-TestSuperCall";
|
||||
let loggedMessage;
|
||||
|
||||
global.Log.info = (message) => {
|
||||
loggedMessage = message;
|
||||
};
|
||||
|
||||
Module.register(moduleName, {
|
||||
defaults: {},
|
||||
start () {
|
||||
this.didStart = true;
|
||||
Module.prototype.start.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
const moduleInstance = Module.create(moduleName);
|
||||
moduleInstance.name = moduleName;
|
||||
moduleInstance.start();
|
||||
|
||||
expect(moduleInstance.didStart).toBe(true);
|
||||
expect(loggedMessage).toBe(`Starting module: ${moduleName}`);
|
||||
});
|
||||
|
||||
it("should set config when defaults are undefined", () => {
|
||||
const moduleName = "MMM-TestNoDefaults";
|
||||
Module.register(moduleName, {});
|
||||
|
||||
const moduleInstance = Module.create(moduleName);
|
||||
|
||||
moduleInstance.setConfig({ foo: "bar" }, false);
|
||||
expect(moduleInstance.config).toEqual({ foo: "bar" });
|
||||
|
||||
moduleInstance.setConfig({ nested: { value: 1 } }, true);
|
||||
expect(moduleInstance.config).toEqual({ nested: { value: 1 } });
|
||||
});
|
||||
|
||||
it("should initialize lifecycle fields in setData", () => {
|
||||
const moduleName = "MMM-TestSetData";
|
||||
Module.register(moduleName, {
|
||||
defaults: { fromDefaults: true }
|
||||
});
|
||||
|
||||
const moduleInstance = Module.create(moduleName);
|
||||
moduleInstance.setData({
|
||||
name: moduleName,
|
||||
identifier: "module_1",
|
||||
config: { fromConfig: true },
|
||||
configDeepMerge: false
|
||||
});
|
||||
|
||||
expect(moduleInstance.name).toBe(moduleName);
|
||||
expect(moduleInstance.identifier).toBe("module_1");
|
||||
expect(moduleInstance.hidden).toBe(false);
|
||||
expect(moduleInstance.hasAnimateIn).toBe(false);
|
||||
expect(moduleInstance.hasAnimateOut).toBe(false);
|
||||
expect(moduleInstance.config).toEqual({ fromDefaults: true, fromConfig: true });
|
||||
});
|
||||
|
||||
it("should not share defaults object across module instances", () => {
|
||||
const moduleName = "MMM-TestDefaultsIsolation";
|
||||
Module.register(moduleName, {
|
||||
defaults: {
|
||||
nested: { value: 1 },
|
||||
list: [1]
|
||||
}
|
||||
});
|
||||
|
||||
const firstModuleInstance = Module.create(moduleName);
|
||||
const secondModuleInstance = Module.create(moduleName);
|
||||
|
||||
firstModuleInstance.defaults.nested.value = 42;
|
||||
firstModuleInstance.defaults.list.push(2);
|
||||
|
||||
expect(secondModuleInstance.defaults).toEqual({
|
||||
nested: { value: 1 },
|
||||
list: [1]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
const SystemInformation = require("../../../js/systeminformation");
|
||||
|
||||
describe("SystemInformation", () => {
|
||||
it("should output system information", async () => {
|
||||
await expect(SystemInformation()).resolves.toContain("platform: linux");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,230 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const helmet = require("helmet");
|
||||
const { JSDOM } = require("jsdom");
|
||||
const express = require("express");
|
||||
|
||||
/**
|
||||
* Helper function to create a fresh Translator instance with DOM environment.
|
||||
* @returns {object} Object containing window and Translator
|
||||
*/
|
||||
function createTranslationTestEnvironment () {
|
||||
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "..", "js", "translator.js"), "utf-8");
|
||||
const dom = new JSDOM("", { url: "http://localhost:3001", runScripts: "outside-only" });
|
||||
|
||||
dom.window.Log = { log: vi.fn(), error: vi.fn() };
|
||||
dom.window.fetch = fetch;
|
||||
dom.window.eval(translatorJs);
|
||||
|
||||
return { window: dom.window, Translator: dom.window.Translator };
|
||||
}
|
||||
|
||||
describe("Translator", () => {
|
||||
let server;
|
||||
const sockets = new Set();
|
||||
const translationTestData = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "..", "tests", "mocks", "translation_test.json"), "utf8"));
|
||||
|
||||
beforeAll(() => {
|
||||
const app = express();
|
||||
app.use(helmet());
|
||||
app.use((req, res, next) => {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
next();
|
||||
});
|
||||
app.use("/translations", express.static(path.join(__dirname, "..", "..", "..", "tests", "mocks")));
|
||||
|
||||
server = app.listen(3001);
|
||||
|
||||
server.on("connection", (socket) => {
|
||||
sockets.add(socket);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
for (const socket of sockets) {
|
||||
socket.destroy();
|
||||
sockets.delete(socket);
|
||||
}
|
||||
|
||||
await server.close();
|
||||
});
|
||||
|
||||
describe("translate", () => {
|
||||
const translations = {
|
||||
"MMM-Module": {
|
||||
Hello: "Hallo",
|
||||
"Hello {username}": "Hallo {username}"
|
||||
}
|
||||
};
|
||||
|
||||
const coreTranslations = {
|
||||
Hello: "XXX",
|
||||
"Hello {username}": "XXX",
|
||||
FOO: "Foo",
|
||||
"BAR {something}": "Bar {something}"
|
||||
};
|
||||
|
||||
const translationsFallback = {
|
||||
"MMM-Module": {
|
||||
Hello: "XXX",
|
||||
"Hello {username}": "XXX",
|
||||
FOO: "XXX",
|
||||
"BAR {something}": "XXX",
|
||||
"A key": "A translation"
|
||||
}
|
||||
};
|
||||
|
||||
const coreTranslationsFallback = {
|
||||
FOO: "XXX",
|
||||
"BAR {something}": "XXX",
|
||||
Hello: "XXX",
|
||||
"Hello {username}": "XXX",
|
||||
"A key": "XXX",
|
||||
Fallback: "core fallback"
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {object} Translator the global Translator object
|
||||
*/
|
||||
const setTranslations = (Translator) => {
|
||||
Translator.translations = translations;
|
||||
Translator.coreTranslations = coreTranslations;
|
||||
Translator.translationsFallback = translationsFallback;
|
||||
Translator.coreTranslationsFallback = coreTranslationsFallback;
|
||||
};
|
||||
|
||||
it("should return custom module translation", () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
setTranslations(Translator);
|
||||
|
||||
let translation = Translator.translate({ name: "MMM-Module" }, "Hello");
|
||||
expect(translation).toBe("Hallo");
|
||||
|
||||
translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}", { username: "fewieden" });
|
||||
expect(translation).toBe("Hallo fewieden");
|
||||
});
|
||||
|
||||
it("should return core translation", () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
setTranslations(Translator);
|
||||
let translation = Translator.translate({ name: "MMM-Module" }, "FOO");
|
||||
expect(translation).toBe("Foo");
|
||||
translation = Translator.translate({ name: "MMM-Module" }, "BAR {something}", { something: "Lorem Ipsum" });
|
||||
expect(translation).toBe("Bar Lorem Ipsum");
|
||||
});
|
||||
|
||||
it("should return custom module translation fallback", () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "A key");
|
||||
expect(translation).toBe("A translation");
|
||||
});
|
||||
|
||||
it("should return core translation fallback", () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "Fallback");
|
||||
expect(translation).toBe("core fallback");
|
||||
});
|
||||
|
||||
it("should return translation with placeholder for missing variables", () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}");
|
||||
expect(translation).toBe("Hallo {username}");
|
||||
});
|
||||
|
||||
it("should return key if no translation was found", () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "MISSING");
|
||||
expect(translation).toBe("MISSING");
|
||||
});
|
||||
});
|
||||
|
||||
describe("load", () => {
|
||||
const mmm = {
|
||||
name: "TranslationTest",
|
||||
file (file) {
|
||||
return `http://localhost:3001/translations/${file}`;
|
||||
}
|
||||
};
|
||||
|
||||
it("should load translations", async () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
const file = "translation_test.json";
|
||||
|
||||
await Translator.load(mmm, file, false);
|
||||
const json = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "..", "tests", "mocks", file), "utf8"));
|
||||
expect(Translator.translations[mmm.name]).toEqual(json);
|
||||
});
|
||||
|
||||
it("should load translation fallbacks", async () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
const file = "translation_test.json";
|
||||
|
||||
await Translator.load(mmm, file, true);
|
||||
const json = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "..", "tests", "mocks", file), "utf8"));
|
||||
expect(Translator.translationsFallback[mmm.name]).toEqual(json);
|
||||
});
|
||||
|
||||
it("should not load translations, if module fallback exists", async () => {
|
||||
const { Translator } = createTranslationTestEnvironment();
|
||||
const file = "translation_test.json";
|
||||
|
||||
Translator.translationsFallback[mmm.name] = {
|
||||
Hello: "Hallo"
|
||||
};
|
||||
|
||||
await Translator.load(mmm, file, false);
|
||||
expect(Translator.translations[mmm.name]).toBeUndefined();
|
||||
expect(Translator.translationsFallback[mmm.name]).toEqual({
|
||||
Hello: "Hallo"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("loadCoreTranslations", () => {
|
||||
it("should load core translations and fallback", async () => {
|
||||
const { window, Translator } = createTranslationTestEnvironment();
|
||||
window.translations = { en: "http://localhost:3001/translations/translation_test.json" };
|
||||
await Translator.loadCoreTranslations("en");
|
||||
|
||||
const en = translationTestData;
|
||||
|
||||
expect(Translator.coreTranslations).toEqual(en);
|
||||
expect(Translator.coreTranslationsFallback).toEqual(en);
|
||||
});
|
||||
|
||||
it("should load core fallback if language cannot be found", async () => {
|
||||
const { window, Translator } = createTranslationTestEnvironment();
|
||||
window.translations = { en: "http://localhost:3001/translations/translation_test.json" };
|
||||
await Translator.loadCoreTranslations("MISSINGLANG");
|
||||
|
||||
const en = translationTestData;
|
||||
|
||||
expect(Translator.coreTranslations).toEqual({});
|
||||
expect(Translator.coreTranslationsFallback).toEqual(en);
|
||||
});
|
||||
});
|
||||
|
||||
describe("loadCoreTranslationsFallback", () => {
|
||||
it("should load core translations fallback", async () => {
|
||||
const { window, Translator } = createTranslationTestEnvironment();
|
||||
window.translations = { en: "http://localhost:3001/translations/translation_test.json" };
|
||||
await Translator.loadCoreTranslationsFallback();
|
||||
|
||||
const en = translationTestData;
|
||||
|
||||
expect(Translator.coreTranslationsFallback).toEqual(en);
|
||||
});
|
||||
|
||||
it("should load core fallback if language cannot be found", async () => {
|
||||
const { window, Translator } = createTranslationTestEnvironment();
|
||||
window.translations = {};
|
||||
await Translator.loadCoreTranslations();
|
||||
|
||||
expect(Translator.coreTranslationsFallback).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
const fs = require("node:fs");
|
||||
|
||||
const Log = require("../../../js/logger");
|
||||
const { checkConfigFile, ConfigError } = require("../../../js/utils");
|
||||
|
||||
const createConfigObject = (modules) => ({
|
||||
configFilename: "config.js",
|
||||
configContentFull: "module.exports = { modules: [] };",
|
||||
fullConf: { modules }
|
||||
});
|
||||
|
||||
const runCheck = (modules) => {
|
||||
checkConfigFile(createConfigObject(modules));
|
||||
};
|
||||
|
||||
const expectExitForModules = (modules) => {
|
||||
vi.spyOn(process, "exit").mockImplementation(() => {
|
||||
throw new ConfigError("");
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
runCheck(modules);
|
||||
}).toThrow(ConfigError);
|
||||
};
|
||||
|
||||
describe("utils", () => {
|
||||
let originalReadFileSync;
|
||||
|
||||
beforeEach(() => {
|
||||
originalReadFileSync = fs.readFileSync;
|
||||
|
||||
vi.spyOn(fs, "readFileSync").mockImplementation((fileName, ...args) => {
|
||||
if (fileName === "index.html") {
|
||||
return "<div class=\"region top_bar\"></div>\n<div class=\"region lower_third\"></div>";
|
||||
}
|
||||
|
||||
return originalReadFileSync.call(fs, fileName, ...args);
|
||||
});
|
||||
|
||||
vi.spyOn(fs, "writeFileSync").mockImplementation(() => {});
|
||||
vi.spyOn(Log, "info").mockImplementation(() => {});
|
||||
vi.spyOn(Log, "warn").mockImplementation(() => {});
|
||||
vi.spyOn(Log, "error").mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("accepts valid module entries", () => {
|
||||
expect(() => {
|
||||
runCheck([
|
||||
{ module: "clock", position: "top_bar" },
|
||||
{ module: "newsfeed" }
|
||||
]);
|
||||
}).not.toThrow();
|
||||
expect(Log.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("exits when modules is not an array", () => {
|
||||
expectExitForModules("not-an-array");
|
||||
expect(Log.error).toHaveBeenCalledWith("This module configuration contains errors:\nmodules must be an array");
|
||||
});
|
||||
|
||||
it("exits when module field is missing or not a string", () => {
|
||||
expectExitForModules([{ module: 123, position: "top_bar" }]);
|
||||
expect(Log.error).toHaveBeenCalled();
|
||||
expect(Log.error.mock.calls[0][0]).toContain("module: must be a string");
|
||||
});
|
||||
|
||||
it("warns for unknown positions without exiting", () => {
|
||||
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
||||
throw new ConfigError("");
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
runCheck([{ module: "clock", position: "made_up_region" }]);
|
||||
}).not.toThrow();
|
||||
expect(exitSpy).not.toHaveBeenCalled();
|
||||
expect(Log.warn).toHaveBeenCalled();
|
||||
expect(Log.warn.mock.calls[0][0]).toContain("uses unknown position");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user