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?
seems we dont need the parse5 pin as long as jsdom is fixed to v27.0.0.
not sure if there is anything else we can do to the deps?
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
## Description
This PR adds a new `server:watch` script that runs MagicMirror² in
server-only mode with automatic restart and browser reload capabilities.
Particularly helpful for:
- **Developers** who need to see changes immediately without manual
restarts.
- **Users setting up their mirror** who make many changes to `config.js`
or `custom.css` and need quick feedback.
### What it does
When you run `npm run server:watch`, the watcher monitors files you
specify in `config.watchTargets`. Whenever a monitored file changes:
1. The server automatically restarts
2. Waits for the port to become available
3. Sends a reload notification to all connected browsers via Socket.io
4. Browsers automatically refresh to show the changes
This creates a seamless development experience where you can edit code,
save, and see the results within seconds.
### Implementation highlights
**Zero dependencies:** Uses only Node.js built-ins (`fs.watch`,
`child_process.spawn`, `net`, `http`) - no nodemon or external watchers
needed.
**Smart file watching:** Monitors parent directories instead of files
directly to handle atomic writes from modern editors (VSCode, etc.) that
create temporary files during save operations.
**Port management:** Waits for the old server instance to fully release
the port before starting a new one, preventing "port already in use"
errors.
### Configuration
Users explicitly define which files to monitor in their `config.js`:
```js
let config = {
watchTargets: [
"config/config.js",
"css/custom.css",
"modules/MMM-MyModule/MMM-MyModule.js",
"modules/MMM-MyModule/node_helper.js"
],
// ... rest of config
};
```
This explicit approach keeps the implementation simple (~260 lines)
while giving users full control over what triggers restarts. If
`watchTargets` is empty or undefined, the watcher starts but monitors
nothing, logging a clear warning message.
---
**Note:** This PR description has been updated to reflect the final
implementation. During the review process, we refined the approach
multiple times based on feedback.
---------
Co-authored-by: Jboucly <contact@jboucly.fr>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
This is just to reduce a little noise in the dev console. The following
line will not appear with this change:
```shell
module.js:480 Check MagicMirror² version for module 'calendar' - Minimum version: 2.1.0 - Current version: 2.34.0-
```
Since version 2.1.0 is so old, we can surely throw it out without
concern.
- Combine file existence and permission checks with better error
messages
- Replace thrown exceptions with clean error output (no stack traces)
- Support custom module positions by changing strict validation to
warnings
- Add missing process.exit(1) after validation errors
Users now see clear, actionable error messages without stack traces, and
custom region configurations work correctly.
## example before
```bash
$ npm run start
> magicmirror@2.34.0-develop start
> node --run start:x11
[2025-10-22 17:56:06.303] [LOG] Starting MagicMirror: v2.34.0-develop
[2025-10-22 17:56:06.304] [LOG] Loading config ...
[2025-10-22 17:56:06.304] [LOG] config template file not exists, no envsubst
[2025-10-22 17:56:06.356] [ERROR] File not found: /home/kristjan/MagicMirror/config/config.js
No config file present!
[2025-10-22 17:56:06.356] [ERROR] [checkconfig] Error: Error: ENOENT: no such file or directory, access '/home/kristjan/MagicMirror/config/config.js'
No permission to access config file!
at checkConfigFile (/home/kristjan/MagicMirror/js/check_config.js:43:9)
at Object.<anonymous> (/home/kristjan/MagicMirror/js/check_config.js:138:2)
at Module._compile (node:internal/modules/cjs/loader:1714:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1848:10)
at Module.load (node:internal/modules/cjs/loader:1448:32)
at Module._load (node:internal/modules/cjs/loader:1270:12)
at c._load (node:electron/js2c/node_init:2:17993)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:244:24)
at Module.require (node:internal/modules/cjs/loader:1470:12)
at require (node:internal/modules/helpers:147:16)
at loadConfig (/home/kristjan/MagicMirror/js/app.js:126:3)
at App.start (/home/kristjan/MagicMirror/js/app.js:291:18)
at Object.<anonymous> (/home/kristjan/MagicMirror/js/electron.js:228:7)
at Module._compile (node:internal/modules/cjs/loader:1714:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1848:10)
```
## example after
```bash
$ npm run start
> magicmirror@2.34.0-develop start
> node --run start:x11
[2025-10-22 21:33:27.930] [LOG] Starting MagicMirror: v2.34.0-develop
[2025-10-22 21:33:27.931] [LOG] Loading config ...
[2025-10-22 21:33:27.931] [LOG] config template file not exists, no envsubst
[2025-10-22 21:33:27.985] [ERROR] [check_config] File not found: /home/kristjan/MagicMirror/config/config.js
```
Remove the "Recurring event per timezone" test that manipulated
Date.prototype.getTimezoneOffset to simulate 24 different timezones for
testing all-day recurring events.
Reasons for removal:
1. The test approach is incompatible with node-ical 0.22.0's Intl-based
timezone handling (which replaced moment-timezone). Manipulating
Date.prototype.getTimezoneOffset no longer affects Intl.DateTimeFormat,
which reads the system timezone directly.
2. node-ical 0.22.0 handles all-day events (VALUE=DATE) correctly by
preserving the calendar date without timezone conversions, making
cross-timezone testing unnecessary. The library includes comprehensive
tests for this behavior, particularly "keeps whole-day recurrence across
DST" in
[test/advanced.test.js](https://github.com/jens-maus/node-ical/blob/master/test/advanced.test.js).
3. The existing "Recurring event" test already verifies that recurring
events from the same ICS file are displayed correctly, so a simplified
version of "Recurring event per timezone" is not necessary.
The old test attempted to work around timezone conversion issues in
node-ical 0.21.0 that are now properly resolved upstream.
Closes#3928
Normally, I wouldn't update the dependencies again so soon, but
`node-ical` underwent some major changes (see
https://github.com/jens-maus/node-ical/pull/404) with the last release,
and I'd like to use it here as early as possible to see if there are any
problems with it.
The envcanada provider in the default Weather module was fixed in MM
v2.33.0 to use a new URL hierarchy that Environment Canada implemented
to access weather data for Canadian locations. Subsequent to this
provider update, Environment Canada has implemented one further update
to their URL hierarchy to make it easier to access 'current day' weather
data. Tis change was raised in Issue #3912 as a Bug, which is addressed
in this Provider update. There are no Magic Mirror UI changes from this
update.
The fix is to add one additional element to the URL used to access
Environment Canada XML-based weather data.
This PR is also taking the opportunity to make one further small fix to
how windspeed is handled in this Provider. Most of the time, Env Canada
provides an expected numeric value. There are instances, however, where
the value provided is 'calm', which the Weather module does not expect.
The Provider code has been changed to detect a 'calm' windspeed and
convert it to '0' for the purposes of the Weather module. Note that in
the world of weather/climate analysis, a windspeed of 'calm' is used as
a synonym for a windspeed of 0.
Note that a ChangeLog entry is included in this PR.
This fixes security issue
[CVE-2023-42282](https://github.com/advisories/GHSA-78xj-cgh5-2h22),
which is not very likely to be exploitable in MagicMirror² setups, but
still should be fixed.
The [express-ipfilter](https://www.npmjs.com/package/express-ipfilter)
package depends on the obviously unmaintained
[ip](https://github.com/indutny/node-ip) package, which has known
security vulnerabilities. Since no fix is available, this commit
replaces both dependencies with a custom middleware using the better
maintained [ipaddr.js](https://www.npmjs.com/package/ipaddr.js) library.
Changes:
- Add new `js/ip_access_control.js` with lightweight middleware
- Remove `express-ipfilter` dependency, add `ipaddr.js`
- Update `js/server.js` to use new middleware
- In addition, I have formulated the descriptions of the corresponding
tests a little more clearly.
Adding a rule to the config checker config so that unexpected commas in
the middle of arrays (reported in issue #3910) are better detected.
Two commas in a row inside the modules array create an empty entry
(`undefined`). JavaScript accepts that syntax, but MagicMirror would
later try to load that “module” and fail.
Alternatively, we could filter out undefined entries, but with this PR,
the user receives a clear message indicating where the error lies, can
easily fix it, and thus has a cleaner configuration.
## Before
```
[2025-10-10 19:33:30.874] [INFO] Checking config file /home/kristjan/MagicMirror/config/config.js ...
[2025-10-10 19:33:30.944] [INFO] Your configuration file doesn't contain syntax errors :)
[2025-10-10 19:33:30.945] [INFO] Checking modules structure configuration ...
[2025-10-10 19:33:31.027] [ERROR] This module configuration contains errors:
undefinedmust be object
```
## After
```
[2025-10-10 19:41:20.030] [INFO] Checking config file /home/kristjan/MagicMirror/config/config.js ...
[2025-10-10 19:41:20.107] [ERROR] Your configuration file contains syntax errors :(
Line 91 column 1: Unexpected comma in middle of array.
```
- removes the external unmaintained `module-alias` dependency ->
reducing complexity and risk
- introduces a small internal alias mechanism for `logger` and
`node_helper`
- preserves backward compatibility for existing 3rd‑party modules
- should simplify a future ESM migration of MagicMirror
I'm confident that it shouldn't cause any problems, but we could also
consider including it in the release after next. What do you think?
This PR is inspired by PR #2934 - so thanks to @thesebas! 🙇😃
Earlier in 2025, Environment Canada changed the process to access
weather data for Canadian cities. This change was raised in Issue #3822
as a Bug, which is addressed in this Provider update. There are no Magic
Mirror UI changes from this update.
The 'old' method to access Environment Canada involved accessing a
static URL based on a City identifier which would result in an XML
document containing the appropriate weather data.
The 'new' method is a 2 step process. The first step is to access a
time-sensitive URL that contains a list of links to various cities that
have weather data available. The second step requires finding the
correct city in that list based on a City identifier, and then accessing
that unique URL to access an XML document containing the appropriate
weather data.
The changes made to the envcanada Provider code are solely aimed at
using the new 2-step method to access a specified City's weather data.
Since the resulting XML document structure has not changed, no other
code in envcanada required changes.
Note that a ChangeLog entry is included in this PR.
---------
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
Having repeatedly seen that users are unaware of the meaning of the
EADDRINUSE error message (see, for example, this [forum
thread](https://forum.magicmirror.builders/topic/19871/update-package-list/5)),
I thought we should intercept this message and provide clearer output.
This may help users identify the cause of the problem more quickly
themselves.
## before
```
[2025-09-13 09:54:32.903] [LOG] Starting MagicMirror: v2.33.0-develop
...
[2025-09-13 09:54:33.533] [LOG] Starting server on port 8080 ...
[2025-09-13 09:54:33.537] [WARN] You're using a full whitelist configuration to allow for all IPs
[2025-09-13 09:54:33.568] [ERROR] Whoops! There was an uncaught exception...
[2025-09-13 09:54:33.574] [ERROR] Error: listen EADDRINUSE: address already in use 0.0.0.0:8080
at Server.setupListenHandle [as _listen2] (node:net:1940:16)
at listenInCluster (node:net:1997:12)
at node:net:2206:7
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '0.0.0.0',
port: 8080
}
[2025-09-13 09:54:33.574] [ERROR] MagicMirror² will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?
[2025-09-13 09:54:33.574] [ERROR] If you think this really is an issue, please open an issue on GitHub: https://github.com/MagicMirrorOrg/MagicMirror/issues
[2025-09-13 09:54:35.235] [INFO]
#### System Information ####
...
```
## after
```
[2025-09-13 09:53:20.151] [LOG] Starting MagicMirror: v2.33.0-develop
...
[2025-09-13 09:53:20.928] [LOG] Starting server on port 8080 ...
[2025-09-13 09:53:20.931] [WARN] You're using a full whitelist configuration to allow for all IPs
[2025-09-13 09:53:20.970] [ERROR]
────────────────────────────────────────────────────────────────
PORT IN USE: 0.0.0.0:8080
Another process (most likely another MagicMirror instance)
is already using this port.
Stop the other process (free the port) or use a different port.
────────────────────────────────────────────────────────────────
[2025-09-13 09:53:22.471] [INFO]
#### System Information ####
...
```
This prevents `prettier` from failing when `lint-staged` passes
unknown/binary files, making the pre-commit hook more robust.
In concrete terms this could happen, when we, for example, add a new PNG
file. Since we rarely do this, it has not been noticed so far.
This is recommended when using asterisk:
https://github.com/lint-staged/lint-staged#automatically-fix-code-style-with-prettier-for-any-format-prettier-supports
## before
```bash
$ npx lint-staged <-- after staging a new PNG file
✔ Backed up original state in git stash (c3247d4b)
✔ Hiding unstaged changes to partially staged files...
⚠ Running tasks for staged files...
❯ package.json — 2 files
❯ * — 2 files
✖ prettier --write [FAILED]
↓ *.js — no files
↓ *.css — no files
↓ Skipped because of errors from tasks.
↓ Skipped because of errors from tasks.
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...
✖ prettier --write:
[error] No parser could be inferred for file "~/MagicMirror/test.png".
...
```
## after
```bash
$ npx lint-staged <-- after staging a new PNG file
✔ Backed up original state in git stash (0c3fe285)
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
```
electron uses node v22.18 in its [current
releases](https://releases.electronjs.org/), so we should go hand in
hand and use that as the minimal node version
nothing fancy in these though
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
The current logic never showed any different temperature than the
current one, so I looked into a more "explained" formula and found one
in the HomeAssistant forums.
- Remove `sinon` dependency in favor of Jest native mocking
- Unify test helper functions across translation test suites
- Rename `setupDOMEnvironment` to `createTranslationTestEnvironment` for
consistency
- Simplify DOM setup by removing unnecessary Promise/async patterns
- Avoid potential port conflicts by using port 3001 for translator unit
tests
- Improve test reliability and maintainability
socket.io times out and closes the client side socket without any
callback
sendSocntNotification() from the server side data is lost as the socket
is closed. but the client doesn't know
increase the timeout
fixes#3380
This is not a cosmetic change because jest errors when run with
`CI=true`.
I got this error when running unit tests in gitlab:
```bash
FAIL unit tests/unit/functions/updatenotification_spec.js
● Test suite failed to run
Outdated guide link: The snapshot guide link is outdated.Please update all snapshots while upgrading of Jest
Expected: https://jestjs.io/docs/snapshot-testing
Received: https://goo.gl/fbAQLP
at validateSnapshotHeader (node_modules/@jest/snapshot-utils/build/index.js:104:12)
at getSnapshotData (node_modules/@jest/snapshot-utils/build/index.js:156:28)
```
If you run the test without `CI=true` jest will update the file.
Fixes#3253
Adds a configuration option to overwrite the default `User-Agent` header
that is send at least by the calendar and news module. Allows other
modules to use the individual user agent as well.
The configuration accepts either a string or a function:
```
var config =
{
...
userAgent: 'Mozilla/5.0 (My User Agent)',
...
}
```
or
```
var config =
{
...
userAgent: () => 'Mozilla/5.0 (My User Agent)',
...
}
```
---------
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>