mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 03:39:55 +00:00
commit
9e0293047f
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@ -20,9 +20,7 @@ If you are facing an issue or found a bug while trying to install MagicMirror²
|
|||||||
## I found a bug in the MagicMirror² Docker image
|
## I found a bug in the MagicMirror² Docker image
|
||||||
|
|
||||||
If you are facing an issue or found a bug while running MagicMirror² inside a Docker container please create an issue in the corresponding repository:
|
If you are facing an issue or found a bug while running MagicMirror² inside a Docker container please create an issue in the corresponding repository:
|
||||||
|
[https://gitlab.com/khassel/magicmirror](https://gitlab.com/khassel/magicmirror)
|
||||||
- karsten13/magicmirror: [https://gitlab.com/khassel/magicmirror](https://gitlab.com/khassel/magicmirror)
|
|
||||||
- (deprecated) bastilimbach/docker-magicmirror: [https://github.com/bastilimbach/docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
4
.github/workflows/automated-tests.yaml
vendored
4
.github/workflows/automated-tests.yaml
vendored
@ -23,7 +23,7 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
@ -31,7 +31,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
Xvfb :99 -screen 0 1024x768x16 &
|
Xvfb :99 -screen 0 1024x768x16 &
|
||||||
export DISPLAY=:99
|
export DISPLAY=:99
|
||||||
npm install
|
npm run install-mm:dev
|
||||||
touch css/custom.css
|
touch css/custom.css
|
||||||
npm run test:prettier
|
npm run test:prettier
|
||||||
npm run test:js
|
npm run test:js
|
||||||
|
2
.github/workflows/codecov-test-suites.yaml
vendored
2
.github/workflows/codecov-test-suites.yaml
vendored
@ -27,7 +27,7 @@ jobs:
|
|||||||
touch css/custom.css
|
touch css/custom.css
|
||||||
npm run test:coverage
|
npm run test:coverage
|
||||||
- name: Upload coverage results to codecov
|
- name: Upload coverage results to codecov
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
files: ./coverage/lcov.info
|
files: ./coverage/lcov.info
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
|
100
CHANGELOG.md
100
CHANGELOG.md
@ -5,6 +5,38 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror².
|
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror².
|
||||||
|
|
||||||
|
## [2.21.0] - 2022-10-01
|
||||||
|
|
||||||
|
Special thanks to: @BKeyport, @buxxi, @davide125, @khassel, @kolbyjack, @krukle, @MikeBishop, @rejas, @sdetweil, @SkySails and @veeck
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Possibility to fetch calendars through socket notifications.
|
||||||
|
- New scripts `install-mm` (and `install-mm:dev`) for simplifying mm installation (now: `npm run install-mm`) and adding params `--no-audit --no-fund --no-update-notifier` for less noise.
|
||||||
|
- New `showTimeToday` option in calendar module shows time for current-day events even if `timeFormat` is `"relative"`.
|
||||||
|
- Add hourly forecasts, apparent temperature & custom location name to SMHI weather provider.
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- Old weather deprecated modules `currentweather` and `weatherforecast`.
|
||||||
|
|
||||||
|
## Updated
|
||||||
|
|
||||||
|
- Removed `DAYAFTERTOMORROW` from English.
|
||||||
|
- Update dependencies.
|
||||||
|
- Updated jsdoc.
|
||||||
|
- Updated font tree to use variables consistantly.
|
||||||
|
- Removed deprecated Docker Repository from issue template.
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Broadcast all calendar events while still honoring global and per-calendar maximumEntries.
|
||||||
|
- Respect rss ttl provided by newsfeed (#2883).
|
||||||
|
- Fix multi day calendar events always presented as "(1/X)" instead of the amount of days the event has progressed.
|
||||||
|
- Fix weatherbit provider to use type config value instead of endpoint.
|
||||||
|
- Fix calendar events which DO NOT specify rrule byday adjusted incorrectly (#2885).
|
||||||
|
- Fix e2e tests not failing on errors (#2911).
|
||||||
|
|
||||||
## [2.20.0] - 2022-07-02
|
## [2.20.0] - 2022-07-02
|
||||||
|
|
||||||
Special thanks to the following contributors: @eouia, @khassel, @kolbyjack, @KristjanESPERANTO, @nathannaveen, @naveensrinivasan, @rejas, @rohitdharavath and @sdetweil.
|
Special thanks to the following contributors: @eouia, @khassel, @kolbyjack, @KristjanESPERANTO, @nathannaveen, @naveensrinivasan, @rejas, @rohitdharavath and @sdetweil.
|
||||||
@ -13,13 +45,13 @@ Special thanks to the following contributors: @eouia, @khassel, @kolbyjack, @Kri
|
|||||||
|
|
||||||
- Added a new config option `httpHeaders` used by helmet (see https://helmetjs.github.io/). You can now set own httpHeaders which will override the defaults in `js/defauls.js` which is useful e.g. if you want to embed MagicMirror into annother website (solves #2847).
|
- Added a new config option `httpHeaders` used by helmet (see https://helmetjs.github.io/). You can now set own httpHeaders which will override the defaults in `js/defauls.js` which is useful e.g. if you want to embed MagicMirror into annother website (solves #2847).
|
||||||
- Show endDate for calendar events when dateHeader is enabled and showEnd is set to true (#2192).
|
- Show endDate for calendar events when dateHeader is enabled and showEnd is set to true (#2192).
|
||||||
- Added the notification emitting from the weather module on infromation updated.
|
- Added the notification emitting from the weather module on information updated.
|
||||||
- Use recommended file extention for YAML files (#2864).
|
- Use recommended file extension for YAML files (#2864).
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Use latest node 18 when running tests on github actions.
|
- Use latest node 18 when running tests on github actions.
|
||||||
- Update `electron` to v19 and other dependencies.
|
- Updated `electron` to v19 and other dependencies.
|
||||||
- Use internal fetch function of node instead external `node-fetch` library if used node version >= `v18`.
|
- Use internal fetch function of node instead external `node-fetch` library if used node version >= `v18`.
|
||||||
- Include duplicate events in broadcasts.
|
- Include duplicate events in broadcasts.
|
||||||
|
|
||||||
@ -45,12 +77,12 @@ Special thanks to the following contributors: @10bias, @CFenner, @JHWelch, @k1rd
|
|||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Deprecated roboto fonts package `roboto-fontface-bower` replaced with `fontsource`.
|
- Deprecated roboto fonts package `roboto-fontface-bower` replaced with `fontsource`.
|
||||||
- Update `electron` to v17, `helmet` to v5 (use defaults of v4) and other dependencies
|
- Updated `electron` to v17, `helmet` to v5 (use defaults of v4) and other dependencies
|
||||||
- Updates Font Awesome css class to new default style (fixes #2768)
|
- Updated Font Awesome css class to new default style (fixes #2768)
|
||||||
- Replaced deprecated modules `currentweather` and `weatherforecast` with dummy modules only displaying that they have to be replaced.
|
- Replaced deprecated modules `currentweather` and `weatherforecast` with dummy modules only displaying that they have to be replaced.
|
||||||
- Include all calendar events from the configured date range when broadcasting.
|
- Include all calendar events from the configured date range when broadcasting.
|
||||||
- Update Danish and German translation.
|
- Updated Danish and German translation.
|
||||||
- Update `node-ical` to v0.15 and added `luxon` as dependency for not breaking the "no-optional" install (see #2718 and #2824).
|
- Updated `node-ical` to v0.15 and added `luxon` as dependency for not breaking the "no-optional" install (see #2718 and #2824).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -76,8 +108,8 @@ Special thanks to the following contributors: @AmpioRosso, @eouia, @fewieden, @j
|
|||||||
- ESLint version supports now ECMAScript 2018.
|
- ESLint version supports now ECMAScript 2018.
|
||||||
- Cleaned up `updatenotification` module and switched to nunjuck template.
|
- Cleaned up `updatenotification` module and switched to nunjuck template.
|
||||||
- Moved calendar tests from category `electron` to `e2e`.
|
- Moved calendar tests from category `electron` to `e2e`.
|
||||||
- Update missed translations for Korean language (ko.json).
|
- Updated missed translations for Korean language (ko.json).
|
||||||
- Update missed translations for Dutch language (nl.json).
|
- Updated missed translations for Dutch language (nl.json).
|
||||||
- Cleaned up `alert` module and switched to nunjuck template.
|
- Cleaned up `alert` module and switched to nunjuck template.
|
||||||
- Moved weather tests from category `electron` to `e2e`.
|
- Moved weather tests from category `electron` to `e2e`.
|
||||||
- Updated github actions.
|
- Updated github actions.
|
||||||
@ -128,14 +160,14 @@ Special thanks to the following contributors: @apiontek, @eouia, @jupadin, @khas
|
|||||||
- Refactor test configs, use default test config for all tests.
|
- Refactor test configs, use default test config for all tests.
|
||||||
- Updated github templates.
|
- Updated github templates.
|
||||||
- Actually test all js and css files when lint script is run.
|
- Actually test all js and css files when lint script is run.
|
||||||
- Update jsdocs and print warnings during testing too.
|
- Updated jsdocs and print warnings during testing too.
|
||||||
- Update weathergov provider to try fetching not just current, but also foreacst, when API URLs available.
|
- Updated weathergov provider to try fetching not just current, but also foreacst, when API URLs available.
|
||||||
- Refactored clock layout.
|
- Refactored clock layout.
|
||||||
- Refactored methods from weatherproviders into weatherobject (isDaytime, updateSunTime).
|
- Refactored methods from weatherproviders into weatherobject (isDaytime, updateSunTime).
|
||||||
- Use of `logger.js` in jest tests.
|
- Use of `logger.js` in jest tests.
|
||||||
- Run prettier over all relevant files.
|
- Run prettier over all relevant files.
|
||||||
- Move tests needing electron in new category `electron`, use `server only` mode in `e2e` tests.
|
- Move tests needing electron in new category `electron`, use `server only` mode in `e2e` tests.
|
||||||
- Update dependencies in package.json.
|
- Updated dependencies in package.json.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -169,13 +201,13 @@ Special thanks to the following contributors: @210954, @B1gG, @codac, @Crazylegs
|
|||||||
- Refactor code into es6 where possible (e.g. var -> let/const).
|
- Refactor code into es6 where possible (e.g. var -> let/const).
|
||||||
- Use node v16 in github workflow (replacing node v10).
|
- Use node v16 in github workflow (replacing node v10).
|
||||||
- Moved some files into better suited directories.
|
- Moved some files into better suited directories.
|
||||||
- Update dependencies in package.json, require node >= v12, remove `rrule-alt` and `rrule`.
|
- Updated dependencies in package.json, require node >= v12, remove `rrule-alt` and `rrule`.
|
||||||
- Update dependencies in package.json and migrate husky to v6, fix husky setup in prod environment.
|
- Updated dependencies in package.json and migrate husky to v6, fix husky setup in prod environment.
|
||||||
- Cleaned up error handling in newsfeed and calendar modules for real.
|
- Cleaned up error handling in newsfeed and calendar modules for real.
|
||||||
- Updated default WEATHER module such that a provider can optionally set a custom unit-of-measure for precipitation (`weatherObject.precipitationUnits`).
|
- Updated default WEATHER module such that a provider can optionally set a custom unit-of-measure for precipitation (`weatherObject.precipitationUnits`).
|
||||||
- Update documentation.
|
- Updated documentation.
|
||||||
- Update jest tests: Reset changes on js/logger.js, mock logger.js in global_vars tests.
|
- Updated jest tests: Reset changes on js/logger.js, mock logger.js in global_vars tests.
|
||||||
- Update dependencies in package.json.
|
- Updated dependencies in package.json.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
@ -287,10 +319,10 @@ Special thanks to the following contributors: @Alvinger, @AndyPoms, @ashishtank,
|
|||||||
|
|
||||||
- Merging .gitignore in the config-folder with the .gitignore in the root-folder.
|
- Merging .gitignore in the config-folder with the .gitignore in the root-folder.
|
||||||
- Weather module - forecast now show TODAY and TOMORROW instead of weekday, to make it easier to understand.
|
- Weather module - forecast now show TODAY and TOMORROW instead of weekday, to make it easier to understand.
|
||||||
- Update dependencies to latest versions.
|
- Updated dependencies to latest versions.
|
||||||
- Update dependencies eslint, feedme, simple-git and socket.io to latest versions.
|
- Updated dependencies eslint, feedme, simple-git and socket.io to latest versions.
|
||||||
- Update lithuanian translation.
|
- Updated lithuanian translation.
|
||||||
- Update config sample.
|
- Updated config sample.
|
||||||
- Highlight required version mismatch.
|
- Highlight required version mismatch.
|
||||||
- No select Text for TouchScreen use.
|
- No select Text for TouchScreen use.
|
||||||
- Corrected logic for timeFormat "relative" and "absolute".
|
- Corrected logic for timeFormat "relative" and "absolute".
|
||||||
@ -318,12 +350,12 @@ Special thanks to the following contributors: @Alvinger, @AndyPoms, @ashishtank,
|
|||||||
- Catch errors when parsing calendar data with ical. (#2022)
|
- Catch errors when parsing calendar data with ical. (#2022)
|
||||||
- Fix Default Alert Module does not hide black overlay when alert is dismissed manually. (#2228)
|
- Fix Default Alert Module does not hide black overlay when alert is dismissed manually. (#2228)
|
||||||
- Weather module - Always displays night icons when local is other than English. (#2221)
|
- Weather module - Always displays night icons when local is other than English. (#2221)
|
||||||
- Update node-ical 0.12.4, fix invalid RRULE format in cal entries
|
- Updated node-ical 0.12.4, fix invalid RRULE format in cal entries
|
||||||
- Fix package.json for optional electron dependency (2378)
|
- Fix package.json for optional electron dependency (2378)
|
||||||
- Update node-ical version again, 0.12.5, change RRULE fix (#2371, #2379)
|
- Updated node-ical version again, 0.12.5, change RRULE fix (#2371, #2379)
|
||||||
- Remove undefined objects from modules array (#2382)
|
- Remove undefined objects from modules array (#2382)
|
||||||
- Update node-ical version again, 0.12.7, change RRULE fix (#2371, #2379), node-ical now throws error (which we catch)
|
- Updated node-ical version again, 0.12.7, change RRULE fix (#2371, #2379), node-ical now throws error (which we catch)
|
||||||
- Update simple-git version to 2.31 unhandled promise rejection (#2383)
|
- Updated simple-git version to 2.31 unhandled promise rejection (#2383)
|
||||||
|
|
||||||
## [2.13.0] - 2020-10-01
|
## [2.13.0] - 2020-10-01
|
||||||
|
|
||||||
@ -548,10 +580,10 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
|
|
||||||
- English translation for "Feels" to "Feels like"
|
- English translation for "Feels" to "Feels like"
|
||||||
- Fixed the example calendar url in `config.js.sample`
|
- Fixed the example calendar url in `config.js.sample`
|
||||||
- Update `ical.js` to solve various calendar issues.
|
- Updated `ical.js` to solve various calendar issues.
|
||||||
- Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
|
- Updated weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
|
||||||
- Only update clock once per minute when seconds aren't shown
|
- Only update clock once per minute when seconds aren't shown
|
||||||
- Update weatherprovider documentation.
|
- Updated weatherprovider documentation.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -571,7 +603,7 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
- use current username vs hardcoded 'pi' to support non-pi install
|
- use current username vs hardcoded 'pi' to support non-pi install
|
||||||
- check for npm installed. node install doesn't do npm anymore
|
- check for npm installed. node install doesn't do npm anymore
|
||||||
- check for mac as part of PM2 install, add install option string
|
- check for mac as part of PM2 install, add install option string
|
||||||
- update pm2 config with current username instead of hard coded 'pi'
|
- Updated pm2 config with current username instead of hard coded 'pi'
|
||||||
- check for screen saver config, "/etc/xdg/lxsession", bypass if not setup
|
- check for screen saver config, "/etc/xdg/lxsession", bypass if not setup
|
||||||
|
|
||||||
## [2.7.1] - 2019-04-02
|
## [2.7.1] - 2019-04-02
|
||||||
@ -779,7 +811,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add types for module.
|
- Add types for module.
|
||||||
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
|
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
|
||||||
- Allow scrolling in full page article view of default newsfeed module with gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
- Allow scrolling in full page article view of default newsfeed module with gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
||||||
- Changed 'compliments.js' - update DOM if remote compliments are loaded instead of waiting one updateInterval to show custom compliments
|
- Changed 'compliments.js' - Updated DOM if remote compliments are loaded instead of waiting one updateInterval to show custom compliments
|
||||||
- Automated unit tests utils, deprecated, translator, cloneObject(lockstrings)
|
- Automated unit tests utils, deprecated, translator, cloneObject(lockstrings)
|
||||||
- Automated integration tests translations
|
- Automated integration tests translations
|
||||||
- Add advanced filtering to the excludedEvents configuration of the default calendar module
|
- Add advanced filtering to the excludedEvents configuration of the default calendar module
|
||||||
@ -791,7 +823,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
|
|
||||||
- Add link to GitHub repository which contains the respective Dockerfile.
|
- Add link to GitHub repository which contains the respective Dockerfile.
|
||||||
- Optimized automated unit tests cloneObject, cmpVersions
|
- Optimized automated unit tests cloneObject, cmpVersions
|
||||||
- Update notifications use now translation templates instead of normal strings.
|
- Updated notifications use now translation templates instead of normal strings.
|
||||||
- Yarn can be used now as an installation tool
|
- Yarn can be used now as an installation tool
|
||||||
- Changed Electron dependency to v1.7.13.
|
- Changed Electron dependency to v1.7.13.
|
||||||
|
|
||||||
@ -998,7 +1030,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Update .gitignore to not ignore default modules folder.
|
- Updated .gitignore to not ignore default modules folder.
|
||||||
- Remove white flash on boot up.
|
- Remove white flash on boot up.
|
||||||
- Added `update` in Raspberry Pi installation script.
|
- Added `update` in Raspberry Pi installation script.
|
||||||
- Fix an issue where the analog clock looked scrambled. ([#611](https://github.com/MichMich/MagicMirror/issues/611))
|
- Fix an issue where the analog clock looked scrambled. ([#611](https://github.com/MichMich/MagicMirror/issues/611))
|
||||||
@ -1083,8 +1115,8 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Force fullscreen when kioskmode is active.
|
- Force fullscreen when kioskmode is active.
|
||||||
- Update the .github templates and information with more modern information.
|
- Updated the .github templates and information with more modern information.
|
||||||
- Update the Gruntfile with a more functional StyleLint implementation.
|
- Updated the Gruntfile with a more functional StyleLint implementation.
|
||||||
|
|
||||||
## [2.0.4] - 2016-08-07
|
## [2.0.4] - 2016-08-07
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# The MIT License (MIT)
|
# The MIT License (MIT)
|
||||||
|
|
||||||
Copyright © 2016-2021 Michael Teeuw
|
Copyright © 2016-2022 Michael Teeuw
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person
|
||||||
obtaining a copy of this software and associated documentation
|
obtaining a copy of this software and associated documentation
|
||||||
|
18
css/main.css
18
css/main.css
@ -8,7 +8,11 @@
|
|||||||
--font-secondary: "Roboto";
|
--font-secondary: "Roboto";
|
||||||
|
|
||||||
--font-size: 20px;
|
--font-size: 20px;
|
||||||
--font-size-small: 0.75rem;
|
--font-size-xsmall: 0.75rem;
|
||||||
|
--font-size-small: 1rem;
|
||||||
|
--font-size-medium: 1.5rem;
|
||||||
|
--font-size-large: 3.25rem;
|
||||||
|
--font-size-xlarge: 3.75rem;
|
||||||
|
|
||||||
--gap-body-top: 60px;
|
--gap-body-top: 60px;
|
||||||
--gap-body-right: 60px;
|
--gap-body-right: 60px;
|
||||||
@ -60,27 +64,27 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.xsmall {
|
.xsmall {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-xsmall);
|
||||||
line-height: 1.275;
|
line-height: 1.275;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
font-size: 1rem;
|
font-size: var(--font-size-small);
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium {
|
.medium {
|
||||||
font-size: 1.5rem;
|
font-size: var(--font-size-medium);
|
||||||
line-height: 1.225;
|
line-height: 1.225;
|
||||||
}
|
}
|
||||||
|
|
||||||
.large {
|
.large {
|
||||||
font-size: 3.25rem;
|
font-size: var(--font-size-large);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xlarge {
|
.xlarge {
|
||||||
font-size: 3.75rem;
|
font-size: var(--font-size-xlarge);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: -3px;
|
letter-spacing: -3px;
|
||||||
}
|
}
|
||||||
@ -115,7 +119,7 @@ body {
|
|||||||
|
|
||||||
header {
|
header {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-xsmall);
|
||||||
font-family: var(--font-primary), Arial, Helvetica, sans-serif;
|
font-family: var(--font-primary), Arial, Helvetica, sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
border-bottom: 1px solid var(--color-text-dimmed);
|
border-bottom: 1px solid var(--color-text-dimmed);
|
||||||
|
28
fonts/package-lock.json
generated
28
fonts/package-lock.json
generated
@ -7,31 +7,31 @@
|
|||||||
"name": "magicmirror-fonts",
|
"name": "magicmirror-fonts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": "^4.5.7",
|
"@fontsource/roboto": "^4.5.8",
|
||||||
"@fontsource/roboto-condensed": "^4.5.8"
|
"@fontsource/roboto-condensed": "^4.5.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fontsource/roboto": {
|
"node_modules/@fontsource/roboto": {
|
||||||
"version": "4.5.7",
|
"version": "4.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
|
||||||
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
|
"integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
|
||||||
},
|
},
|
||||||
"node_modules/@fontsource/roboto-condensed": {
|
"node_modules/@fontsource/roboto-condensed": {
|
||||||
"version": "4.5.8",
|
"version": "4.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.9.tgz",
|
||||||
"integrity": "sha512-HCuf1rVSOsXnl/KgHNRLCr8XS/Dunzn10BjhliJiEZ5qPynXCWH4RRBFupIODHamhj2Uyp/iZkSQp574luKp6A=="
|
"integrity": "sha512-ql4sQq+h8puBVildZ5ssjYf8DWDONYDe3PD3Bu/p1ZW9GnRETRNPPcCTs/q62HIl3QimwwkiKWynn6wZhQaetg=="
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": {
|
"@fontsource/roboto": {
|
||||||
"version": "4.5.7",
|
"version": "4.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
|
||||||
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
|
"integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
|
||||||
},
|
},
|
||||||
"@fontsource/roboto-condensed": {
|
"@fontsource/roboto-condensed": {
|
||||||
"version": "4.5.8",
|
"version": "4.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.9.tgz",
|
||||||
"integrity": "sha512-HCuf1rVSOsXnl/KgHNRLCr8XS/Dunzn10BjhliJiEZ5qPynXCWH4RRBFupIODHamhj2Uyp/iZkSQp574luKp6A=="
|
"integrity": "sha512-ql4sQq+h8puBVildZ5ssjYf8DWDONYDe3PD3Bu/p1ZW9GnRETRNPPcCTs/q62HIl3QimwwkiKWynn6wZhQaetg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"url": "https://github.com/MichMich/MagicMirror/issues"
|
"url": "https://github.com/MichMich/MagicMirror/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": "^4.5.7",
|
"@fontsource/roboto": "^4.5.8",
|
||||||
"@fontsource/roboto-condensed": "^4.5.8"
|
"@fontsource/roboto-condensed": "^4.5.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,39 +22,38 @@ const NodeHelper = Class.extend({
|
|||||||
Log.log(`Starting module helper: ${this.name}`);
|
Log.log(`Starting module helper: ${this.name}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* stop()
|
/**
|
||||||
* Called when the MagicMirror² server receives a `SIGINT`
|
* Called when the MagicMirror² server receives a `SIGINT`
|
||||||
* Close any open connections, stop any sub-processes and
|
* Close any open connections, stop any sub-processes and
|
||||||
* gracefully exit the module.
|
* gracefully exit the module.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
stop() {
|
stop() {
|
||||||
Log.log(`Stopping module helper: ${this.name}`);
|
Log.log(`Stopping module helper: ${this.name}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* socketNotificationReceived(notification, payload)
|
/**
|
||||||
* This method is called when a socket notification arrives.
|
* This method is called when a socket notification arrives.
|
||||||
*
|
*
|
||||||
* argument notification string - The identifier of the notification.
|
* @param {string} notification The identifier of the notification.
|
||||||
* argument payload mixed - The payload of the notification.
|
* @param {*} payload The payload of the notification.
|
||||||
*/
|
*/
|
||||||
socketNotificationReceived(notification, payload) {
|
socketNotificationReceived(notification, payload) {
|
||||||
Log.log(`${this.name} received a socket notification: ${notification} - Payload: ${payload}`);
|
Log.log(`${this.name} received a socket notification: ${notification} - Payload: ${payload}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* setName(name)
|
/**
|
||||||
* Set the module name.
|
* Set the module name.
|
||||||
*
|
*
|
||||||
* argument name string - Module name.
|
* @param {string} name Module name.
|
||||||
*/
|
*/
|
||||||
setName(name) {
|
setName(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* setPath(path)
|
/**
|
||||||
* Set the module path.
|
* Set the module path.
|
||||||
*
|
*
|
||||||
* argument path string - Module path.
|
* @param {string} path Module path.
|
||||||
*/
|
*/
|
||||||
setPath(path) {
|
setPath(path) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
0
modules/default/calendar/README.md
Executable file → Normal file
0
modules/default/calendar/README.md
Executable file → Normal file
21
modules/default/calendar/calendar.js
Executable file → Normal file
21
modules/default/calendar/calendar.js
Executable file → Normal file
@ -37,6 +37,7 @@ Module.register("calendar", {
|
|||||||
hidePrivate: false,
|
hidePrivate: false,
|
||||||
hideOngoing: false,
|
hideOngoing: false,
|
||||||
hideTime: false,
|
hideTime: false,
|
||||||
|
showTimeToday: false,
|
||||||
colored: false,
|
colored: false,
|
||||||
coloredSymbolOnly: false,
|
coloredSymbolOnly: false,
|
||||||
customEvents: [], // Array of {keyword: "", symbol: "", color: ""} where Keyword is a regexp and symbol/color are to be applied for matched
|
customEvents: [], // Array of {keyword: "", symbol: "", color: ""} where Keyword is a regexp and symbol/color are to be applied for matched
|
||||||
@ -133,6 +134,10 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
// Override socket notification handler.
|
// Override socket notification handler.
|
||||||
socketNotificationReceived: function (notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
|
if (notification === "FETCH_CALENDAR") {
|
||||||
|
this.sendSocketNotification(notification, { url: payload.url, id: this.identifier });
|
||||||
|
}
|
||||||
|
|
||||||
if (this.identifier !== payload.id) {
|
if (this.identifier !== payload.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -368,7 +373,7 @@ Module.register("calendar", {
|
|||||||
} else {
|
} else {
|
||||||
timeWrapper.innerHTML = this.capFirst(
|
timeWrapper.innerHTML = this.capFirst(
|
||||||
moment(event.startDate, "x").calendar(null, {
|
moment(event.startDate, "x").calendar(null, {
|
||||||
sameDay: "[" + this.translate("TODAY") + "]",
|
sameDay: this.config.showTimeToday ? "LT" : "[" + this.translate("TODAY") + "]",
|
||||||
nextDay: "[" + this.translate("TOMORROW") + "]",
|
nextDay: "[" + this.translate("TOMORROW") + "]",
|
||||||
nextWeek: "dddd",
|
nextWeek: "dddd",
|
||||||
sameElse: event.fullDayEvent ? this.config.fullDayEventDateFormat : this.config.dateFormat
|
sameElse: event.fullDayEvent ? this.config.fullDayEventDateFormat : this.config.dateFormat
|
||||||
@ -493,6 +498,7 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
for (const calendarUrl in this.calendarData) {
|
for (const calendarUrl in this.calendarData) {
|
||||||
const calendar = this.calendarData[calendarUrl];
|
const calendar = this.calendarData[calendarUrl];
|
||||||
|
let remainingEntries = this.maximumEntriesForUrl(calendarUrl);
|
||||||
for (const e in calendar) {
|
for (const e in calendar) {
|
||||||
const event = JSON.parse(JSON.stringify(calendar[e])); // clone object
|
const event = JSON.parse(JSON.stringify(calendar[e])); // clone object
|
||||||
|
|
||||||
@ -510,6 +516,9 @@ Module.register("calendar", {
|
|||||||
if (this.listContainsEvent(events, event)) {
|
if (this.listContainsEvent(events, event)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (--remainingEntries < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
event.url = calendarUrl;
|
event.url = calendarUrl;
|
||||||
event.today = event.startDate >= today && event.startDate < today + 24 * 60 * 60 * 1000;
|
event.today = event.startDate >= today && event.startDate < today + 24 * 60 * 60 * 1000;
|
||||||
@ -718,6 +727,16 @@ Module.register("calendar", {
|
|||||||
return this.getCalendarProperty(url, "repeatingCountTitle", this.config.defaultRepeatingCountTitle);
|
return this.getCalendarProperty(url, "repeatingCountTitle", this.config.defaultRepeatingCountTitle);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the maximum entry count for a specific calendar url.
|
||||||
|
*
|
||||||
|
* @param {string} url The calendar url
|
||||||
|
* @returns {number} The maximum entry count
|
||||||
|
*/
|
||||||
|
maximumEntriesForUrl: function (url) {
|
||||||
|
return this.getCalendarProperty(url, "maximumEntries", this.config.maximumEntries);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to retrieve the property for a specific calendar url.
|
* Helper method to retrieve the property for a specific calendar url.
|
||||||
*
|
*
|
||||||
|
@ -333,9 +333,12 @@ const CalendarUtils = {
|
|||||||
// If the offset is negative (east of GMT), where the problem is
|
// If the offset is negative (east of GMT), where the problem is
|
||||||
if (dateoffset < 0) {
|
if (dateoffset < 0) {
|
||||||
if (dh < Math.abs(dateoffset / 60)) {
|
if (dh < Math.abs(dateoffset / 60)) {
|
||||||
|
// if the rrule byweekday WAS explicitly set , correct it
|
||||||
// reduce the time by the offset
|
// reduce the time by the offset
|
||||||
// Apply the correction to the date/time to get it UTC relative
|
if (curEvent.rrule.origOptions.byweekday !== undefined) {
|
||||||
date = new Date(date.getTime() - Math.abs(24 * 60) * 60000);
|
// Apply the correction to the date/time to get it UTC relative
|
||||||
|
date = new Date(date.getTime() - Math.abs(24 * 60) * 60000);
|
||||||
|
}
|
||||||
// the duration was calculated way back at the top before we could correct the start time..
|
// the duration was calculated way back at the top before we could correct the start time..
|
||||||
// fix it for this event entry
|
// fix it for this event entry
|
||||||
//duration = 24 * 60 * 60 * 1000;
|
//duration = 24 * 60 * 60 * 1000;
|
||||||
@ -346,8 +349,11 @@ const CalendarUtils = {
|
|||||||
//if (event.start.tz === moment.tz.guess()) {
|
//if (event.start.tz === moment.tz.guess()) {
|
||||||
// if the date hour is less than the offset
|
// if the date hour is less than the offset
|
||||||
if (24 - dh <= Math.abs(dateoffset / 60)) {
|
if (24 - dh <= Math.abs(dateoffset / 60)) {
|
||||||
// apply the correction to the date/time back to right day
|
// if the rrule byweekday WAS explicitly set , correct it
|
||||||
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
|
if (curEvent.rrule.origOptions.byweekday !== undefined) {
|
||||||
|
// apply the correction to the date/time back to right day
|
||||||
|
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
|
||||||
|
}
|
||||||
// the duration was calculated way back at the top before we could correct the start time..
|
// the duration was calculated way back at the top before we could correct the start time..
|
||||||
// fix it for this event entry
|
// fix it for this event entry
|
||||||
//duration = 24 * 60 * 60 * 1000;
|
//duration = 24 * 60 * 60 * 1000;
|
||||||
@ -361,9 +367,12 @@ const CalendarUtils = {
|
|||||||
if (dateoffset < 0) {
|
if (dateoffset < 0) {
|
||||||
// if the date hour is less than the offset
|
// if the date hour is less than the offset
|
||||||
if (dh <= Math.abs(dateoffset / 60)) {
|
if (dh <= Math.abs(dateoffset / 60)) {
|
||||||
// Reduce the time by the offset:
|
// if the rrule byweekday WAS explicitly set , correct it
|
||||||
// Apply the correction to the date/time to get it UTC relative
|
if (curEvent.rrule.origOptions.byweekday !== undefined) {
|
||||||
date = new Date(date.getTime() - Math.abs(24 * 60) * 60000);
|
// Reduce the time by t:
|
||||||
|
// Apply the correction to the date/time to get it UTC relative
|
||||||
|
date = new Date(date.getTime() - Math.abs(24 * 60) * 60000);
|
||||||
|
}
|
||||||
// the duration was calculated way back at the top before we could correct the start time..
|
// the duration was calculated way back at the top before we could correct the start time..
|
||||||
// fix it for this event entry
|
// fix it for this event entry
|
||||||
//duration = 24 * 60 * 60 * 1000;
|
//duration = 24 * 60 * 60 * 1000;
|
||||||
@ -374,8 +383,11 @@ const CalendarUtils = {
|
|||||||
//if (event.start.tz === moment.tz.guess()) {
|
//if (event.start.tz === moment.tz.guess()) {
|
||||||
// if the date hour is less than the offset
|
// if the date hour is less than the offset
|
||||||
if (24 - dh <= Math.abs(dateoffset / 60)) {
|
if (24 - dh <= Math.abs(dateoffset / 60)) {
|
||||||
// apply the correction to the date/time back to right day
|
// if the rrule byweekday WAS explicitly set , correct it
|
||||||
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
|
if (curEvent.rrule.origOptions.byweekday !== undefined) {
|
||||||
|
// apply the correction to the date/time back to right day
|
||||||
|
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
|
||||||
|
}
|
||||||
// the duration was calculated way back at the top before we could correct the start time..
|
// the duration was calculated way back at the top before we could correct the start time..
|
||||||
// fix it for this event entry
|
// fix it for this event entry
|
||||||
//duration = 24 * 60 * 60 * 1000;
|
//duration = 24 * 60 * 60 * 1000;
|
||||||
@ -469,10 +481,6 @@ const CalendarUtils = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust start date so multiple day events will be displayed as happening today even though they started some days ago already
|
|
||||||
if (fullDayEvent && startDate <= today && endDate > today) {
|
|
||||||
startDate = moment(today);
|
|
||||||
}
|
|
||||||
// if the start and end are the same, then make end the 'end of day' value (start is at 00:00:00)
|
// if the start and end are the same, then make end the 'end of day' value (start is at 00:00:00)
|
||||||
if (fullDayEvent && startDate.format("x") === endDate.format("x")) {
|
if (fullDayEvent && startDate.format("x") === endDate.format("x")) {
|
||||||
endDate = endDate.endOf("day");
|
endDate = endDate.endOf("day");
|
||||||
@ -498,8 +506,7 @@ const CalendarUtils = {
|
|||||||
return a.startDate - b.startDate;
|
return a.startDate - b.startDate;
|
||||||
});
|
});
|
||||||
|
|
||||||
let maxEvents = newEvents.slice(0, config.maximumEntries);
|
return newEvents;
|
||||||
return maxEvents;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,6 +19,14 @@ module.exports = NodeHelper.create({
|
|||||||
socketNotificationReceived: function (notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
if (notification === "ADD_CALENDAR") {
|
if (notification === "ADD_CALENDAR") {
|
||||||
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.selfSignedCert, payload.id);
|
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.selfSignedCert, payload.id);
|
||||||
|
} else if (notification === "FETCH_CALENDAR") {
|
||||||
|
const key = payload.id + payload.url;
|
||||||
|
if (typeof this.fetchers[key] === "undefined") {
|
||||||
|
Log.error("Calendar Error. No fetcher exists with key: ", key);
|
||||||
|
this.sendSocketNotification("CALENDAR_ERROR", { error_type: "MODULE_ERROR_UNSPECIFIED" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fetchers[key].startFetch();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
/* MagicMirror²
|
|
||||||
* Module: CurrentWeather
|
|
||||||
*
|
|
||||||
* By Michael Teeuw https://michaelteeuw.nl
|
|
||||||
* MIT Licensed.
|
|
||||||
*
|
|
||||||
* This module is deprecated. Any additional feature will no longer be merged.
|
|
||||||
*/
|
|
||||||
Module.register("currentweather", {
|
|
||||||
// Define start sequence.
|
|
||||||
start: function () {
|
|
||||||
Log.info("Starting module: " + this.name);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Override dom generator.
|
|
||||||
getDom: function () {
|
|
||||||
var wrapper = document.createElement("div");
|
|
||||||
wrapper.className = this.config.tableClass;
|
|
||||||
wrapper.innerHTML =
|
|
||||||
"<style>text-decoration: none</style>" +
|
|
||||||
"This module is deprecated since release v2.15 and removed with v2.19." +
|
|
||||||
'<br>Please use the `weather` module as replacement, more info in the <a href="https://docs.magicmirror.builders/modules/weather.html" style="color: #ffffff">documentation</a>.';
|
|
||||||
wrapper.className = "dimmed light small";
|
|
||||||
return wrapper;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Override getHeader method.
|
|
||||||
getHeader: function () {
|
|
||||||
return "deprecated currentweather";
|
|
||||||
}
|
|
||||||
});
|
|
@ -4,7 +4,7 @@
|
|||||||
* By Michael Teeuw https://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
const defaultModules = ["alert", "calendar", "clock", "compliments", "currentweather", "helloworld", "newsfeed", "weatherforecast", "updatenotification", "weather"];
|
const defaultModules = ["alert", "calendar", "clock", "compliments", "helloworld", "newsfeed", "updatenotification", "weather"];
|
||||||
|
|
||||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||||
if (typeof module !== "undefined") {
|
if (typeof module !== "undefined") {
|
||||||
|
@ -78,6 +78,19 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
|||||||
scheduleTimer();
|
scheduleTimer();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
parser.on("ttl", (minutes) => {
|
||||||
|
try {
|
||||||
|
// 86400000 = 24 hours is mentioned in the docs as maximum value:
|
||||||
|
const ttlms = Math.min(minutes * 60 * 1000, 86400000);
|
||||||
|
if (ttlms > reloadInterval) {
|
||||||
|
reloadInterval = ttlms;
|
||||||
|
Log.info("Newsfeed-Fetcher: reloadInterval set to ttl=" + reloadInterval + " for url " + url);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Log.warn("Newsfeed-Fetcher: feed ttl is no valid integer=" + minutes + " for url " + url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
||||||
const headers = {
|
const headers = {
|
||||||
"User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version,
|
"User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version,
|
||||||
|
2
modules/default/weather/README.md
Executable file → Normal file
2
modules/default/weather/README.md
Executable file → Normal file
@ -1,5 +1,5 @@
|
|||||||
# Weather Module
|
# Weather Module
|
||||||
|
|
||||||
This module aims to be the replacement for the current `currentweather` and `weatherforcast` modules. The module will be configurable to be used as a current weather view, or to show the forecast. This way the module can be used twice to fulfill both purposes.
|
This module will be configurable to be used as a current weather view, or to show the forecast. This way the module can be used twice to fulfill both purposes.
|
||||||
|
|
||||||
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/weather.html).
|
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/weather.html).
|
||||||
|
0
modules/default/weather/current.njk
Executable file → Normal file
0
modules/default/weather/current.njk
Executable file → Normal file
0
modules/default/weather/providers/README.md
Executable file → Normal file
0
modules/default/weather/providers/README.md
Executable file → Normal file
0
modules/default/weather/providers/darksky.js
Executable file → Normal file
0
modules/default/weather/providers/darksky.js
Executable file → Normal file
0
modules/default/weather/providers/openweathermap.js
Executable file → Normal file
0
modules/default/weather/providers/openweathermap.js
Executable file → Normal file
@ -17,19 +17,20 @@ WeatherProvider.register("smhi", {
|
|||||||
defaults: {
|
defaults: {
|
||||||
lat: 0,
|
lat: 0,
|
||||||
lon: 0,
|
lon: 0,
|
||||||
precipitationValue: "pmedian"
|
precipitationValue: "pmedian",
|
||||||
|
location: false
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements method in interface for fetching current weather
|
* Implements method in interface for fetching current weather.
|
||||||
*/
|
*/
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getURL())
|
this.fetchData(this.getURL())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
let closest = this.getClosestToCurrentTime(data.timeSeries);
|
const closest = this.getClosestToCurrentTime(data.timeSeries);
|
||||||
let coordinates = this.resolveCoordinates(data);
|
const coordinates = this.resolveCoordinates(data);
|
||||||
let weatherObject = this.convertWeatherDataToObject(closest, coordinates);
|
const weatherObject = this.convertWeatherDataToObject(closest, coordinates);
|
||||||
this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`);
|
this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`);
|
||||||
this.setCurrentWeather(weatherObject);
|
this.setCurrentWeather(weatherObject);
|
||||||
})
|
})
|
||||||
.catch((error) => Log.error("Could not load data: " + error.message))
|
.catch((error) => Log.error("Could not load data: " + error.message))
|
||||||
@ -37,21 +38,35 @@ WeatherProvider.register("smhi", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements method in interface for fetching a forecast.
|
* Implements method in interface for fetching a multi-day forecast.
|
||||||
* Handling hourly forecast would be easy as not grouping by day but it seems really specific for one weather provider for now.
|
|
||||||
*/
|
*/
|
||||||
fetchWeatherForecast() {
|
fetchWeatherForecast() {
|
||||||
this.fetchData(this.getURL())
|
this.fetchData(this.getURL())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
let coordinates = this.resolveCoordinates(data);
|
const coordinates = this.resolveCoordinates(data);
|
||||||
let weatherObjects = this.convertWeatherDataGroupedByDay(data.timeSeries, coordinates);
|
const weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates);
|
||||||
this.setFetchedLocation(`(${coordinates.lat},${coordinates.lon})`);
|
this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`);
|
||||||
this.setWeatherForecast(weatherObjects);
|
this.setWeatherForecast(weatherObjects);
|
||||||
})
|
})
|
||||||
.catch((error) => Log.error("Could not load data: " + error.message))
|
.catch((error) => Log.error("Could not load data: " + error.message))
|
||||||
.finally(() => this.updateAvailable());
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements method in interface for fetching hourly forecasts.
|
||||||
|
*/
|
||||||
|
fetchWeatherHourly() {
|
||||||
|
this.fetchData(this.getURL())
|
||||||
|
.then((data) => {
|
||||||
|
const coordinates = this.resolveCoordinates(data);
|
||||||
|
const weatherObjects = this.convertWeatherDataGroupedBy(data.timeSeries, coordinates, "hour");
|
||||||
|
this.setFetchedLocation(this.config.location || `(${coordinates.lat},${coordinates.lon})`);
|
||||||
|
this.setWeatherHourly(weatherObjects);
|
||||||
|
})
|
||||||
|
.catch((error) => Log.error("Could not load data: " + error.message))
|
||||||
|
.finally(() => this.updateAvailable());
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides method for setting config with checks for the precipitationValue being unset or invalid
|
* Overrides method for setting config with checks for the precipitationValue being unset or invalid
|
||||||
*
|
*
|
||||||
@ -94,6 +109,21 @@ WeatherProvider.register("smhi", {
|
|||||||
return `https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/${lon}/lat/${lat}/data.json`;
|
return `https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/${lon}/lat/${lat}/data.json`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the apparent temperature based on known atmospheric data.
|
||||||
|
*
|
||||||
|
* @param {object} weatherData Weatherdata to use for the calculation
|
||||||
|
* @returns {number} The apparent temperature
|
||||||
|
*/
|
||||||
|
calculateApparentTemperature(weatherData) {
|
||||||
|
const Ta = this.paramValue(weatherData, "t");
|
||||||
|
const rh = this.paramValue(weatherData, "r");
|
||||||
|
const ws = this.paramValue(weatherData, "ws");
|
||||||
|
const p = (rh / 100) * 6.105 * Math.E * ((17.27 * Ta) / (237.7 + Ta));
|
||||||
|
|
||||||
|
return Ta + 0.33 * p - 0.7 * ws - 4;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the returned data into a WeatherObject with required properties set for both current weather and forecast.
|
* Converts the returned data into a WeatherObject with required properties set for both current weather and forecast.
|
||||||
* The returned units is always in metric system.
|
* The returned units is always in metric system.
|
||||||
@ -114,6 +144,7 @@ WeatherProvider.register("smhi", {
|
|||||||
currentWeather.windSpeed = this.paramValue(weatherData, "ws");
|
currentWeather.windSpeed = this.paramValue(weatherData, "ws");
|
||||||
currentWeather.windDirection = this.paramValue(weatherData, "wd");
|
currentWeather.windDirection = this.paramValue(weatherData, "wd");
|
||||||
currentWeather.weatherType = this.convertWeatherType(this.paramValue(weatherData, "Wsymb2"), currentWeather.isDayTime());
|
currentWeather.weatherType = this.convertWeatherType(this.paramValue(weatherData, "Wsymb2"), currentWeather.isDayTime());
|
||||||
|
currentWeather.feelsLikeTemp = this.calculateAT(weatherData);
|
||||||
|
|
||||||
// Determine the precipitation amount and category and update the
|
// Determine the precipitation amount and category and update the
|
||||||
// weatherObject with it, the valuetype to use can be configured or uses
|
// weatherObject with it, the valuetype to use can be configured or uses
|
||||||
@ -147,9 +178,10 @@ WeatherProvider.register("smhi", {
|
|||||||
*
|
*
|
||||||
* @param {object[]} allWeatherData Array of weatherdata
|
* @param {object[]} allWeatherData Array of weatherdata
|
||||||
* @param {object} coordinates Coordinates of the locations of the weather
|
* @param {object} coordinates Coordinates of the locations of the weather
|
||||||
|
* @param {string} groupBy The interval to use for grouping the data (day, hour)
|
||||||
* @returns {WeatherObject[]} Array of weatherobjects
|
* @returns {WeatherObject[]} Array of weatherobjects
|
||||||
*/
|
*/
|
||||||
convertWeatherDataGroupedByDay(allWeatherData, coordinates) {
|
convertWeatherDataGroupedBy(allWeatherData, coordinates, groupBy = "day") {
|
||||||
let currentWeather;
|
let currentWeather;
|
||||||
let result = [];
|
let result = [];
|
||||||
|
|
||||||
@ -157,10 +189,11 @@ WeatherProvider.register("smhi", {
|
|||||||
let dayWeatherTypes = [];
|
let dayWeatherTypes = [];
|
||||||
|
|
||||||
for (const weatherObject of allWeatherObjects) {
|
for (const weatherObject of allWeatherObjects) {
|
||||||
//If its the first object or if a day change we need to reset the summary object
|
//If its the first object or if a day/hour change we need to reset the summary object
|
||||||
if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, "day")) {
|
if (!currentWeather || !currentWeather.date.isSame(weatherObject.date, groupBy)) {
|
||||||
currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||||
dayWeatherTypes = [];
|
dayWeatherTypes = [];
|
||||||
|
currentWeather.temperature = weatherObject.temperature;
|
||||||
currentWeather.date = weatherObject.date;
|
currentWeather.date = weatherObject.date;
|
||||||
currentWeather.minTemperature = Infinity;
|
currentWeather.minTemperature = Infinity;
|
||||||
currentWeather.maxTemperature = -Infinity;
|
currentWeather.maxTemperature = -Infinity;
|
||||||
|
0
modules/default/weather/providers/ukmetoffice.js
Executable file → Normal file
0
modules/default/weather/providers/ukmetoffice.js
Executable file → Normal file
@ -18,7 +18,6 @@ WeatherProvider.register("weatherbit", {
|
|||||||
// Set the default config properties that is specific to this provider
|
// Set the default config properties that is specific to this provider
|
||||||
defaults: {
|
defaults: {
|
||||||
apiBase: "https://api.weatherbit.io/v2.0",
|
apiBase: "https://api.weatherbit.io/v2.0",
|
||||||
weatherEndpoint: "/current",
|
|
||||||
apiKey: "",
|
apiKey: "",
|
||||||
lat: 0,
|
lat: 0,
|
||||||
lon: 0
|
lon: 0
|
||||||
@ -69,6 +68,31 @@ WeatherProvider.register("weatherbit", {
|
|||||||
.finally(() => this.updateAvailable());
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides method for setting config to check if endpoint is correct for hourly
|
||||||
|
*
|
||||||
|
* @param {object} config The configuration object
|
||||||
|
*/
|
||||||
|
setConfig(config) {
|
||||||
|
this.config = config;
|
||||||
|
if (!this.config.weatherEndpoint) {
|
||||||
|
switch (this.config.type) {
|
||||||
|
case "hourly":
|
||||||
|
this.config.weatherEndpoint = "/forecast/hourly";
|
||||||
|
break;
|
||||||
|
case "daily":
|
||||||
|
case "forecast":
|
||||||
|
this.config.weatherEndpoint = "/forecast/daily";
|
||||||
|
break;
|
||||||
|
case "current":
|
||||||
|
this.config.weatherEndpoint = "/current";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.error("weatherEndpoint not configured and could not resolve it based on type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Create a URL from the config and base URL.
|
// Create a URL from the config and base URL.
|
||||||
getUrl() {
|
getUrl() {
|
||||||
const units = this.units[this.config.units] || "auto";
|
const units = this.units[this.config.units] || "auto";
|
||||||
|
0
modules/default/weather/providers/weathergov.js
Executable file → Normal file
0
modules/default/weather/providers/weathergov.js
Executable file → Normal file
0
modules/default/weather/weatherobject.js
Executable file → Normal file
0
modules/default/weather/weatherobject.js
Executable file → Normal file
@ -1,33 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
/* MagicMirror²
|
|
||||||
* Module: CurrentWeather
|
|
||||||
*
|
|
||||||
* By Michael Teeuw https://michaelteeuw.nl
|
|
||||||
* MIT Licensed.
|
|
||||||
*
|
|
||||||
* This module is deprecated. Any additional feature will no longer be merged.
|
|
||||||
*/
|
|
||||||
Module.register("weatherforecast", {
|
|
||||||
// Define start sequence.
|
|
||||||
start: function () {
|
|
||||||
Log.info("Starting module: " + this.name);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Override dom generator.
|
|
||||||
getDom: function () {
|
|
||||||
var wrapper = document.createElement("div");
|
|
||||||
wrapper.className = this.config.tableClass;
|
|
||||||
wrapper.innerHTML =
|
|
||||||
"<style>text-decoration: none</style>" +
|
|
||||||
"This module is deprecated since release v2.15 and removed with v2.19." +
|
|
||||||
'<br>Please use the `weather` module as replacement, more info in the <a href="https://docs.magicmirror.builders/modules/weather.html" style="color: #ffffff">documentation</a>.';
|
|
||||||
wrapper.className = "dimmed light small";
|
|
||||||
return wrapper;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Override getHeader method.
|
|
||||||
getHeader: function () {
|
|
||||||
return "deprecated weatherforecast";
|
|
||||||
}
|
|
||||||
});
|
|
3821
package-lock.json
generated
3821
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
38
package.json
38
package.json
@ -1,15 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "magicmirror",
|
"name": "magicmirror",
|
||||||
"version": "2.20.0",
|
"version": "2.21.0",
|
||||||
"description": "The open source modular smart mirror platform.",
|
"description": "The open source modular smart mirror platform.",
|
||||||
"main": "js/electron.js",
|
"main": "js/electron.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js",
|
"start": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js",
|
||||||
"start:dev": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js dev",
|
"start:dev": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js dev",
|
||||||
"server": "node ./serveronly",
|
"server": "node ./serveronly",
|
||||||
"install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error",
|
"install-mm": "npm install --no-audit --no-fund --no-update-notifier --only=prod --omit=dev",
|
||||||
"install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error",
|
"install-mm:dev": "npm install --no-audit --no-fund --no-update-notifier",
|
||||||
"postinstall": "npm run install-fonts && echo \"MagicMirror² installation finished successfully! \n\"",
|
"install-vendor": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error --no-audit --no-fund --no-update-notifier",
|
||||||
|
"install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error --no-audit --no-fund --no-update-notifier",
|
||||||
|
"postinstall": "npm run install-vendor && npm run install-fonts && echo \"MagicMirror² installation finished successfully! \n\"",
|
||||||
"test": "NODE_ENV=test jest -i --forceExit",
|
"test": "NODE_ENV=test jest -i --forceExit",
|
||||||
"test:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text jest -i --forceExit",
|
"test:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text jest -i --forceExit",
|
||||||
"test:electron": "NODE_ENV=test jest --selectProjects electron -i --forceExit",
|
"test:electron": "NODE_ENV=test jest --selectProjects electron -i --forceExit",
|
||||||
@ -48,44 +50,44 @@
|
|||||||
"homepage": "https://magicmirror.builders",
|
"homepage": "https://magicmirror.builders",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-jest": "^26.5.3",
|
"eslint-plugin-jest": "^27.0.4",
|
||||||
"eslint-plugin-jsdoc": "^39.3.3",
|
"eslint-plugin-jsdoc": "^39.3.6",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"express-basic-auth": "^1.2.1",
|
"express-basic-auth": "^1.2.1",
|
||||||
"husky": "^8.0.1",
|
"husky": "^8.0.1",
|
||||||
"jest": "^28.1.1",
|
"jest": "^29.0.3",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "^20.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"playwright": "^1.22.2",
|
"playwright": "^1.26.1",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.1.3",
|
||||||
"sinon": "^14.0.0",
|
"sinon": "^14.0.0",
|
||||||
"stylelint": "^14.9.1",
|
"stylelint": "^14.12.1",
|
||||||
"stylelint-config-prettier": "^9.0.3",
|
"stylelint-config-prettier": "^9.0.3",
|
||||||
"stylelint-config-standard": "^26.0.0",
|
"stylelint-config-standard": "^28.0.0",
|
||||||
"stylelint-prettier": "^2.0.0",
|
"stylelint-prettier": "^2.0.0",
|
||||||
"suncalc": "^1.9.0"
|
"suncalc": "^1.9.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"electron": "^19.0.6"
|
"electron": "^19.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"console-stamp": "^3.0.6",
|
"console-stamp": "^3.0.6",
|
||||||
"digest-fetch": "^1.2.1",
|
"digest-fetch": "^1.3.0",
|
||||||
"eslint": "^8.18.0",
|
"eslint": "^8.24.0",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
"express-ipfilter": "^1.2.0",
|
"express-ipfilter": "^1.3.1",
|
||||||
"feedme": "^2.0.2",
|
"feedme": "^2.0.2",
|
||||||
"helmet": "^5.1.0",
|
"helmet": "^6.0.0",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"luxon": "^1.28.0",
|
"luxon": "^1.28.0",
|
||||||
"module-alias": "^2.2.2",
|
"module-alias": "^2.2.2",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.4",
|
||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.7",
|
||||||
"node-ical": "^0.15.1",
|
"node-ical": "^0.15.1",
|
||||||
"socket.io": "^4.5.1"
|
"socket.io": "^4.5.2"
|
||||||
},
|
},
|
||||||
"_moduleAliases": {
|
"_moduleAliases": {
|
||||||
"node_helper": "js/node_helper.js",
|
"node_helper": "js/node_helper.js",
|
||||||
|
@ -12,7 +12,7 @@ BEGIN:STANDARD
|
|||||||
TZOFFSETFROM:+0000
|
TZOFFSETFROM:+0000
|
||||||
TZOFFSETTO:+0000
|
TZOFFSETTO:+0000
|
||||||
TZNAME:GMT
|
TZNAME:GMT
|
||||||
DTSTART:19700101T00000--äüüßßß-0
|
DTSTART:19700101T000000
|
||||||
END:STANDARD
|
END:STANDARD
|
||||||
END:VTIMEZONE
|
END:VTIMEZONE
|
||||||
BEGIN:VEVENT
|
BEGIN:VEVENT
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
const fetch = require("fetch");
|
const fetch = require("fetch");
|
||||||
const helpers = require("./global-setup");
|
const helpers = require("./global-setup");
|
||||||
|
|
||||||
describe("App environment", function () {
|
describe("App environment", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/default.js");
|
helpers.startApplication("tests/configs/default.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("get request from http://localhost:8080 should return 200", function (done) {
|
it("get request from http://localhost:8080 should return 200", (done) => {
|
||||||
fetch("http://localhost:8080").then((res) => {
|
fetch("http://localhost:8080").then((res) => {
|
||||||
|
done();
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("get request from http://localhost:8080/nothing should return 404", function (done) {
|
it("get request from http://localhost:8080/nothing should return 404", (done) => {
|
||||||
fetch("http://localhost:8080/nothing").then((res) => {
|
fetch("http://localhost:8080/nothing").then((res) => {
|
||||||
expect(res.status).toBe(404);
|
|
||||||
done();
|
done();
|
||||||
|
expect(res.status).toBe(404);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the title MagicMirror²", function () {
|
it("should show the title MagicMirror²", (done) => {
|
||||||
helpers.waitForElement("title").then((elem) => {
|
helpers.waitForElement("title").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toBe("MagicMirror²");
|
expect(elem.textContent).toBe("MagicMirror²");
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const jsdom = require("jsdom");
|
const jsdom = require("jsdom");
|
||||||
|
|
||||||
exports.startApplication = function (configFilename, exec) {
|
exports.startApplication = (configFilename, exec) => {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
this.stopApplication();
|
this.stopApplication();
|
||||||
// Set config sample for use in test
|
// Set config sample for use in test
|
||||||
@ -14,41 +14,60 @@ exports.startApplication = function (configFilename, exec) {
|
|||||||
global.app.start();
|
global.app.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.stopApplication = async function () {
|
exports.stopApplication = async () => {
|
||||||
if (global.app) {
|
if (global.app) {
|
||||||
global.app.stop();
|
global.app.stop();
|
||||||
}
|
}
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.getDocument = function (callback) {
|
exports.getDocument = (callback) => {
|
||||||
const url = "http://" + (config.address || "localhost") + ":" + (config.port || "8080");
|
const url = "http://" + (config.address || "localhost") + ":" + (config.port || "8080");
|
||||||
jsdom.JSDOM.fromURL(url, { resources: "usable", runScripts: "dangerously" }).then((dom) => {
|
jsdom.JSDOM.fromURL(url, { resources: "usable", runScripts: "dangerously" }).then((dom) => {
|
||||||
dom.window.name = "jsdom";
|
dom.window.name = "jsdom";
|
||||||
dom.window.onload = function () {
|
dom.window.onload = () => {
|
||||||
global.MutationObserver = dom.window.MutationObserver;
|
|
||||||
global.document = dom.window.document;
|
global.document = dom.window.document;
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.waitForElement = function (selector) {
|
exports.waitForElement = (selector, ignoreValue = "") => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (document.querySelector(selector) && document.querySelector(selector).value !== undefined) {
|
let oldVal = "dummy12345";
|
||||||
return resolve(document.querySelector(selector));
|
const interval = setInterval(() => {
|
||||||
}
|
const element = document.querySelector(selector);
|
||||||
|
if (element) {
|
||||||
const observer = new MutationObserver(() => {
|
let newVal = element.textContent;
|
||||||
if (document.querySelector(selector) && document.querySelector(selector).value !== undefined) {
|
if (newVal === oldVal) {
|
||||||
resolve(document.querySelector(selector));
|
clearInterval(interval);
|
||||||
observer.disconnect();
|
resolve(element);
|
||||||
|
} else {
|
||||||
|
if (ignoreValue === "") {
|
||||||
|
oldVal = newVal;
|
||||||
|
} else {
|
||||||
|
if (!newVal.includes(ignoreValue)) oldVal = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}, 100);
|
||||||
|
});
|
||||||
observer.observe(document.body, {
|
};
|
||||||
childList: true,
|
|
||||||
subtree: true
|
exports.waitForAllElements = (selector) => {
|
||||||
});
|
return new Promise((resolve) => {
|
||||||
|
let oldVal = 999999;
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
const element = document.querySelectorAll(selector);
|
||||||
|
if (element) {
|
||||||
|
let newVal = element.length;
|
||||||
|
if (newVal === oldVal) {
|
||||||
|
clearInterval(interval);
|
||||||
|
resolve(element);
|
||||||
|
} else {
|
||||||
|
if (newVal !== 0) oldVal = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
const helpers = require("../global-setup");
|
const helpers = require("../global-setup");
|
||||||
|
|
||||||
describe("Alert module", function () {
|
describe("Alert module", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/alert/default.js");
|
helpers.startApplication("tests/configs/modules/alert/default.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the welcome message", function () {
|
it("should show the welcome message", (done) => {
|
||||||
helpers.waitForElement(".ns-box .ns-box-inner .light.bright.small").then((elem) => {
|
helpers.waitForElement(".ns-box .ns-box-inner .light.bright.small").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Welcome, start was successful!");
|
expect(elem.textContent).toContain("Welcome, start was successful!");
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
const helpers = require("../global-setup");
|
const helpers = require("../global-setup");
|
||||||
const serverBasicAuth = require("./basic-auth.js");
|
const serverBasicAuth = require("./basic-auth.js");
|
||||||
|
|
||||||
describe("Calendar module", function () {
|
describe("Calendar module", () => {
|
||||||
/**
|
/**
|
||||||
|
* @param {string} done test done
|
||||||
* @param {string} element css selector
|
* @param {string} element css selector
|
||||||
* @param {string} result expected number
|
* @param {string} result expected number
|
||||||
* @param {string} not reverse result
|
* @param {string} not reverse result
|
||||||
*/
|
*/
|
||||||
function testElementLength(element, result, not) {
|
const testElementLength = (done, element, result, not) => {
|
||||||
helpers.waitForElement(element).then((elem) => {
|
helpers.waitForAllElements(element).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
if (not === "not") {
|
if (not === "not") {
|
||||||
expect(elem.length).not.toBe(result);
|
expect(elem.length).not.toBe(result);
|
||||||
@ -16,147 +18,148 @@ describe("Calendar module", function () {
|
|||||||
expect(elem.length).toBe(result);
|
expect(elem.length).toBe(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const testTextContain = function (element, text) {
|
const testTextContain = (done, element, text) => {
|
||||||
helpers.waitForElement(element).then((elem) => {
|
helpers.waitForElement(element, "undefinedLoading").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain(text);
|
expect(elem.textContent).toContain(text);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Default configuration", function () {
|
describe("Default configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/default.js");
|
helpers.startApplication("tests/configs/modules/calendar/default.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the default maximumEntries of 10", () => {
|
it("should show the default maximumEntries of 10", (done) => {
|
||||||
testElementLength(".calendar .event", 10);
|
testElementLength(done, ".calendar .event", 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the default calendar symbol in each event", () => {
|
it("should show the default calendar symbol in each event", (done) => {
|
||||||
testElementLength(".calendar .event .fa-calendar-alt", 0, "not");
|
testElementLength(done, ".calendar .event .fa-calendar-alt", 0, "not");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Custom configuration", function () {
|
describe("Custom configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/custom.js");
|
helpers.startApplication("tests/configs/modules/calendar/custom.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the custom maximumEntries of 4", () => {
|
it("should show the custom maximumEntries of 4", (done) => {
|
||||||
testElementLength(".calendar .event", 4);
|
testElementLength(done, ".calendar .event", 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the custom calendar symbol in each event", () => {
|
it("should show the custom calendar symbol in each event", (done) => {
|
||||||
testElementLength(".calendar .event .fa-birthday-cake", 4);
|
testElementLength(done, ".calendar .event .fa-birthday-cake", 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show two custom icons for repeating events", () => {
|
it("should show two custom icons for repeating events", (done) => {
|
||||||
testElementLength(".calendar .event .fa-undo", 2);
|
testElementLength(done, ".calendar .event .fa-undo", 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show two custom icons for day events", () => {
|
it("should show two custom icons for day events", (done) => {
|
||||||
testElementLength(".calendar .event .fa-calendar-day", 2);
|
testElementLength(done, ".calendar .event .fa-calendar-day", 2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Recurring event", function () {
|
describe("Recurring event", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/recurring.js");
|
helpers.startApplication("tests/configs/modules/calendar/recurring.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the recurring birthday event 6 times", () => {
|
it("should show the recurring birthday event 6 times", (done) => {
|
||||||
testElementLength(".calendar .event", 6);
|
testElementLength(done, ".calendar .event", 6);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
process.setMaxListeners(0);
|
process.setMaxListeners(0);
|
||||||
for (let i = -12; i < 12; i++) {
|
for (let i = -12; i < 12; i++) {
|
||||||
describe("Recurring event per timezone", function () {
|
describe("Recurring event per timezone", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
Date.prototype.getTimezoneOffset = function () {
|
Date.prototype.getTimezoneOffset = () => {
|
||||||
return i * 60;
|
return i * 60;
|
||||||
};
|
};
|
||||||
helpers.startApplication("tests/configs/modules/calendar/recurring.js");
|
helpers.startApplication("tests/configs/modules/calendar/recurring.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain text "Mar 25th" in timezone UTC ' + -i, () => {
|
it('should contain text "Mar 25th" in timezone UTC ' + -i, (done) => {
|
||||||
testTextContain(".calendar", "Mar 25th");
|
testTextContain(done, ".calendar", "Mar 25th");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Changed port", function () {
|
describe("Changed port", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/changed-port.js");
|
helpers.startApplication("tests/configs/modules/calendar/changed-port.js");
|
||||||
serverBasicAuth.listen(8010);
|
serverBasicAuth.listen(8010);
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(function (done) {
|
afterAll((done) => {
|
||||||
serverBasicAuth.close(done());
|
serverBasicAuth.close(done());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return TestEvents", function () {
|
it("should return TestEvents", (done) => {
|
||||||
testElementLength(".calendar .event", 0, "not");
|
testElementLength(done, ".calendar .event", 0, "not");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Basic auth", function () {
|
describe("Basic auth", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/basic-auth.js");
|
helpers.startApplication("tests/configs/modules/calendar/basic-auth.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return TestEvents", function () {
|
it("should return TestEvents", (done) => {
|
||||||
testElementLength(".calendar .event", 0, "not");
|
testElementLength(done, ".calendar .event", 0, "not");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Basic auth by default", function () {
|
describe("Basic auth by default", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/auth-default.js");
|
helpers.startApplication("tests/configs/modules/calendar/auth-default.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return TestEvents", function () {
|
it("should return TestEvents", (done) => {
|
||||||
testElementLength(".calendar .event", 0, "not");
|
testElementLength(done, ".calendar .event", 0, "not");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Basic auth backward compatibility configuration: DEPRECATED", function () {
|
describe("Basic auth backward compatibility configuration: DEPRECATED", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/old-basic-auth.js");
|
helpers.startApplication("tests/configs/modules/calendar/old-basic-auth.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return TestEvents", function () {
|
it("should return TestEvents", (done) => {
|
||||||
testElementLength(".calendar .event", 0, "not");
|
testElementLength(done, ".calendar .event", 0, "not");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Fail Basic auth", function () {
|
describe("Fail Basic auth", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/calendar/fail-basic-auth.js");
|
helpers.startApplication("tests/configs/modules/calendar/fail-basic-auth.js");
|
||||||
serverBasicAuth.listen(8020);
|
serverBasicAuth.listen(8020);
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(function (done) {
|
afterAll((done) => {
|
||||||
serverBasicAuth.close(done());
|
serverBasicAuth.close(done());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show Unauthorized error", function () {
|
it("should show Unauthorized error", (done) => {
|
||||||
testTextContain(".calendar", "Error in the calendar module. Authorization failed");
|
testTextContain(done, ".calendar", "Error in the calendar module. Authorization failed");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,72 +1,73 @@
|
|||||||
const helpers = require("../global-setup");
|
const helpers = require("../global-setup");
|
||||||
|
|
||||||
describe("Clock set to spanish language module", function () {
|
describe("Clock set to spanish language module", () => {
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
const testMatch = function (element, regex) {
|
const testMatch = (done, element, regex) => {
|
||||||
helpers.waitForElement(element).then((elem) => {
|
helpers.waitForElement(element).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toMatch(regex);
|
expect(elem.textContent).toMatch(regex);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("with default 24hr clock config", function () {
|
describe("with default 24hr clock config", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/es/clock_24hr.js");
|
helpers.startApplication("tests/configs/modules/clock/es/clock_24hr.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows date with correct format", function () {
|
it("shows date with correct format", (done) => {
|
||||||
const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/;
|
const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/;
|
||||||
testMatch(".clock .date", dateRegex);
|
testMatch(done, ".clock .date", dateRegex);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows time in 24hr format", function () {
|
it("shows time in 24hr format", (done) => {
|
||||||
const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/;
|
const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with default 12hr clock config", function () {
|
describe("with default 12hr clock config", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/es/clock_12hr.js");
|
helpers.startApplication("tests/configs/modules/clock/es/clock_12hr.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows date with correct format", function () {
|
it("shows date with correct format", (done) => {
|
||||||
const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/;
|
const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/;
|
||||||
testMatch(".clock .date", dateRegex);
|
testMatch(done, ".clock .date", dateRegex);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows time in 12hr format", function () {
|
it("shows time in 12hr format", (done) => {
|
||||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/;
|
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with showPeriodUpper config enabled", function () {
|
describe("with showPeriodUpper config enabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/es/clock_showPeriodUpper.js");
|
helpers.startApplication("tests/configs/modules/clock/es/clock_showPeriodUpper.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows 12hr time with upper case AM/PM", function () {
|
it("shows 12hr time with upper case AM/PM", (done) => {
|
||||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/;
|
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with showWeek config enabled", function () {
|
describe("with showWeek config enabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/es/clock_showWeek.js");
|
helpers.startApplication("tests/configs/modules/clock/es/clock_showWeek.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows week with correct format", function () {
|
it("shows week with correct format", (done) => {
|
||||||
const weekRegex = /^Semana [0-9]{1,2}$/;
|
const weekRegex = /^Semana [0-9]{1,2}$/;
|
||||||
testMatch(".clock .week", weekRegex);
|
testMatch(done, ".clock .week", weekRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,118 +1,121 @@
|
|||||||
const helpers = require("../global-setup");
|
const helpers = require("../global-setup");
|
||||||
const moment = require("moment");
|
const moment = require("moment");
|
||||||
|
|
||||||
describe("Clock module", function () {
|
describe("Clock module", () => {
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
const testMatch = function (element, regex) {
|
const testMatch = (done, element, regex) => {
|
||||||
helpers.waitForElement(element).then((elem) => {
|
helpers.waitForElement(element).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toMatch(regex);
|
expect(elem.textContent).toMatch(regex);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("with default 24hr clock config", function () {
|
describe("with default 24hr clock config", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_24hr.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_24hr.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the date in the correct format", function () {
|
it("should show the date in the correct format", (done) => {
|
||||||
const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/;
|
const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/;
|
||||||
testMatch(".clock .date", dateRegex);
|
testMatch(done, ".clock .date", dateRegex);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the time in 24hr format", function () {
|
it("should show the time in 24hr format", (done) => {
|
||||||
const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/;
|
const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with default 12hr clock config", function () {
|
describe("with default 12hr clock config", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_12hr.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_12hr.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the date in the correct format", function () {
|
it("should show the date in the correct format", (done) => {
|
||||||
const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/;
|
const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/;
|
||||||
testMatch(".clock .date", dateRegex);
|
testMatch(done, ".clock .date", dateRegex);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the time in 12hr format", function () {
|
it("should show the time in 12hr format", (done) => {
|
||||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/;
|
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with showPeriodUpper config enabled", function () {
|
describe("with showPeriodUpper config enabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_showPeriodUpper.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_showPeriodUpper.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show 12hr time with upper case AM/PM", function () {
|
it("should show 12hr time with upper case AM/PM", (done) => {
|
||||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/;
|
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with displaySeconds config disabled", function () {
|
describe("with displaySeconds config disabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_displaySeconds_false.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_displaySeconds_false.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show 12hr time without seconds am/pm", function () {
|
it("should show 12hr time without seconds am/pm", (done) => {
|
||||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[ap]m$/;
|
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[ap]m$/;
|
||||||
testMatch(".clock .time", timeRegex);
|
testMatch(done, ".clock .time", timeRegex);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with showTime config disabled", function () {
|
describe("with showTime config disabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_showTime.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_showTime.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show not show the time when digital clock is shown", function () {
|
it("should not show the time when digital clock is shown", (done) => {
|
||||||
helpers.waitForElement(".clock .digital .time").then((elem) => {
|
const elem = document.querySelector(".clock .digital .time");
|
||||||
expect(elem).toBe(null);
|
done();
|
||||||
});
|
expect(elem).toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with showWeek config enabled", function () {
|
describe("with showWeek config enabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_showWeek.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_showWeek.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the week in the correct format", function () {
|
it("should show the week in the correct format", (done) => {
|
||||||
const weekRegex = /^Week [0-9]{1,2}$/;
|
const weekRegex = /^Week [0-9]{1,2}$/;
|
||||||
testMatch(".clock .week", weekRegex);
|
testMatch(done, ".clock .week", weekRegex);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the week with the correct number of week of year", function () {
|
it("should show the week with the correct number of week of year", (done) => {
|
||||||
const currentWeekNumber = moment().week();
|
const currentWeekNumber = moment().week();
|
||||||
const weekToShow = "Week " + currentWeekNumber;
|
const weekToShow = "Week " + currentWeekNumber;
|
||||||
helpers.waitForElement(".clock .week").then((elem) => {
|
helpers.waitForElement(".clock .week").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toBe(weekToShow);
|
expect(elem.textContent).toBe(weekToShow);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with analog clock face enabled", function () {
|
describe("with analog clock face enabled", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/clock/clock_analog.js");
|
helpers.startApplication("tests/configs/modules/clock/clock_analog.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the analog clock face", () => {
|
it("should show the analog clock face", (done) => {
|
||||||
helpers.waitForElement(".clockCircle").then((elem) => {
|
helpers.waitForElement(".clockCircle").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,87 +3,95 @@ const helpers = require("../global-setup");
|
|||||||
/**
|
/**
|
||||||
* move similar tests in function doTest
|
* move similar tests in function doTest
|
||||||
*
|
*
|
||||||
|
* @param {string} done test done
|
||||||
* @param {Array} complimentsArray The array of compliments.
|
* @param {Array} complimentsArray The array of compliments.
|
||||||
*/
|
*/
|
||||||
function doTest(complimentsArray) {
|
const doTest = (done, complimentsArray) => {
|
||||||
helpers.waitForElement(".compliments").then((elem) => {
|
helpers.waitForElement(".compliments").then((elem) => {
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
helpers.waitForElement(".module-content").then((elem) => {
|
helpers.waitForElement(".module-content").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(complimentsArray).toContain(elem.textContent);
|
expect(complimentsArray).toContain(elem.textContent);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
describe("Compliments module", function () {
|
describe("Compliments module", () => {
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("parts of days", function () {
|
describe("parts of days", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/compliments/compliments_parts_day.js");
|
helpers.startApplication("tests/configs/modules/compliments/compliments_parts_day.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("if Morning compliments for that part of day", function () {
|
it("if Morning compliments for that part of day", (done) => {
|
||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
if (hour >= 3 && hour < 12) {
|
if (hour >= 3 && hour < 12) {
|
||||||
// if morning check
|
// if morning check
|
||||||
doTest(["Hi", "Good Morning", "Morning test"]);
|
doTest(done, ["Hi", "Good Morning", "Morning test"]);
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("if Afternoon show Compliments for that part of day", function () {
|
it("if Afternoon show Compliments for that part of day", (done) => {
|
||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
if (hour >= 12 && hour < 17) {
|
if (hour >= 12 && hour < 17) {
|
||||||
// if afternoon check
|
// if afternoon check
|
||||||
doTest(["Hello", "Good Afternoon", "Afternoon test"]);
|
doTest(done, ["Hello", "Good Afternoon", "Afternoon test"]);
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("if Evening show Compliments for that part of day", function () {
|
it("if Evening show Compliments for that part of day", (done) => {
|
||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
if (!(hour >= 3 && hour < 12) && !(hour >= 12 && hour < 17)) {
|
if (!(hour >= 3 && hour < 12) && !(hour >= 12 && hour < 17)) {
|
||||||
// if evening check
|
// if evening check
|
||||||
doTest(["Hello There", "Good Evening", "Evening test"]);
|
doTest(done, ["Hello There", "Good Evening", "Evening test"]);
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Feature anytime in compliments module", function () {
|
describe("Feature anytime in compliments module", () => {
|
||||||
describe("Set anytime and empty compliments for morning, evening and afternoon ", function () {
|
describe("Set anytime and empty compliments for morning, evening and afternoon ", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/compliments/compliments_anytime.js");
|
helpers.startApplication("tests/configs/modules/compliments/compliments_anytime.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Show anytime because if configure empty parts of day compliments and set anytime compliments", function () {
|
it("Show anytime because if configure empty parts of day compliments and set anytime compliments", (done) => {
|
||||||
doTest(["Anytime here"]);
|
doTest(done, ["Anytime here"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Only anytime present in configuration compliments", function () {
|
describe("Only anytime present in configuration compliments", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/compliments/compliments_only_anytime.js");
|
helpers.startApplication("tests/configs/modules/compliments/compliments_only_anytime.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Show anytime compliments", function () {
|
it("Show anytime compliments", (done) => {
|
||||||
doTest(["Anytime here"]);
|
doTest(done, ["Anytime here"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Feature date in compliments module", function () {
|
describe("Feature date in compliments module", () => {
|
||||||
describe("Set date and empty compliments for anytime, morning, evening and afternoon", function () {
|
describe("Set date and empty compliments for anytime, morning, evening and afternoon", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/compliments/compliments_date.js");
|
helpers.startApplication("tests/configs/modules/compliments/compliments_date.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Show happy new year compliment on new years day", function () {
|
it("Show happy new year compliment on new years day", (done) => {
|
||||||
doTest(["Happy new year!"]);
|
doTest(done, ["Happy new year!"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,32 +1,34 @@
|
|||||||
const helpers = require("../global-setup");
|
const helpers = require("../global-setup");
|
||||||
|
|
||||||
describe("Test helloworld module", function () {
|
describe("Test helloworld module", () => {
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("helloworld set config text", function () {
|
describe("helloworld set config text", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/helloworld/helloworld.js");
|
helpers.startApplication("tests/configs/modules/helloworld/helloworld.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Test message helloworld module", function () {
|
it("Test message helloworld module", (done) => {
|
||||||
helpers.waitForElement(".helloworld").then((elem) => {
|
helpers.waitForElement(".helloworld").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Test HelloWorld Module");
|
expect(elem.textContent).toContain("Test HelloWorld Module");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("helloworld default config text", function () {
|
describe("helloworld default config text", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/helloworld/helloworld_default.js");
|
helpers.startApplication("tests/configs/modules/helloworld/helloworld_default.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Test message helloworld module", function () {
|
it("Test message helloworld module", (done) => {
|
||||||
helpers.waitForElement(".helloworld").then((elem) => {
|
helpers.waitForElement(".helloworld").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Hello World!");
|
expect(elem.textContent).toContain("Hello World!");
|
||||||
});
|
});
|
||||||
|
@ -1,80 +1,88 @@
|
|||||||
const helpers = require("../global-setup");
|
const helpers = require("../global-setup");
|
||||||
|
|
||||||
describe("Newsfeed module", function () {
|
describe("Newsfeed module", () => {
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Default configuration", function () {
|
describe("Default configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/newsfeed/default.js");
|
helpers.startApplication("tests/configs/modules/newsfeed/default.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the newsfeed title", function () {
|
it("should show the newsfeed title", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .newsfeed-source").then((elem) => {
|
helpers.waitForElement(".newsfeed .newsfeed-source").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Rodrigo Ramirez Blog");
|
expect(elem.textContent).toContain("Rodrigo Ramirez Blog");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the newsfeed article", function () {
|
it("should show the newsfeed article", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .newsfeed-title").then((elem) => {
|
helpers.waitForElement(".newsfeed .newsfeed-title").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("QPanel");
|
expect(elem.textContent).toContain("QPanel");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should NOT show the newsfeed description", () => {
|
it("should NOT show the newsfeed description", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .newsfeed-desc").then((elem) => {
|
helpers.waitForElement(".newsfeed").then((elem) => {
|
||||||
expect(elem).toBe(null);
|
const element = document.querySelector(".newsfeed .newsfeed-desc");
|
||||||
|
done();
|
||||||
|
expect(element).toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Custom configuration", function () {
|
describe("Custom configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/newsfeed/prohibited_words.js");
|
helpers.startApplication("tests/configs/modules/newsfeed/prohibited_words.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not show articles with prohibited words", function () {
|
it("should not show articles with prohibited words", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .newsfeed-title").then((elem) => {
|
helpers.waitForElement(".newsfeed .newsfeed-title").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Problema VirtualBox");
|
expect(elem.textContent).toContain("Problema VirtualBox");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the newsfeed description", () => {
|
it("should show the newsfeed description", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .newsfeed-desc").then((elem) => {
|
helpers.waitForElement(".newsfeed .newsfeed-desc").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent.length).not.toBe(0);
|
expect(elem.textContent.length).not.toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Invalid configuration", function () {
|
describe("Invalid configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/newsfeed/incorrect_url.js");
|
helpers.startApplication("tests/configs/modules/newsfeed/incorrect_url.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show malformed url warning", function () {
|
it("should show malformed url warning", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .small").then((elem) => {
|
helpers.waitForElement(".newsfeed .small", "No news at the moment.").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Error in the Newsfeed module. Malformed url.");
|
expect(elem.textContent).toContain("Error in the Newsfeed module. Malformed url.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Ignore items", function () {
|
describe("Ignore items", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/newsfeed/ignore_items.js");
|
helpers.startApplication("tests/configs/modules/newsfeed/ignore_items.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show empty items info message", function () {
|
it("should show empty items info message", (done) => {
|
||||||
helpers.waitForElement(".newsfeed .small").then((elem) => {
|
helpers.waitForElement(".newsfeed .small").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("No news at the moment.");
|
expect(elem.textContent).toContain("No news at the moment.");
|
||||||
});
|
});
|
||||||
|
@ -4,13 +4,15 @@ const path = require("path");
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const { generateWeather, generateWeatherForecast } = require("./mocks");
|
const { generateWeather, generateWeatherForecast } = require("./mocks");
|
||||||
|
|
||||||
describe("Weather module", function () {
|
describe("Weather module", () => {
|
||||||
/**
|
/**
|
||||||
|
* @param {string} done test done
|
||||||
* @param {string} element css selector
|
* @param {string} element css selector
|
||||||
* @param {string} result Expected text in given selector
|
* @param {string} result Expected text in given selector
|
||||||
*/
|
*/
|
||||||
function getText(element, result) {
|
const getText = (done, element, result) => {
|
||||||
helpers.waitForElement(element).then((elem) => {
|
helpers.waitForElement(element).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(
|
expect(
|
||||||
elem.textContent
|
elem.textContent
|
||||||
@ -19,14 +21,14 @@ describe("Weather module", function () {
|
|||||||
.replace(/[ ]+/g, " ")
|
.replace(/[ ]+/g, " ")
|
||||||
).toBe(result);
|
).toBe(result);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} configFile path to configuration file
|
* @param {string} configFile path to configuration file
|
||||||
* @param {string} additionalMockData special data for mocking
|
* @param {string} additionalMockData special data for mocking
|
||||||
* @param {string} callback callback
|
* @param {string} callback callback
|
||||||
*/
|
*/
|
||||||
function startApp(configFile, additionalMockData, callback) {
|
const startApp = (configFile, additionalMockData, callback) => {
|
||||||
let mockWeather;
|
let mockWeather;
|
||||||
if (configFile.includes("forecast")) {
|
if (configFile.includes("forecast")) {
|
||||||
mockWeather = generateWeatherForecast(additionalMockData);
|
mockWeather = generateWeatherForecast(additionalMockData);
|
||||||
@ -38,94 +40,98 @@ describe("Weather module", function () {
|
|||||||
fs.writeFileSync(path.resolve(__dirname + "../../../../config/config.js"), content);
|
fs.writeFileSync(path.resolve(__dirname + "../../../../config/config.js"), content);
|
||||||
helpers.startApplication("");
|
helpers.startApplication("");
|
||||||
helpers.getDocument(callback);
|
helpers.getDocument(callback);
|
||||||
}
|
};
|
||||||
|
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Current weather", function () {
|
describe("Current weather", () => {
|
||||||
describe("Default configuration", function () {
|
describe("Default configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/currentweather_default.js", {}, done);
|
startApp("tests/configs/modules/weather/currentweather_default.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render wind speed and wind direction", function () {
|
it("should render wind speed and wind direction", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(2)", "6 WSW");
|
getText(done, ".weather .normal.medium span:nth-child(2)", "6 WSW"); // now "12"
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render temperature with icon", function () {
|
it("should render temperature with icon", (done) => {
|
||||||
getText(".weather .large.light span.bright", "1.5°");
|
getText(done, ".weather .large.light span.bright", "1.5°"); // now "1°C"
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render feels like temperature", function () {
|
it("should render feels like temperature", (done) => {
|
||||||
getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°");
|
getText(done, ".weather .normal.medium.feelslike span.dimmed", "Feels like -5.6°"); // now "Feels like -6°C"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Default configuration with sunrise", function () {
|
describe("Default configuration with sunrise", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
const sunrise = moment().startOf("day").unix();
|
const sunrise = moment().startOf("day").unix();
|
||||||
const sunset = moment().startOf("day").unix();
|
const sunset = moment().startOf("day").unix();
|
||||||
startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } }, done);
|
startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } }, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render sunrise", function () {
|
it("should render sunrise", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(4)", "12:00 am");
|
getText(done, ".weather .normal.medium span:nth-child(4)", "12:00 am");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Default configuration with sunset", function () {
|
describe("Default configuration with sunset", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
const sunrise = moment().startOf("day").unix();
|
const sunrise = moment().startOf("day").unix();
|
||||||
const sunset = moment().endOf("day").unix();
|
const sunset = moment().endOf("day").unix();
|
||||||
startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } }, done);
|
startApp("tests/configs/modules/weather/currentweather_default.js", { sys: { sunrise, sunset } }, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render sunset", function () {
|
it("should render sunset", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(4)", "11:59 pm");
|
getText(done, ".weather .normal.medium span:nth-child(4)", "11:59 pm");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Compliments Integration", function () {
|
describe("Compliments Integration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/currentweather_compliments.js", {}, done);
|
startApp("tests/configs/modules/weather/currentweather_compliments.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render a compliment based on the current weather", function () {
|
it("should render a compliment based on the current weather", (done) => {
|
||||||
getText(".compliments .module-content span", "snow");
|
getText(done, ".compliments .module-content span", "snow");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Configuration Options", function () {
|
describe("Configuration Options", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/currentweather_options.js", {}, done);
|
startApp("tests/configs/modules/weather/currentweather_options.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render useBeaufort = false", function () {
|
it("should render useBeaufort = false", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(2)", "12");
|
getText(done, ".weather .normal.medium span:nth-child(2)", "12");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render showWindDirectionAsArrow = true", function () {
|
it("should render showWindDirectionAsArrow = true", (done) => {
|
||||||
helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-up").then((elem) => {
|
helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-up").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.outerHTML).toContain("transform:rotate(250deg);");
|
expect(elem.outerHTML).toContain("transform:rotate(250deg);");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render showHumidity = true", function () {
|
it("should render showHumidity = true", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(3)", "93.7");
|
getText(done, ".weather .normal.medium span:nth-child(3)", "93.7");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render degreeLabel = true", function () {
|
it("should render degreeLabel = true for temp", (done) => {
|
||||||
getText(".weather .large.light span.bright", "1°C");
|
getText(done, ".weather .large.light span.bright", "1°C");
|
||||||
getText(".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C");
|
});
|
||||||
|
|
||||||
|
it("should render degreeLabel = true for feels like", (done) => {
|
||||||
|
getText(done, ".weather .normal.medium.feelslike span.dimmed", "Feels like -6°C");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Current weather units", function () {
|
describe("Current weather units", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp(
|
startApp(
|
||||||
"tests/configs/modules/weather/currentweather_units.js",
|
"tests/configs/modules/weather/currentweather_units.js",
|
||||||
{
|
{
|
||||||
@ -142,98 +148,108 @@ describe("Weather module", function () {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render imperial units", function () {
|
it("should render imperial units for wind", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(2)", "6 WSW");
|
getText(done, ".weather .normal.medium span:nth-child(2)", "6 WSW");
|
||||||
getText(".weather .large.light span.bright", "34,7°");
|
|
||||||
getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render custom decimalSymbol = ','", function () {
|
it("should render imperial units for temp", (done) => {
|
||||||
getText(".weather .normal.medium span:nth-child(3)", "93,7");
|
getText(done, ".weather .large.light span.bright", "34,7°");
|
||||||
getText(".weather .large.light span.bright", "34,7°");
|
});
|
||||||
getText(".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°");
|
|
||||||
|
it("should render imperial units for feels like", (done) => {
|
||||||
|
getText(done, ".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render custom decimalSymbol = ',' for humidity", (done) => {
|
||||||
|
getText(done, ".weather .normal.medium span:nth-child(3)", "93,7");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render custom decimalSymbol = ',' for temp", (done) => {
|
||||||
|
getText(done, ".weather .large.light span.bright", "34,7°");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render custom decimalSymbol = ',' for feels like", (done) => {
|
||||||
|
getText(done, ".weather .normal.medium.feelslike span.dimmed", "Feels like 22,0°");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Weather Forecast", function () {
|
describe("Weather Forecast", () => {
|
||||||
describe("Default configuration", function () {
|
describe("Default configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/forecastweather_default.js", {}, done);
|
startApp("tests/configs/modules/weather/forecastweather_default.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render days", function () {
|
const days = ["Today", "Tomorrow", "Sun", "Mon", "Tue"];
|
||||||
const days = ["Today", "Tomorrow", "Sun", "Mon", "Tue"];
|
for (const [index, day] of days.entries()) {
|
||||||
|
it("should render day " + day, (done) => {
|
||||||
|
getText(done, `.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const [index, day] of days.entries()) {
|
const icons = ["day-cloudy", "rain", "day-sunny", "day-sunny", "day-sunny"];
|
||||||
getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day);
|
for (const [index, icon] of icons.entries()) {
|
||||||
}
|
it("should render icon " + icon, (done) => {
|
||||||
});
|
|
||||||
|
|
||||||
it("should render icons", function () {
|
|
||||||
const icons = ["day-cloudy", "rain", "day-sunny", "day-sunny", "day-sunny"];
|
|
||||||
|
|
||||||
for (const [index, icon] of icons.entries()) {
|
|
||||||
helpers.waitForElement(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(2) span.wi-${icon}`).then((elem) => {
|
helpers.waitForElement(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(2) span.wi-${icon}`).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
it("should render max temperatures", function () {
|
const maxTemps = ["24.4°", "21.0°", "22.9°", "23.4°", "20.6°"];
|
||||||
const temperatures = ["24.4°", "21.0°", "22.9°", "23.4°", "20.6°"];
|
for (const [index, temp] of maxTemps.entries()) {
|
||||||
|
it("should render max temperature " + temp, (done) => {
|
||||||
|
getText(done, `.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const [index, temp] of temperatures.entries()) {
|
const minTemps = ["15.3°", "13.6°", "13.8°", "13.9°", "10.9°"];
|
||||||
getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp);
|
for (const [index, temp] of minTemps.entries()) {
|
||||||
}
|
it("should render min temperature " + temp, (done) => {
|
||||||
});
|
getText(done, `.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
it("should render min temperatures", function () {
|
const opacities = [1, 1, 0.8, 0.5333333333333333, 0.2666666666666667];
|
||||||
const temperatures = ["15.3°", "13.6°", "13.8°", "13.9°", "10.9°"];
|
for (const [index, opacity] of opacities.entries()) {
|
||||||
|
it("should render fading of rows with opacity=" + opacity, (done) => {
|
||||||
for (const [index, temp] of temperatures.entries()) {
|
|
||||||
getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(4)`, temp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render fading of rows", function () {
|
|
||||||
const opacities = [1, 1, 0.8, 0.5333333333333333, 0.2666666666666667];
|
|
||||||
|
|
||||||
for (const [index, opacity] of opacities.entries()) {
|
|
||||||
helpers.waitForElement(`.weather table.small tr:nth-child(${index + 1})`).then((elem) => {
|
helpers.waitForElement(`.weather table.small tr:nth-child(${index + 1})`).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.outerHTML).toContain(`<tr style="opacity: ${opacity};">`);
|
expect(elem.outerHTML).toContain(`<tr style="opacity: ${opacity};">`);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Absolute configuration", function () {
|
describe("Absolute configuration", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/forecastweather_absolute.js", {}, done);
|
startApp("tests/configs/modules/weather/forecastweather_absolute.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render days", function () {
|
const days = ["Fri", "Sat", "Sun", "Mon", "Tue"];
|
||||||
const days = ["Fri", "Sat", "Sun", "Mon", "Tue"];
|
for (const [index, day] of days.entries()) {
|
||||||
|
it("should render day " + day, (done) => {
|
||||||
for (const [index, day] of days.entries()) {
|
getText(done, `.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day);
|
||||||
getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(1)`, day);
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Configuration Options", function () {
|
describe("Configuration Options", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/forecastweather_options.js", {}, done);
|
startApp("tests/configs/modules/weather/forecastweather_options.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render custom table class", function () {
|
it("should render custom table class", (done) => {
|
||||||
helpers.waitForElement(".weather table.myTableClass").then((elem) => {
|
helpers.waitForElement(".weather table.myTableClass").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render colored rows", function () {
|
it("should render colored rows", (done) => {
|
||||||
helpers.waitForElement(".weather table.myTableClass").then((table) => {
|
helpers.waitForElement(".weather table.myTableClass").then((table) => {
|
||||||
|
done();
|
||||||
expect(table).not.toBe(null);
|
expect(table).not.toBe(null);
|
||||||
expect(table.rows).not.toBe(null);
|
expect(table.rows).not.toBe(null);
|
||||||
expect(table.rows.length).toBe(5);
|
expect(table.rows.length).toBe(5);
|
||||||
@ -241,18 +257,17 @@ describe("Weather module", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Forecast weather units", function () {
|
describe("Forecast weather units", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
startApp("tests/configs/modules/weather/forecastweather_units.js", {}, done);
|
startApp("tests/configs/modules/weather/forecastweather_units.js", {}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render custom decimalSymbol = '_'", function () {
|
const temperatures = ["24_4°", "21_0°", "22_9°", "23_4°", "20_6°"];
|
||||||
const temperatures = ["24_4°", "21_0°", "22_9°", "23_4°", "20_6°"];
|
for (const [index, temp] of temperatures.entries()) {
|
||||||
|
it("should render custom decimalSymbol = '_' for temp " + temp, (done) => {
|
||||||
for (const [index, temp] of temperatures.entries()) {
|
getText(done, `.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp);
|
||||||
getText(`.weather table.small tr:nth-child(${index + 1}) td:nth-child(3)`, temp);
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
const helpers = require("./global-setup");
|
const helpers = require("./global-setup");
|
||||||
|
|
||||||
describe("Display of modules", function () {
|
describe("Display of modules", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll(function (done) {
|
||||||
helpers.startApplication("tests/configs/modules/display.js");
|
helpers.startApplication("tests/configs/modules/display.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the test header", function () {
|
it("should show the test header", (done) => {
|
||||||
helpers.waitForElement("#module_0_helloworld .module-header").then((elem) => {
|
helpers.waitForElement("#module_0_helloworld .module-header").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
// textContent gibt hier lowercase zurück, das uppercase wird durch css realisiert, was daher nicht in textContent landet
|
// textContent gibt hier lowercase zurück, das uppercase wird durch css realisiert, was daher nicht in textContent landet
|
||||||
expect(elem.textContent).toBe("test_header");
|
expect(elem.textContent).toBe("test_header");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show no header if no header text is specified", function () {
|
it("should show no header if no header text is specified", (done) => {
|
||||||
helpers.waitForElement("#module_1_helloworld .module-header").then((elem) => {
|
helpers.waitForElement("#module_1_helloworld .module-header").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toBe("undefined");
|
expect(elem.textContent).toBe("undefined");
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
const helpers = require("./global-setup");
|
const helpers = require("./global-setup");
|
||||||
|
|
||||||
describe("Position of modules", function () {
|
describe("Position of modules", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/modules/positions.js");
|
helpers.startApplication("tests/configs/modules/positions.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -13,8 +13,9 @@ describe("Position of modules", function () {
|
|||||||
|
|
||||||
for (const position of positions) {
|
for (const position of positions) {
|
||||||
const className = position.replace("_", ".");
|
const className = position.replace("_", ".");
|
||||||
it("should show text in " + position, function () {
|
it("should show text in " + position, (done) => {
|
||||||
helpers.waitForElement("." + className).then((elem) => {
|
helpers.waitForElement("." + className).then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("Text in " + position);
|
expect(elem.textContent).toContain("Text in " + position);
|
||||||
});
|
});
|
||||||
|
@ -164,7 +164,7 @@ describe("Translations", function () {
|
|||||||
dom.window.onload = function () {
|
dom.window.onload = function () {
|
||||||
const { Translator } = dom.window;
|
const { Translator } = dom.window;
|
||||||
|
|
||||||
Translator.load(mmm, translations.en, false, function () {
|
Translator.load(mmm, translations.de, false, function () {
|
||||||
base = Object.keys(Translator.translations[mmm.name]).sort();
|
base = Object.keys(Translator.translations[mmm.name]).sort();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -175,8 +175,10 @@ describe("Translations", function () {
|
|||||||
console.log(missing);
|
console.log(missing);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Using German as the base rather than English, since
|
||||||
|
// at least one translated word doesn't exist in English.
|
||||||
for (let language in translations) {
|
for (let language in translations) {
|
||||||
if (language === "en") {
|
if (language === "de") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
const helpers = require("./global-setup");
|
const helpers = require("./global-setup");
|
||||||
|
|
||||||
describe("Check configuration without modules", function () {
|
describe("Check configuration without modules", () => {
|
||||||
beforeAll(function (done) {
|
beforeAll((done) => {
|
||||||
helpers.startApplication("tests/configs/without_modules.js");
|
helpers.startApplication("tests/configs/without_modules.js");
|
||||||
helpers.getDocument(done);
|
helpers.getDocument(done);
|
||||||
});
|
});
|
||||||
afterAll(async function () {
|
afterAll(async () => {
|
||||||
await helpers.stopApplication();
|
await helpers.stopApplication();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Show the message MagicMirror² title", function () {
|
it("Show the message MagicMirror² title", (done) => {
|
||||||
helpers.waitForElement("#module_1_helloworld .module-content").then((elem) => {
|
helpers.waitForElement("#module_1_helloworld .module-content").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("MagicMirror²");
|
expect(elem.textContent).toContain("MagicMirror²");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Show the text Michael's website", function () {
|
it("Show the text Michael's website", (done) => {
|
||||||
helpers.waitForElement("#module_5_helloworld .module-content").then((elem) => {
|
helpers.waitForElement("#module_5_helloworld .module-content").then((elem) => {
|
||||||
|
done();
|
||||||
expect(elem).not.toBe(null);
|
expect(elem).not.toBe(null);
|
||||||
expect(elem.textContent).toContain("www.michaelteeuw.nl");
|
expect(elem.textContent).toContain("www.michaelteeuw.nl");
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Updatenotification custom module returns status information without hash 1`] = `
|
exports[`Updatenotification custom module returns status information without hash 1`] = `
|
||||||
Object {
|
{
|
||||||
"behind": 7,
|
"behind": 7,
|
||||||
"current": "master",
|
"current": "master",
|
||||||
"hash": "",
|
"hash": "",
|
||||||
@ -12,7 +12,7 @@ Object {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Updatenotification default returns status information 1`] = `
|
exports[`Updatenotification default returns status information 1`] = `
|
||||||
Object {
|
{
|
||||||
"behind": 5,
|
"behind": 5,
|
||||||
"current": "develop",
|
"current": "develop",
|
||||||
"hash": "332e429a41f1a2339afd4f0ae96dd125da6beada",
|
"hash": "332e429a41f1a2339afd4f0ae96dd125da6beada",
|
||||||
@ -23,7 +23,7 @@ Object {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Updatenotification default returns status information early if isBehindInStatus 1`] = `
|
exports[`Updatenotification default returns status information early if isBehindInStatus 1`] = `
|
||||||
Object {
|
{
|
||||||
"behind": 5,
|
"behind": 5,
|
||||||
"current": "develop",
|
"current": "develop",
|
||||||
"hash": "332e429a41f1a2339afd4f0ae96dd125da6beada",
|
"hash": "332e429a41f1a2339afd4f0ae96dd125da6beada",
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
"TODAY": "Today",
|
"TODAY": "Today",
|
||||||
"TOMORROW": "Tomorrow",
|
"TOMORROW": "Tomorrow",
|
||||||
"DAYAFTERTOMORROW": "In 2 days",
|
|
||||||
"RUNNING": "Ends in",
|
"RUNNING": "Ends in",
|
||||||
"EMPTY": "No upcoming events.",
|
"EMPTY": "No upcoming events.",
|
||||||
"WEEK": "Week {weekNumber}",
|
"WEEK": "Week {weekNumber}",
|
||||||
|
42
vendor/package-lock.json
generated
vendored
42
vendor/package-lock.json
generated
vendored
@ -7,18 +7,18 @@
|
|||||||
"name": "magicmirror-vendors",
|
"name": "magicmirror-vendors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
"@fortawesome/fontawesome-free": "^6.2.0",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.4",
|
||||||
"moment-timezone": "^0.5.34",
|
"moment-timezone": "^0.5.37",
|
||||||
"nunjucks": "^3.2.3",
|
"nunjucks": "^3.2.3",
|
||||||
"suncalc": "^1.9.0",
|
"suncalc": "^1.9.0",
|
||||||
"weathericons": "^2.1.0"
|
"weathericons": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/fontawesome-free": {
|
"node_modules/@fortawesome/fontawesome-free": {
|
||||||
"version": "6.1.1",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz",
|
||||||
"integrity": "sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg==",
|
"integrity": "sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@ -43,17 +43,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/moment": {
|
"node_modules/moment": {
|
||||||
"version": "2.29.3",
|
"version": "2.29.4",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||||
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==",
|
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/moment-timezone": {
|
"node_modules/moment-timezone": {
|
||||||
"version": "0.5.34",
|
"version": "0.5.37",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.37.tgz",
|
||||||
"integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
|
"integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"moment": ">= 2.9.0"
|
"moment": ">= 2.9.0"
|
||||||
},
|
},
|
||||||
@ -98,9 +98,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": {
|
"@fortawesome/fontawesome-free": {
|
||||||
"version": "6.1.1",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz",
|
||||||
"integrity": "sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg=="
|
"integrity": "sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ=="
|
||||||
},
|
},
|
||||||
"a-sync-waterfall": {
|
"a-sync-waterfall": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -118,14 +118,14 @@
|
|||||||
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="
|
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="
|
||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.29.3",
|
"version": "2.29.4",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||||
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
|
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
|
||||||
},
|
},
|
||||||
"moment-timezone": {
|
"moment-timezone": {
|
||||||
"version": "0.5.34",
|
"version": "0.5.37",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.37.tgz",
|
||||||
"integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
|
"integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"moment": ">= 2.9.0"
|
"moment": ">= 2.9.0"
|
||||||
}
|
}
|
||||||
|
6
vendor/package.json
vendored
Executable file → Normal file
6
vendor/package.json
vendored
Executable file → Normal file
@ -10,9 +10,9 @@
|
|||||||
"url": "https://github.com/MichMich/MagicMirror/issues"
|
"url": "https://github.com/MichMich/MagicMirror/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
"@fortawesome/fontawesome-free": "^6.2.0",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.4",
|
||||||
"moment-timezone": "^0.5.34",
|
"moment-timezone": "^0.5.37",
|
||||||
"nunjucks": "^3.2.3",
|
"nunjucks": "^3.2.3",
|
||||||
"suncalc": "^1.9.0",
|
"suncalc": "^1.9.0",
|
||||||
"weathericons": "^2.1.0"
|
"weathericons": "^2.1.0"
|
||||||
|
0
vendor/vendor.js
vendored
Executable file → Normal file
0
vendor/vendor.js
vendored
Executable file → Normal file
Loading…
x
Reference in New Issue
Block a user