Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ _This release is scheduled to be released on 2022-10-01._
- 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

Expand Down
2 changes: 1 addition & 1 deletion tests/configs/data/calendar_test_recurring.ics
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ BEGIN:STANDARD
TZOFFSETFROM:+0000
TZOFFSETTO:+0000
TZNAME:GMT
DTSTART:19700101T00000--äüüßßß-0
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
Expand Down
17 changes: 9 additions & 8 deletions tests/e2e/env_spec.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
const fetch = require("fetch");
const helpers = require("./global-setup");

describe("App environment", function () {
beforeAll(function (done) {
describe("App environment", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/default.js");
helpers.getDocument(done);
});
afterAll(async function () {
afterAll(async () => {
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) => {
expect(res.status).toBe(200);
done();
expect(res.status).toBe(200);
});
});

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) => {
expect(res.status).toBe(404);
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) => {
done();
expect(elem).not.toBe(null);
expect(elem.textContent).toBe("MagicMirror²");
});
Expand Down
57 changes: 38 additions & 19 deletions tests/e2e/global-setup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const jsdom = require("jsdom");

exports.startApplication = function (configFilename, exec) {
exports.startApplication = (configFilename, exec) => {
jest.resetModules();
this.stopApplication();
// Set config sample for use in test
Expand All @@ -14,41 +14,60 @@ exports.startApplication = function (configFilename, exec) {
global.app.start();
};

exports.stopApplication = async function () {
exports.stopApplication = async () => {
if (global.app) {
global.app.stop();
}
await new Promise((resolve) => setTimeout(resolve, 100));
};

exports.getDocument = function (callback) {
exports.getDocument = (callback) => {
const url = "http://" + (config.address || "localhost") + ":" + (config.port || "8080");
jsdom.JSDOM.fromURL(url, { resources: "usable", runScripts: "dangerously" }).then((dom) => {
dom.window.name = "jsdom";
dom.window.onload = function () {
global.MutationObserver = dom.window.MutationObserver;
dom.window.onload = () => {
global.document = dom.window.document;
callback();
};
});
};

exports.waitForElement = function (selector) {
exports.waitForElement = (selector, ignoreValue = "") => {
return new Promise((resolve) => {
if (document.querySelector(selector) && document.querySelector(selector).value !== undefined) {
return resolve(document.querySelector(selector));
}

const observer = new MutationObserver(() => {
if (document.querySelector(selector) && document.querySelector(selector).value !== undefined) {
resolve(document.querySelector(selector));
observer.disconnect();
let oldVal = "dummy12345";
const interval = setInterval(() => {
const element = document.querySelector(selector);
if (element) {
let newVal = element.textContent;
if (newVal === oldVal) {
clearInterval(interval);
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);
});
};
9 changes: 5 additions & 4 deletions tests/e2e/modules/alert_spec.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
const helpers = require("../global-setup");

describe("Alert module", function () {
beforeAll(function (done) {
describe("Alert module", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/alert/default.js");
helpers.getDocument(done);
});
afterAll(async function () {
afterAll(async () => {
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) => {
done();
expect(elem).not.toBe(null);
expect(elem.textContent).toContain("Welcome, start was successful!");
});
Expand Down
111 changes: 57 additions & 54 deletions tests/e2e/modules/calendar_spec.js
Original file line number Diff line number Diff line change
@@ -1,162 +1,165 @@
const helpers = require("../global-setup");
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} result expected number
* @param {string} not reverse result
*/
function testElementLength(element, result, not) {
helpers.waitForElement(element).then((elem) => {
const testElementLength = (done, element, result, not) => {
helpers.waitForAllElements(element).then((elem) => {
done();
expect(elem).not.toBe(null);
if (not === "not") {
expect(elem.length).not.toBe(result);
} else {
expect(elem.length).toBe(result);
}
});
}
};

const testTextContain = function (element, text) {
helpers.waitForElement(element).then((elem) => {
const testTextContain = (done, element, text) => {
helpers.waitForElement(element, "undefinedLoading").then((elem) => {
done();
expect(elem).not.toBe(null);
expect(elem.textContent).toContain(text);
});
};

afterAll(async function () {
afterAll(async () => {
await helpers.stopApplication();
});

describe("Default configuration", function () {
beforeAll(function (done) {
describe("Default configuration", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/default.js");
helpers.getDocument(done);
});

it("should show the default maximumEntries of 10", () => {
testElementLength(".calendar .event", 10);
it("should show the default maximumEntries of 10", (done) => {
testElementLength(done, ".calendar .event", 10);
});

it("should show the default calendar symbol in each event", () => {
testElementLength(".calendar .event .fa-calendar-alt", 0, "not");
it("should show the default calendar symbol in each event", (done) => {
testElementLength(done, ".calendar .event .fa-calendar-alt", 0, "not");
});
});

describe("Custom configuration", function () {
beforeAll(function (done) {
describe("Custom configuration", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/custom.js");
helpers.getDocument(done);
});

it("should show the custom maximumEntries of 4", () => {
testElementLength(".calendar .event", 4);
it("should show the custom maximumEntries of 4", (done) => {
testElementLength(done, ".calendar .event", 4);
});

it("should show the custom calendar symbol in each event", () => {
testElementLength(".calendar .event .fa-birthday-cake", 4);
it("should show the custom calendar symbol in each event", (done) => {
testElementLength(done, ".calendar .event .fa-birthday-cake", 4);
});

it("should show two custom icons for repeating events", () => {
testElementLength(".calendar .event .fa-undo", 2);
it("should show two custom icons for repeating events", (done) => {
testElementLength(done, ".calendar .event .fa-undo", 2);
});

it("should show two custom icons for day events", () => {
testElementLength(".calendar .event .fa-calendar-day", 2);
it("should show two custom icons for day events", (done) => {
testElementLength(done, ".calendar .event .fa-calendar-day", 2);
});
});

describe("Recurring event", function () {
beforeAll(function (done) {
describe("Recurring event", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/recurring.js");
helpers.getDocument(done);
});

it("should show the recurring birthday event 6 times", () => {
testElementLength(".calendar .event", 6);
it("should show the recurring birthday event 6 times", (done) => {
testElementLength(done, ".calendar .event", 6);
});
});

process.setMaxListeners(0);
for (let i = -12; i < 12; i++) {
describe("Recurring event per timezone", function () {
beforeAll(function (done) {
Date.prototype.getTimezoneOffset = function () {
describe("Recurring event per timezone", () => {
beforeAll((done) => {
Date.prototype.getTimezoneOffset = () => {
return i * 60;
};
helpers.startApplication("tests/configs/modules/calendar/recurring.js");
helpers.getDocument(done);
});

it('should contain text "Mar 25th" in timezone UTC ' + -i, () => {
testTextContain(".calendar", "Mar 25th");
it('should contain text "Mar 25th" in timezone UTC ' + -i, (done) => {
testTextContain(done, ".calendar", "Mar 25th");
});
});
}

describe("Changed port", function () {
beforeAll(function (done) {
describe("Changed port", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/changed-port.js");
serverBasicAuth.listen(8010);
helpers.getDocument(done);
});

afterAll(function (done) {
afterAll((done) => {
serverBasicAuth.close(done());
});

it("should return TestEvents", function () {
testElementLength(".calendar .event", 0, "not");
it("should return TestEvents", (done) => {
testElementLength(done, ".calendar .event", 0, "not");
});
});

describe("Basic auth", function () {
beforeAll(function (done) {
describe("Basic auth", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/basic-auth.js");
helpers.getDocument(done);
});

it("should return TestEvents", function () {
testElementLength(".calendar .event", 0, "not");
it("should return TestEvents", (done) => {
testElementLength(done, ".calendar .event", 0, "not");
});
});

describe("Basic auth by default", function () {
beforeAll(function (done) {
describe("Basic auth by default", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/auth-default.js");
helpers.getDocument(done);
});

it("should return TestEvents", function () {
testElementLength(".calendar .event", 0, "not");
it("should return TestEvents", (done) => {
testElementLength(done, ".calendar .event", 0, "not");
});
});

describe("Basic auth backward compatibility configuration: DEPRECATED", function () {
beforeAll(function (done) {
describe("Basic auth backward compatibility configuration: DEPRECATED", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/old-basic-auth.js");
helpers.getDocument(done);
});

it("should return TestEvents", function () {
testElementLength(".calendar .event", 0, "not");
it("should return TestEvents", (done) => {
testElementLength(done, ".calendar .event", 0, "not");
});
});

describe("Fail Basic auth", function () {
beforeAll(function (done) {
describe("Fail Basic auth", () => {
beforeAll((done) => {
helpers.startApplication("tests/configs/modules/calendar/fail-basic-auth.js");
serverBasicAuth.listen(8020);
helpers.getDocument(done);
});

afterAll(function (done) {
afterAll((done) => {
serverBasicAuth.close(done());
});

it("should show Unauthorized error", function () {
testTextContain(".calendar", "Error in the calendar module. Authorization failed");
it("should show Unauthorized error", (done) => {
testTextContain(done, ".calendar", "Error in the calendar module. Authorization failed");
});
});
});
Loading