Update weather tests (#3008)

Added a few tests for sunset/sunrise and feelsLike 
Lets see if they run through first...

Co-authored-by: veeck <michael@veeck.de>
This commit is contained in:
Veeck 2023-01-26 19:43:34 +01:00 committed by GitHub
parent 58b9ddcd9f
commit a8dc563a31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 885 additions and 849 deletions

View File

@ -27,6 +27,7 @@ _This release is scheduled to be released on 2023-04-01._
- Use develop as target branch for dependabot - Use develop as target branch for dependabot
- Update issue template and contributing doc - Update issue template and contributing doc
- Update weather tests
- Changed updatenotification module for MagicMirror repo only: Send only notifications for `master` if there is a tag on a newer commit - Changed updatenotification module for MagicMirror repo only: Send only notifications for `master` if there is a tag on a newer commit
- Update dates in Calendar widgets every minute - Update dates in Calendar widgets every minute

View File

@ -25,7 +25,7 @@ module.exports = async () => {
testPathIgnorePatterns: ["<rootDir>/tests/e2e/helpers/", "<rootDir>/tests/e2e/mocks"] testPathIgnorePatterns: ["<rootDir>/tests/e2e/helpers/", "<rootDir>/tests/e2e/mocks"]
} }
], ],
collectCoverageFrom: ["./clientonly/**/*.js", "./js/**/*.js", "./modules/**/*.js", "./serveronly/**/*.js"], collectCoverageFrom: ["./clientonly/**/*.js", "./js/**/*.js", "./modules/default/**/*.js", "./serveronly/**/*.js"],
coverageReporters: ["lcov", "text"], coverageReporters: ["lcov", "text"],
coverageProvider: "v8" coverageProvider: "v8"
}; };

View File

