mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-08-21 12:55:22 +00:00
Compare commits
16 Commits
855b1d7cbf
...
develop
Author | SHA1 | Date | |
---|---|---|---|
|
83d15aaaaa | ||
|
1b31cf19e9 | ||
|
0ca7d23b69 | ||
|
839d074df1 | ||
|
e34ef0cb6e | ||
|
3fa2b96054 | ||
|
e7b669af34 | ||
|
54752f10e8 | ||
|
02e76da196 | ||
|
7f8935a34c | ||
|
931fe55022 | ||
|
a05eb23306 | ||
|
e115475a9d | ||
|
e4ec8c3589 | ||
|
d9e2e0272f | ||
|
3a2a52c864 |
4
.github/workflows/automated-tests.yaml
vendored
4
.github/workflows/automated-tests.yaml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: "Use Node.js"
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libnss3 libasound2t64 labwc
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: "Use Node.js ${{ matrix.node-version }}"
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
2
.github/workflows/dep-review.yaml
vendored
2
.github/workflows/dep-review.yaml
vendored
@@ -13,6 +13,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: "Dependency Review"
|
||||
uses: actions/dependency-review-action@v4
|
||||
|
2
.github/workflows/electron-rebuild.yaml
vendored
2
.github/workflows/electron-rebuild.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
node-version: [22.14.0, 22.x, 24.x]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: "Use Node.js ${{ matrix.node-version }}"
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
2
.github/workflows/spellcheck.yaml
vendored
2
.github/workflows/spellcheck.yaml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: develop
|
||||
- name: Set up Node.js
|
||||
|
21
CHANGELOG.md
21
CHANGELOG.md
@@ -11,9 +11,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
planned for 2025-10-01
|
||||
|
||||
Thanks to: @dathbe.
|
||||
|
||||
### Changed
|
||||
|
||||
- [clock] Add CSS to prevent line breaking of sunset/sunrise time display (#3816)
|
||||
- [core] Enhance system information logging format and include additional env and RAM details (#3839, #3843)
|
||||
- [refactor] Add new file `js/module_functions.js` to move code used in several modules to one place (#3837)
|
||||
- [tests] refactor: simplify jest config file (#3844)
|
||||
- [tests] refactor: extract constants for weather electron tests (#3845)
|
||||
- [tests] refactor: add `setupDOMEnvironment` helper function to eliminate repetitive JSDOM setup code (#3860)
|
||||
- [tests] replace `console` with `Log` in calendar `debug.js` to avoid exception in eslint config (#3846)
|
||||
- [tests] speed up e2e tests, cleanup and stabilize weather e2e tests (#3847, #3848)
|
||||
|
||||
### Updated
|
||||
|
||||
- [core] Update dependencies including electron to v37 (#3831)
|
||||
- [core] Update dependencies including electron to v37 as well as github actions (#3831, #3849, #3857, #3858)
|
||||
|
||||
### Fixed
|
||||
|
||||
- [calendar] Fixed broken unittest that only broke on the 1st of July and 1st of january (#3830)
|
||||
- [clock] Fixed missing icons when no other modules with icons is loaded (#3834)
|
||||
- [weather] Fixed handling of empty values in weathergov providers handling of precipitationAmount (#3859)
|
||||
|
||||
## [2.32.0] - 2025-07-01
|
||||
|
||||
|
@@ -88,7 +88,6 @@ export default defineConfig([
|
||||
files: ["**/*.js"],
|
||||
ignores: [
|
||||
"clientonly/index.js",
|
||||
"modules/default/calendar/debug.js",
|
||||
"js/logger.js",
|
||||
"tests/**/*.js"
|
||||
],
|
||||
|
@@ -1,32 +1,37 @@
|
||||
module.exports = async () => {
|
||||
return {
|
||||
verbose: true,
|
||||
testTimeout: 20000,
|
||||
testSequencer: "<rootDir>/tests/utils/test_sequencer.js",
|
||||
projects: [
|
||||
{
|
||||
displayName: "unit",
|
||||
globalSetup: "<rootDir>/tests/unit/helpers/global-setup.js",
|
||||
moduleNameMapper: {
|
||||
logger: "<rootDir>/js/logger.js"
|
||||
},
|
||||
testMatch: ["**/tests/unit/**/*.[jt]s?(x)"],
|
||||
testPathIgnorePatterns: ["<rootDir>/tests/unit/mocks", "<rootDir>/tests/unit/helpers"]
|
||||
const config = {
|
||||
verbose: true,
|
||||
testTimeout: 20000,
|
||||
testSequencer: "<rootDir>/tests/utils/test_sequencer.js",
|
||||
projects: [
|
||||
{
|
||||
displayName: "unit",
|
||||
globalSetup: "<rootDir>/tests/unit/helpers/global-setup.js",
|
||||
moduleNameMapper: {
|
||||
logger: "<rootDir>/js/logger.js"
|
||||
},
|
||||
{
|
||||
displayName: "electron",
|
||||
testMatch: ["**/tests/electron/**/*.[jt]s?(x)"],
|
||||
testPathIgnorePatterns: ["<rootDir>/tests/electron/helpers"]
|
||||
},
|
||||
{
|
||||
displayName: "e2e",
|
||||
testMatch: ["**/tests/e2e/**/*.[jt]s?(x)"],
|
||||
modulePaths: ["<rootDir>/js/"],
|
||||
testPathIgnorePatterns: ["<rootDir>/tests/e2e/helpers", "<rootDir>/tests/e2e/mocks"]
|
||||
}
|
||||
],
|
||||
collectCoverageFrom: ["./clientonly/**/*.js", "./js/**/*.js", "./modules/default/**/*.js", "./serveronly/**/*.js"],
|
||||
coverageReporters: ["lcov", "text"],
|
||||
coverageProvider: "v8"
|
||||
};
|
||||
testMatch: ["**/tests/unit/**/*.[jt]s?(x)"],
|
||||
testPathIgnorePatterns: ["<rootDir>/tests/unit/mocks", "<rootDir>/tests/unit/helpers"]
|
||||
},
|
||||
{
|
||||
displayName: "electron",
|
||||
testMatch: ["**/tests/electron/**/*.[jt]s?(x)"],
|
||||
testPathIgnorePatterns: ["<rootDir>/tests/electron/helpers"]
|
||||
},
|
||||
{
|
||||
displayName: "e2e",
|
||||
testMatch: ["**/tests/e2e/**/*.[jt]s?(x)"],
|
||||
modulePaths: ["<rootDir>/js/"],
|
||||
testPathIgnorePatterns: ["<rootDir>/tests/e2e/helpers", "<rootDir>/tests/e2e/mocks"]
|
||||
}
|
||||
],
|
||||
collectCoverageFrom: [
|
||||
"<rootDir>/clientonly/**/*.js",
|
||||
"<rootDir>/js/**/*.js",
|
||||
"<rootDir>/modules/default/**/*.js",
|
||||
"<rootDir>/serveronly/**/*.js"
|
||||
],
|
||||
coverageReporters: ["lcov", "text"],
|
||||
coverageProvider: "v8"
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
@@ -22,7 +22,7 @@ global.mmTestMode = process.env.mmTestMode === "true";
|
||||
Log.log(`Starting MagicMirror: v${global.version}`);
|
||||
|
||||
// Log system information.
|
||||
Utils.logSystemInformation();
|
||||
Utils.logSystemInformation(global.version);
|
||||
|
||||
// global absolute root path
|
||||
global.root_path = path.resolve(`${__dirname}/../`);
|
||||
|
18
js/module_functions.js
Normal file
18
js/module_functions.js
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Schedule the timer for the next update
|
||||
* @param {object} timer The timer of the module
|
||||
* @param {bigint} intervalMS interval in milliseconds
|
||||
* @param {Function} callback function to call when the timer expires
|
||||
*/
|
||||
const scheduleTimer = function (timer, intervalMS, callback) {
|
||||
if (process.env.JEST_WORKER_ID === undefined) {
|
||||
// only set timer when not running in jest
|
||||
let tmr = timer;
|
||||
clearTimeout(tmr);
|
||||
tmr = setTimeout(function () {
|
||||
callback();
|
||||
}, intervalMS);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { scheduleTimer };
|
38
js/utils.js
38
js/utils.js
@@ -1,4 +1,3 @@
|
||||
const execSync = require("node:child_process").execSync;
|
||||
const path = require("node:path");
|
||||
|
||||
const rootPath = path.resolve(`${__dirname}/../`);
|
||||
@@ -14,27 +13,34 @@ const discoveredPositionsJSFilename = "js/positions.js";
|
||||
|
||||
module.exports = {
|
||||
|
||||
async logSystemInformation () {
|
||||
async logSystemInformation (mirrorVersion) {
|
||||
try {
|
||||
let installedNodeVersion = execSync("node -v", { encoding: "utf-8" }).replace("v", "").replace(/(?:\r\n|\r|\n)/g, "");
|
||||
const system = await si.system();
|
||||
const osInfo = await si.osInfo();
|
||||
const versions = await si.versions();
|
||||
|
||||
const staticData = await si.get({
|
||||
system: "manufacturer, model, virtual",
|
||||
osInfo: "platform, distro, release, arch",
|
||||
versions: "kernel, node, npm, pm2"
|
||||
});
|
||||
let systemDataString = `System information:
|
||||
### SYSTEM: manufacturer: ${staticData.system.manufacturer}; model: ${staticData.system.model}; virtual: ${staticData.system.virtual}
|
||||
### OS: platform: ${staticData.osInfo.platform}; distro: ${staticData.osInfo.distro}; release: ${staticData.osInfo.release}; arch: ${staticData.osInfo.arch}; kernel: ${staticData.versions.kernel}
|
||||
### VERSIONS: electron: ${process.versions.electron}; used node: ${staticData.versions.node}; installed node: ${installedNodeVersion}; npm: ${staticData.versions.npm}; pm2: ${staticData.versions.pm2}
|
||||
### OTHER: timeZone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}; ELECTRON_ENABLE_GPU: ${process.env.ELECTRON_ENABLE_GPU}`
|
||||
.replace(/\t/g, "");
|
||||
const usedNodeVersion = process.version.replace("v", "");
|
||||
const installedNodeVersion = versions.node;
|
||||
const totalRam = (os.totalmem() / 1024 / 1024).toFixed(2);
|
||||
const freeRam = (os.freemem() / 1024 / 1024).toFixed(2);
|
||||
const usedRam = ((os.totalmem() - os.freemem()) / 1024 / 1024).toFixed(2);
|
||||
|
||||
let systemDataString = [
|
||||
"\n#### System Information ####",
|
||||
`- SYSTEM: manufacturer: ${system.manufacturer}; model: ${system.model}; virtual: ${system.virtual}; MM: ${mirrorVersion}`,
|
||||
`- OS: platform: ${osInfo.platform}; distro: ${osInfo.distro}; release: ${osInfo.release}; arch: ${osInfo.arch}; kernel: ${versions.kernel}`,
|
||||
`- VERSIONS: electron: ${process.versions.electron}; used node: ${usedNodeVersion}; installed node: ${installedNodeVersion}; npm: ${versions.npm}; pm2: ${versions.pm2}`,
|
||||
`- ENV: XDG_SESSION_TYPE: ${process.env.XDG_SESSION_TYPE}; MM_CONFIG_FILE: ${process.env.MM_CONFIG_FILE}`,
|
||||
` WAYLAND_DISPLAY: ${process.env.WAYLAND_DISPLAY}; DISPLAY: ${process.env.DISPLAY}; ELECTRON_ENABLE_GPU: ${process.env.ELECTRON_ENABLE_GPU}`,
|
||||
`- RAM: total: ${totalRam} MB; free: ${freeRam} MB; used: ${usedRam} MB`,
|
||||
`- OTHERS: uptime: ${Math.floor(os.uptime() / 60)} minutes; timeZone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`
|
||||
].join("\n");
|
||||
Log.info(systemDataString);
|
||||
|
||||
// Return is currently only for jest
|
||||
return systemDataString;
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
} catch (error) {
|
||||
Log.error(error);
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
font-size: 70%;
|
||||
position: relative;
|
||||
display: table;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
max-width: 100%;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
@@ -35,7 +35,7 @@
|
||||
top: 40%;
|
||||
width: 40%;
|
||||
height: auto;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,7 @@ const ical = require("node-ical");
|
||||
const Log = require("logger");
|
||||
const NodeHelper = require("node_helper");
|
||||
const CalendarFetcherUtils = require("./calendarfetcherutils");
|
||||
const { scheduleTimer } = require("#module_functions");
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -65,31 +66,18 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
|
||||
});
|
||||
} catch (error) {
|
||||
fetchFailedCallback(this, error);
|
||||
scheduleTimer();
|
||||
scheduleTimer(reloadTimer, reloadInterval, fetchCalendar);
|
||||
return;
|
||||
}
|
||||
this.broadcastEvents();
|
||||
scheduleTimer();
|
||||
scheduleTimer(reloadTimer, reloadInterval, fetchCalendar);
|
||||
})
|
||||
.catch((error) => {
|
||||
fetchFailedCallback(this, error);
|
||||
scheduleTimer();
|
||||
scheduleTimer(reloadTimer, reloadInterval, fetchCalendar);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedule the timer for the next update.
|
||||
*/
|
||||
const scheduleTimer = function () {
|
||||
if (process.env.JEST_WORKER_ID === undefined) {
|
||||
// only set timer when not running in jest
|
||||
clearTimeout(reloadTimer);
|
||||
reloadTimer = setTimeout(function () {
|
||||
fetchCalendar();
|
||||
}, reloadInterval);
|
||||
}
|
||||
};
|
||||
|
||||
/* public methods */
|
||||
|
||||
/**
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
// Alias modules mentioned in package.js under _moduleAliases.
|
||||
require("module-alias/register");
|
||||
const Log = require("../../../js/logger");
|
||||
|
||||
const CalendarFetcher = require("./calendarfetcher");
|
||||
|
||||
@@ -20,22 +21,22 @@ const auth = {
|
||||
pass: pass
|
||||
};
|
||||
|
||||
console.log("Create fetcher ...");
|
||||
Log.log("Create fetcher ...");
|
||||
|
||||
const fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
|
||||
|
||||
fetcher.onReceive(function (fetcher) {
|
||||
console.log(fetcher.events());
|
||||
console.log("------------------------------------------------------------");
|
||||
Log.log(fetcher.events());
|
||||
Log.log("------------------------------------------------------------");
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
fetcher.onError(function (fetcher, error) {
|
||||
console.log("Fetcher error:");
|
||||
console.log(error);
|
||||
Log.log("Fetcher error:");
|
||||
Log.log(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
fetcher.startFetch();
|
||||
|
||||
console.log("Create fetcher done! ");
|
||||
Log.log("Create fetcher done! ");
|
||||
|
@@ -36,7 +36,7 @@ Module.register("clock", {
|
||||
},
|
||||
// Define styles.
|
||||
getStyles () {
|
||||
return ["clock_styles.css"];
|
||||
return ["clock_styles.css", "font-awesome.css"];
|
||||
},
|
||||
// Define start sequence.
|
||||
start () {
|
||||
|
@@ -87,9 +87,17 @@
|
||||
transform-origin: 50% 100%;
|
||||
}
|
||||
|
||||
.module.clock .digital {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.module.clock .sun,
|
||||
.module.clock .moon {
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.module.clock .sun > *,
|
||||
|
@@ -5,6 +5,7 @@ const iconv = require("iconv-lite");
|
||||
const { htmlToText } = require("html-to-text");
|
||||
const Log = require("logger");
|
||||
const NodeHelper = require("node_helper");
|
||||
const { scheduleTimer } = require("#module_functions");
|
||||
|
||||
/**
|
||||
* Responsible for requesting an update on the set interval and broadcasting the data.
|
||||
@@ -79,12 +80,12 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
|
||||
parser.on("error", (error) => {
|
||||
fetchFailedCallback(this, error);
|
||||
scheduleTimer();
|
||||
scheduleTimer(reloadTimer, reloadIntervalMS, fetchNews);
|
||||
});
|
||||
|
||||
//"end" event is not broadcast if the feed is empty but "finish" is used for both
|
||||
parser.on("finish", () => {
|
||||
scheduleTimer();
|
||||
scheduleTimer(reloadTimer, reloadIntervalMS, fetchNews);
|
||||
});
|
||||
|
||||
parser.on("ttl", (minutes) => {
|
||||
@@ -120,23 +121,10 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
})
|
||||
.catch((error) => {
|
||||
fetchFailedCallback(this, error);
|
||||
scheduleTimer();
|
||||
scheduleTimer(reloadTimer, reloadIntervalMS, fetchNews);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedule the timer for the next update.
|
||||
*/
|
||||
const scheduleTimer = function () {
|
||||
if (process.env.JEST_WORKER_ID === undefined) {
|
||||
// only set timer when not running in jest
|
||||
clearTimeout(reloadTimer);
|
||||
reloadTimer = setTimeout(function () {
|
||||
fetchNews();
|
||||
}, reloadIntervalMS);
|
||||
}
|
||||
};
|
||||
|
||||
/* public methods */
|
||||
|
||||
/**
|
||||
|
@@ -218,7 +218,7 @@ WeatherProvider.register("weathergov", {
|
||||
currentWeather.minTemperature = currentWeatherData.minTemperatureLast24Hours.value;
|
||||
currentWeather.maxTemperature = currentWeatherData.maxTemperatureLast24Hours.value;
|
||||
currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
|
||||
currentWeather.precipitationAmount = currentWeatherData.precipitationLastHour.value ? currentWeatherData.precipitationLastHour.value : currentWeatherData.precipitationLast3Hours.value;
|
||||
currentWeather.precipitationAmount = currentWeatherData.precipitationLastHour?.value ?? currentWeatherData.precipitationLast3Hours?.value;
|
||||
if (currentWeatherData.heatIndex.value !== null) {
|
||||
currentWeather.feelsLikeTemp = currentWeatherData.heatIndex.value;
|
||||
} else if (currentWeatherData.windChill.value !== null) {
|
||||
|
@@ -163,7 +163,8 @@ Module.register("weather", {
|
||||
// What to do when the weather provider has new information available?
|
||||
updateAvailable () {
|
||||
Log.log("New weather information available.");
|
||||
this.updateDom(0);
|
||||
// this value was changed from 0 to 300 to stabilize weather tests:
|
||||
this.updateDom(300);
|
||||
this.scheduleUpdate();
|
||||
|
||||
if (this.weatherProvider.currentWeather()) {
|
||||
|
2103
package-lock.json
generated
2103
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
@@ -23,16 +23,21 @@
|
||||
"https://github.com/MagicMirrorOrg/MagicMirror/graphs/contributors"
|
||||
],
|
||||
"type": "commonjs",
|
||||
"imports": {
|
||||
"#module_functions": {
|
||||
"default": "./js/module_functions.js"
|
||||
}
|
||||
},
|
||||
"main": "js/electron.js",
|
||||
"scripts": {
|
||||
"config:check": "node js/check_config.js",
|
||||
"postinstall": "git clean -df fonts vendor",
|
||||
"install-mm": "npm install --no-audit --no-fund --no-update-notifier --only=prod --omit=dev",
|
||||
"install-mm:dev": "npm install --no-audit --no-fund --no-update-notifier",
|
||||
"lint:css": "stylelint 'css/main.css' 'css/roboto.css' 'css/font-awesome.css' 'modules/default/**/*.css' --fix",
|
||||
"lint:js": "eslint --fix",
|
||||
"lint:markdown": "markdownlint-cli2 . --fix",
|
||||
"lint:prettier": "prettier . --write",
|
||||
"postinstall": "git clean -df fonts vendor",
|
||||
"prepare": "[ -f node_modules/.bin/husky ] && husky || echo no husky installed.",
|
||||
"server": "node ./serveronly",
|
||||
"start": "node --run start:x11",
|
||||
@@ -63,13 +68,13 @@
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^5.2.6",
|
||||
"@fontsource/roboto-condensed": "^5.2.6",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@fortawesome/fontawesome-free": "^7.0.0",
|
||||
"ajv": "^8.17.1",
|
||||
"animate.css": "^4.1.1",
|
||||
"console-stamp": "^3.1.2",
|
||||
"croner": "^9.1.0",
|
||||
"envsub": "^4.1.0",
|
||||
"eslint": "^9.30.0",
|
||||
"eslint": "^9.33.0",
|
||||
"express": "^5.1.0",
|
||||
"express-ipfilter": "^1.3.2",
|
||||
"feedme": "^2.0.2",
|
||||
@@ -85,31 +90,31 @@
|
||||
"socket.io": "^4.8.1",
|
||||
"suncalc": "^1.9.0",
|
||||
"systeminformation": "^5.27.7",
|
||||
"undici": "^7.11.0",
|
||||
"undici": "^7.13.0",
|
||||
"weathericons": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stylistic/eslint-plugin": "^5.1.0",
|
||||
"cspell": "^9.1.2",
|
||||
"@stylistic/eslint-plugin": "^5.2.3",
|
||||
"cspell": "^9.2.0",
|
||||
"eslint-plugin-import-x": "^4.16.1",
|
||||
"eslint-plugin-jest": "^29.0.1",
|
||||
"eslint-plugin-jsdoc": "^51.3.1",
|
||||
"eslint-plugin-package-json": "^0.42.0",
|
||||
"eslint-plugin-jsdoc": "^52.0.4",
|
||||
"eslint-plugin-package-json": "^0.52.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.0.3",
|
||||
"jest": "^30.0.5",
|
||||
"jsdom": "^26.1.0",
|
||||
"lint-staged": "^16.1.2",
|
||||
"lint-staged": "^16.1.5",
|
||||
"markdownlint-cli2": "^0.18.1",
|
||||
"playwright": "^1.53.2",
|
||||
"playwright": "^1.54.2",
|
||||
"prettier": "^3.6.2",
|
||||
"sinon": "^21.0.0",
|
||||
"stylelint": "^16.21.0",
|
||||
"stylelint-config-standard": "^38.0.0",
|
||||
"stylelint": "^16.23.1",
|
||||
"stylelint-config-standard": "^39.0.0",
|
||||
"stylelint-prettier": "^5.0.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron": "^37.1.0"
|
||||
"electron": "^37.2.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.14.0"
|
||||
|
@@ -34,7 +34,7 @@ exports.startApplication = async (configFilename, exec) => {
|
||||
return global.app.start();
|
||||
};
|
||||
|
||||
exports.stopApplication = async (waitTime = 1000) => {
|
||||
exports.stopApplication = async (waitTime = 10) => {
|
||||
if (global.window) {
|
||||
// no closing causes jest errors and memory leaks
|
||||
global.window.close();
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const { injectMockData } = require("../../utils/weather_mocker");
|
||||
const { injectMockData, cleanupMockData } = require("../../utils/weather_mocker");
|
||||
const helpers = require("./global-setup");
|
||||
|
||||
exports.getText = async (element, result) => {
|
||||
@@ -13,7 +13,12 @@ exports.getText = async (element, result) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.startApp = async (configFileName, additionalMockData) => {
|
||||
exports.startApplication = async (configFileName, additionalMockData) => {
|
||||
await helpers.startApplication(injectMockData(configFileName, additionalMockData));
|
||||
await helpers.getDocument();
|
||||
};
|
||||
|
||||
exports.stopApplication = async () => {
|
||||
await helpers.stopApplication();
|
||||
cleanupMockData();
|
||||
};
|
||||
|
@@ -1,17 +1,15 @@
|
||||
const helpers = require("../helpers/global-setup");
|
||||
const weatherFunc = require("../helpers/weather-functions");
|
||||
const { cleanupMockData } = require("../../utils/weather_mocker");
|
||||
|
||||
describe("Weather module", () => {
|
||||
afterAll(async () => {
|
||||
await helpers.stopApplication();
|
||||
await cleanupMockData();
|
||||
await weatherFunc.stopApplication();
|
||||
});
|
||||
|
||||
describe("Current weather", () => {
|
||||
describe("Default configuration", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_default.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/currentweather_default.js", {});
|
||||
});
|
||||
|
||||
it("should render wind speed and wind direction", async () => {
|
||||
@@ -34,7 +32,7 @@ describe("Weather module", () => {
|
||||
|
||||
describe("Compliments Integration", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_compliments.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/currentweather_compliments.js", {});
|
||||
});
|
||||
|
||||
it("should render a compliment based on the current weather", async () => {
|
||||
@@ -44,7 +42,7 @@ describe("Weather module", () => {
|
||||
|
||||
describe("Configuration Options", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_options.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/currentweather_options.js", {});
|
||||
});
|
||||
|
||||
it("should render windUnits in beaufort", async () => {
|
||||
@@ -72,7 +70,7 @@ describe("Weather module", () => {
|
||||
|
||||
describe("Current weather with imperial units", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/currentweather_units.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/currentweather_units.js", {});
|
||||
});
|
||||
|
||||
it("should render wind in imperial units", async () => {
|
||||
|
@@ -1,16 +1,14 @@
|
||||
const helpers = require("../helpers/global-setup");
|
||||
const weatherFunc = require("../helpers/weather-functions");
|
||||
const { cleanupMockData } = require("../../utils/weather_mocker");
|
||||
|
||||
describe("Weather module: Weather Forecast", () => {
|
||||
afterAll(async () => {
|
||||
await helpers.stopApplication();
|
||||
await cleanupMockData();
|
||||
await weatherFunc.stopApplication();
|
||||
});
|
||||
|
||||
describe("Default configuration", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_default.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/forecastweather_default.js", {});
|
||||
});
|
||||
|
||||
const days = ["Today", "Tomorrow", "Sun", "Mon", "Tue"];
|
||||
@@ -54,7 +52,7 @@ describe("Weather module: Weather Forecast", () => {
|
||||
|
||||
describe("Absolute configuration", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_absolute.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/forecastweather_absolute.js", {});
|
||||
});
|
||||
|
||||
const days = ["Fri", "Sat", "Sun", "Mon", "Tue"];
|
||||
@@ -67,7 +65,7 @@ describe("Weather module: Weather Forecast", () => {
|
||||
|
||||
describe("Configuration Options", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_options.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/forecastweather_options.js", {});
|
||||
});
|
||||
|
||||
it("should render custom table class", async () => {
|
||||
@@ -94,7 +92,7 @@ describe("Weather module: Weather Forecast", () => {
|
||||
|
||||
describe("Forecast weather with imperial units", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/forecastweather_units.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/forecastweather_units.js", {});
|
||||
});
|
||||
|
||||
describe("Temperature units", () => {
|
||||
|
@@ -1,16 +1,13 @@
|
||||
const helpers = require("../helpers/global-setup");
|
||||
const weatherFunc = require("../helpers/weather-functions");
|
||||
const { cleanupMockData } = require("../../utils/weather_mocker");
|
||||
|
||||
describe("Weather module: Weather Hourly Forecast", () => {
|
||||
afterAll(async () => {
|
||||
await helpers.stopApplication();
|
||||
await cleanupMockData();
|
||||
await weatherFunc.stopApplication();
|
||||
});
|
||||
|
||||
describe("Default configuration", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/hourlyweather_default.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/hourlyweather_default.js", {});
|
||||
});
|
||||
|
||||
const minTemps = ["7:00 pm", "8:00 pm", "9:00 pm", "10:00 pm", "11:00 pm"];
|
||||
@@ -23,7 +20,7 @@ describe("Weather module: Weather Hourly Forecast", () => {
|
||||
|
||||
describe("Hourly weather options", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/hourlyweather_options.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/hourlyweather_options.js", {});
|
||||
});
|
||||
|
||||
describe("Hourly increments of 2", () => {
|
||||
@@ -38,7 +35,7 @@ describe("Weather module: Weather Hourly Forecast", () => {
|
||||
|
||||
describe("Show precipitations", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherFunc.startApp("tests/configs/modules/weather/hourlyweather_showPrecipitation.js", {});
|
||||
await weatherFunc.startApplication("tests/configs/modules/weather/hourlyweather_showPrecipitation.js", {});
|
||||
});
|
||||
|
||||
describe("Shows precipitation amount", () => {
|
||||
|
@@ -6,6 +6,21 @@ const express = require("express");
|
||||
const sinon = require("sinon");
|
||||
const translations = require("../../translations/translations");
|
||||
|
||||
/**
|
||||
* Helper function to setup DOM environment.
|
||||
* @returns {object} The JSDOM window object
|
||||
*/
|
||||
function setupDOMEnvironment () {
|
||||
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
|
||||
|
||||
dom.window.Log = { log: jest.fn(), error: jest.fn() };
|
||||
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
|
||||
dom.window.translations = translations;
|
||||
dom.window.eval(translatorJs);
|
||||
|
||||
return dom.window;
|
||||
}
|
||||
|
||||
describe("translations", () => {
|
||||
let server;
|
||||
|
||||
@@ -38,10 +53,10 @@ describe("translations", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// Create a new JSDOM instance for each test
|
||||
dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
|
||||
const window = setupDOMEnvironment();
|
||||
dom = { window };
|
||||
|
||||
// Mock the necessary global objects
|
||||
dom.window.Log = { log: jest.fn(), error: jest.fn() };
|
||||
// Additional setup for loadTranslations tests
|
||||
dom.window.Translator = {};
|
||||
dom.window.config = { language: "de" };
|
||||
|
||||
@@ -132,21 +147,16 @@ describe("translations", () => {
|
||||
}
|
||||
};
|
||||
|
||||
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
|
||||
|
||||
describe("parsing language files through the Translator class", () => {
|
||||
for (const language in translations) {
|
||||
it(`should parse ${language}`, async () => {
|
||||
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
dom.window.translations = translations;
|
||||
dom.window.eval(translatorJs);
|
||||
const window = setupDOMEnvironment();
|
||||
|
||||
await new Promise((resolve) => {
|
||||
dom.window.onload = resolve;
|
||||
window.onload = resolve;
|
||||
});
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const { Translator } = window;
|
||||
await Translator.load(mmm, translations[language], false);
|
||||
|
||||
expect(typeof Translator.translations[mmm.name]).toBe("object");
|
||||
@@ -178,14 +188,11 @@ describe("translations", () => {
|
||||
|
||||
// Function to initialize JSDOM and load translations
|
||||
const initializeTranslationDOM = (language) => {
|
||||
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
dom.window.translations = translations;
|
||||
dom.window.eval(translatorJs);
|
||||
const window = setupDOMEnvironment();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
dom.window.onload = async () => {
|
||||
const { Translator } = dom.window;
|
||||
window.onload = async () => {
|
||||
const { Translator } = window;
|
||||
await Translator.load(mmm, translations[language], false);
|
||||
resolve(Translator.translations[mmm.name]);
|
||||
};
|
||||
|
@@ -2,29 +2,38 @@ const helpers = require("../helpers/global-setup");
|
||||
const weatherHelper = require("../helpers/weather-setup");
|
||||
const { cleanupMockData } = require("../../utils/weather_mocker");
|
||||
|
||||
const CURRENT_WEATHER_CONFIG = "tests/configs/modules/weather/currentweather_default.js";
|
||||
const SUNRISE_DATE = "13 Jan 2019 00:30:00 GMT";
|
||||
const SUNSET_DATE = "13 Jan 2019 12:30:00 GMT";
|
||||
const SUN_EVENT_SELECTOR = ".weather .normal.medium span:nth-child(4)";
|
||||
const EXPECTED_SUNRISE_TEXT = "7:00 am";
|
||||
const EXPECTED_SUNSET_TEXT = "3:45 pm";
|
||||
|
||||
describe("Weather module", () => {
|
||||
afterEach(async () => {
|
||||
await helpers.stopApplication();
|
||||
await cleanupMockData();
|
||||
cleanupMockData();
|
||||
});
|
||||
|
||||
describe("Current weather with sunrise", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherHelper.startApp("tests/configs/modules/weather/currentweather_default.js", "13 Jan 2019 00:30:00 GMT");
|
||||
await weatherHelper.startApp(CURRENT_WEATHER_CONFIG, SUNRISE_DATE);
|
||||
});
|
||||
|
||||
it("should render sunrise", async () => {
|
||||
await expect(weatherHelper.getText(".weather .normal.medium span:nth-child(4)", "7:00 am")).resolves.toBe(true);
|
||||
const isSunriseRendered = await weatherHelper.getText(SUN_EVENT_SELECTOR, EXPECTED_SUNRISE_TEXT);
|
||||
expect(isSunriseRendered).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Current weather with sunset", () => {
|
||||
beforeAll(async () => {
|
||||
await weatherHelper.startApp("tests/configs/modules/weather/currentweather_default.js", "13 Jan 2019 12:30:00 GMT");
|
||||
await weatherHelper.startApp(CURRENT_WEATHER_CONFIG, SUNSET_DATE);
|
||||
});
|
||||
|
||||
it("should render sunset", async () => {
|
||||
await expect(weatherHelper.getText(".weather .normal.medium span:nth-child(4)", "3:45 pm")).resolves.toBe(true);
|
||||
const isSunsetRendered = await weatherHelper.getText(SUN_EVENT_SELECTOR, EXPECTED_SUNSET_TEXT);
|
||||
expect(isSunsetRendered).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -4,6 +4,21 @@ const helmet = require("helmet");
|
||||
const { JSDOM } = require("jsdom");
|
||||
const express = require("express");
|
||||
|
||||
/**
|
||||
* Helper function to setup DOM environment.
|
||||
* @param {string} scriptContent - The script content to evaluate
|
||||
* @returns {Promise<object>} The JSDOM window object
|
||||
*/
|
||||
async function setupDOMEnvironment (scriptContent) {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
|
||||
dom.window.eval(scriptContent);
|
||||
dom.window.Log = { log: jest.fn(), error: jest.fn() };
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
return dom.window;
|
||||
}
|
||||
|
||||
describe("Translator", () => {
|
||||
let server;
|
||||
const sockets = new Set();
|
||||
@@ -81,12 +96,8 @@ describe("Translator", () => {
|
||||
};
|
||||
|
||||
it("should return custom module translation", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
setTranslations(Translator);
|
||||
|
||||
let translation = Translator.translate({ name: "MMM-Module" }, "Hello");
|
||||
@@ -97,12 +108,8 @@ describe("Translator", () => {
|
||||
});
|
||||
|
||||
it("should return core translation", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
setTranslations(Translator);
|
||||
let translation = Translator.translate({ name: "MMM-Module" }, "FOO");
|
||||
expect(translation).toBe("Foo");
|
||||
@@ -111,48 +118,32 @@ describe("Translator", () => {
|
||||
});
|
||||
|
||||
it("should return custom module translation fallback", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "A key");
|
||||
expect(translation).toBe("A translation");
|
||||
});
|
||||
|
||||
it("should return core translation fallback", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "Fallback");
|
||||
expect(translation).toBe("core fallback");
|
||||
});
|
||||
|
||||
it("should return translation with placeholder for missing variables", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
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", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
setTranslations(Translator);
|
||||
const translation = Translator.translate({ name: "MMM-Module" }, "MISSING");
|
||||
expect(translation).toBe("MISSING");
|
||||
@@ -168,12 +159,8 @@ describe("Translator", () => {
|
||||
};
|
||||
|
||||
it("should load translations", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
const file = "translation_test.json";
|
||||
|
||||
await Translator.load(mmm, file, false);
|
||||
@@ -182,30 +169,20 @@ describe("Translator", () => {
|
||||
});
|
||||
|
||||
it("should load translation fallbacks", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
const file = "translation_test.json";
|
||||
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
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 dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
const { Translator } = window;
|
||||
const file = "translation_test.json";
|
||||
|
||||
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
Translator.translationsFallback[mmm.name] = {
|
||||
Hello: "Hallo"
|
||||
};
|
||||
@@ -220,13 +197,9 @@ describe("Translator", () => {
|
||||
|
||||
describe("loadCoreTranslations", () => {
|
||||
it("should load core translations and fallback", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
dom.window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
|
||||
const { Translator } = window;
|
||||
await Translator.loadCoreTranslations("en");
|
||||
|
||||
const en = translationTestData;
|
||||
@@ -238,13 +211,9 @@ describe("Translator", () => {
|
||||
});
|
||||
|
||||
it("should load core fallback if language cannot be found", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
dom.window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
|
||||
const { Translator } = window;
|
||||
await Translator.loadCoreTranslations("MISSINGLANG");
|
||||
|
||||
const en = translationTestData;
|
||||
@@ -258,13 +227,9 @@ describe("Translator", () => {
|
||||
|
||||
describe("loadCoreTranslationsFallback", () => {
|
||||
it("should load core translations fallback", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
dom.window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
|
||||
const { Translator } = window;
|
||||
await Translator.loadCoreTranslationsFallback();
|
||||
|
||||
const en = translationTestData;
|
||||
@@ -275,14 +240,9 @@ describe("Translator", () => {
|
||||
});
|
||||
|
||||
it("should load core fallback if language cannot be found", async () => {
|
||||
const dom = new JSDOM("", { runScripts: "outside-only" });
|
||||
dom.window.eval(translatorJsScriptContent);
|
||||
dom.window.translations = {};
|
||||
dom.window.Log = { log: jest.fn() };
|
||||
|
||||
await new Promise((resolve) => dom.window.onload = resolve);
|
||||
|
||||
const { Translator } = dom.window;
|
||||
const window = await setupDOMEnvironment(translatorJsScriptContent);
|
||||
window.translations = {};
|
||||
const { Translator } = window;
|
||||
await Translator.loadCoreTranslations();
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
@@ -10,7 +10,7 @@ describe("Calendar fetcher utils test", () => {
|
||||
excludedEvents: [],
|
||||
includePastEvents: false,
|
||||
maximumEntries: 10,
|
||||
maximumNumberOfDays: 365
|
||||
maximumNumberOfDays: 367
|
||||
};
|
||||
|
||||
describe("filterEvents", () => {
|
||||
@@ -53,7 +53,6 @@ describe("Calendar fetcher utils test", () => {
|
||||
expect(filteredEvents[1].title).toBe("upcomingEvent");
|
||||
});
|
||||
|
||||
/*
|
||||
it("should return the correct times when recurring events pass through daylight saving time", () => {
|
||||
const data = ical.parseICS(`BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Amsterdam:20250311T090000
|
||||
@@ -87,7 +86,6 @@ END:VEVENT`);
|
||||
expect(januaryFirst[0].startDate).toEqual(januaryMoment.format("x"));
|
||||
expect(julyFirst[0].startDate).toEqual(julyMoment.format("x"));
|
||||
});
|
||||
*/
|
||||
|
||||
it("should return the correct moments based on the timezone given", () => {
|
||||
const data = ical.parseICS(`BEGIN:VEVENT
|
||||
|
@@ -1,7 +1,6 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const util = require("node:util");
|
||||
const exec = util.promisify(require("node:child_process").exec);
|
||||
const exec = require("node:child_process").execSync;
|
||||
|
||||
/**
|
||||
* @param {string} type what data to read, can be "current" "forecast" or "hourly
|
||||
@@ -45,9 +44,9 @@ const injectMockData = (configFileName, extendedData = {}) => {
|
||||
return tempFile;
|
||||
};
|
||||
|
||||
const cleanupMockData = async () => {
|
||||
const cleanupMockData = () => {
|
||||
const tempDir = path.resolve(`${__dirname}/../configs`).toString();
|
||||
await exec(`find ${tempDir} -type f -name *_temp.js -delete`);
|
||||
exec(`find ${tempDir} -type f -name *_temp.js -delete`);
|
||||
};
|
||||
|
||||
module.exports = { injectMockData, cleanupMockData };
|
||||
|
Reference in New Issue
Block a user