@ -11,6 +11,10 @@
* Currently this is focused on the information which is necessary for the current weather. * Currently this is focused on the information which is necessary for the current weather.
* As soon as we start implementing the forecast, mode properties will be added. * As soon as we start implementing the forecast, mode properties will be added.
*/ */
/**
* @external Moment
*/
class WeatherObject { class WeatherObject {
/** /**
* Constructor for a WeatherObject * Constructor for a WeatherObject
@ -69,34 +73,23 @@ class WeatherObject {
} }
} }
nextSunAction() { /**
return moment().isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise"; * Determines if the sun sets or rises next. Uses the current time and not
* the date from the weather-forecast.
*
* @param {Moment} date an optional date where you want to get the next
* action for. Useful only in tests, defaults to the current time.
* @returns {string} "sunset" or "sunrise"
*/
nextSunAction(date = moment()) {
return date.isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise";
} }
feelsLike() { feelsLike() {
if (this.feelsLikeTemp) { if (this.feelsLikeTemp) {
return this.feelsLikeTemp; return this.feelsLikeTemp;
} }
const windInMph = WeatherUtils.convertWind(this.windSpeed, "imperial"); return WeatherUtils.calculateFeelsLike(this.temperature, this.windSpeed, this.humidity);
const tempInF = WeatherUtils.convertTemp(this.temperature, "imperial");
let feelsLike = tempInF;
if (windInMph > 3 && tempInF < 50) {
feelsLike = Math.round(35.74 + 0.6215 * tempInF - 35.75 * Math.pow(windInMph, 0.16) + 0.4275 * tempInF * Math.pow(windInMph, 0.16));
} else if (tempInF > 80 && this.humidity > 40) {
feelsLike =
-42.379 +
2.04901523 * tempInF +
10.14333127 * this.humidity -
0.22475541 * tempInF * this.humidity -
6.83783 * Math.pow(10, -3) * tempInF * tempInF -
5.481717 * Math.pow(10, -2) * this.humidity * this.humidity +
1.22874 * Math.pow(10, -3) * tempInF * tempInF * this.humidity +
8.5282 * Math.pow(10, -4) * tempInF * this.humidity * this.humidity -
1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity;
}
return ((feelsLike - 32) * 5) / 9;
} }
/** /**
@ -105,7 +98,8 @@ class WeatherObject {
* @returns {boolean} true if it is at dayTime * @returns {boolean} true if it is at dayTime
*/ */
isDayTime() { isDayTime() {
return this.date.isBetween(this.sunrise, this.sunset, undefined, "[]"); const now = !this.date ? moment() : this.date;
return now.isBetween(this.sunrise, this.sunset, undefined, "[]");
} }
/** /**

View File

@ -90,6 +90,29 @@ const WeatherUtils = {
convertWindToMs(kmh) { convertWindToMs(kmh) {
return kmh * 0.27777777777778; return kmh * 0.27777777777778;
},
calculateFeelsLike(temperature, windSpeed, humidity) {
const windInMph = this.convertWind(windSpeed, "imperial");
const tempInF = this.convertTemp(temperature, "imperial");
let feelsLike = tempInF;
if (windInMph > 3 && tempInF < 50) {
feelsLike = Math.round(35.74 + 0.6215 * tempInF - 35.75 * Math.pow(windInMph, 0.16) + 0.4275 * tempInF * Math.pow(windInMph, 0.16));
} else if (tempInF > 80 && humidity > 40) {
feelsLike =
-42.379 +
2.04901523 * tempInF +
10.14333127 * humidity -
0.22475541 * tempInF * humidity -
6.83783 * Math.pow(10, -3) * tempInF * tempInF -
5.481717 * Math.pow(10, -2) * humidity * humidity +
1.22874 * Math.pow(10, -3) * tempInF * tempInF * humidity +
8.5282 * Math.pow(10, -4) * tempInF * humidity * humidity -
1.99 * Math.pow(10, -6) * tempInF * tempInF * humidity * humidity;
}
return ((feelsLike - 32) * 5) / 9;
} }
}; };

1626
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -51,15 +51,15 @@
"devDependencies": { "devDependencies": {
"eslint-config-prettier": "^8.6.0", "eslint-config-prettier": "^8.6.0",
"eslint-plugin-jest": "^27.2.1", "eslint-plugin-jest": "^27.2.1",
"eslint-plugin-jsdoc": "^39.6.4", "eslint-plugin-jsdoc": "^39.6.8",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"express-basic-auth": "^1.2.1", "express-basic-auth": "^1.2.1",
"husky": "^8.0.3", "husky": "^8.0.3",
"jest": "^29.3.1", "jest": "^29.4.0",
"jsdom": "^21.0.0", "jsdom": "^21.1.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"playwright": "^1.29.2", "playwright": "^1.30.0",
"prettier": "^2.8.2", "prettier": "^2.8.3",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"sinon": "^15.0.1", "sinon": "^15.0.1",
"stylelint": "^14.16.1", "stylelint": "^14.16.1",
@ -69,13 +69,13 @@
"suncalc": "^1.9.0" "suncalc": "^1.9.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"electron": "^22.0.0" "electron": "^22.1.0"
}, },
"dependencies": { "dependencies": {
"colors": "^1.4.0", "colors": "^1.4.0",
"console-stamp": "^3.1.0", "console-stamp": "^3.1.0",
"digest-fetch": "^2.0.1", "digest-fetch": "^2.0.1",
"eslint": "^8.31.0", "eslint": "^8.32.0",
"express": "^4.18.2", "express": "^4.18.2",
"express-ipfilter": "^1.3.1", "express-ipfilter": "^1.3.1",
"feedme": "^2.0.2", "feedme": "^2.0.2",

View File

@ -8,7 +8,6 @@ exports.startApplication = async (configFilename, systemDate = null, electronPar
global.page = null; global.page = null;
process.env.MM_CONFIG_FILE = configFilename; process.env.MM_CONFIG_FILE = configFilename;
process.env.TZ = "GMT"; process.env.TZ = "GMT";
jest.retryTimes(3);
global.electronApp = await electron.launch({ args: electronParams }); global.electronApp = await electron.launch({ args: electronParams });
await global.electronApp.firstWindow(); await global.electronApp.firstWindow();

View File

@ -15,23 +15,40 @@ describe("WeatherObject", () => {
}); });
it("should return true for daytime at noon", () => { it("should return true for daytime at noon", () => {
weatherobject.date = moment(12, "HH"); weatherobject.date = moment("12:00", "HH:mm");
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327); weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
expect(weatherobject.isDayTime()).toBe(true); expect(weatherobject.isDayTime()).toBe(true);
}); });
it("should return false for daytime at midnight", () => { it("should return false for daytime at midnight", () => {
weatherobject.date = moment(0, "HH"); weatherobject.date = moment("00:00", "HH:mm");
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327); weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
expect(weatherobject.isDayTime()).toBe(false); expect(weatherobject.isDayTime()).toBe(false);
}); });
it("should return sunrise as the next sunaction", () => {
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
let midnight = moment("00:00", "HH:mm");
expect(weatherobject.nextSunAction(midnight)).toBe("sunrise");
});
it("should return sunset as the next sunaction", () => {
weatherobject.updateSunTime(-6.774877582342688, 37.63345667023327);
let noon = moment(weatherobject.sunrise).hour(14);
expect(weatherobject.nextSunAction(noon)).toBe("sunset");
});
it("should return an already defined feelsLike info", () => {
weatherobject.feelsLikeTemp = "feelsLikeTempValue";
expect(weatherobject.feelsLike()).toBe("feelsLikeTempValue");
});
afterAll(() => { afterAll(() => {
moment.tz.setDefault(originalTimeZone); moment.tz.setDefault(originalTimeZone);
}); });
}); });
describe("WeatherObject", () => { describe("WeatherUtils", () => {
it("should convert windspeed correctly from mph to mps", () => { it("should convert windspeed correctly from mph to mps", () => {
expect(Math.round(WeatherUtils.convertWindToMetric(93.951324266285))).toBe(42); expect(Math.round(WeatherUtils.convertWindToMetric(93.951324266285))).toBe(42);
}); });
@ -43,4 +60,8 @@ describe("WeatherObject", () => {
it("should convert wind direction correctly from cardinal to value", () => { it("should convert wind direction correctly from cardinal to value", () => {
expect(WeatherUtils.convertWindDirection("SSE")).toBe(157); expect(WeatherUtils.convertWindDirection("SSE")).toBe(157);
}); });
it("should return a calculated feelsLike info", () => {
expect(WeatherUtils.calculateFeelsLike(0, 20, 40)).toBe(-9.444444444444445);
});
}); });