mirror of https://github.com/louislam/uptime-kuma
Drop Jest e2e testing (#2174)
parent
a5c102e750
commit
b993859926
|
@ -1,33 +0,0 @@
|
|||
const PuppeteerEnvironment = require("jest-environment-puppeteer");
|
||||
const util = require("util");
|
||||
|
||||
class DebugEnv extends PuppeteerEnvironment {
|
||||
async handleTestEvent(event, state) {
|
||||
const ignoredEvents = [
|
||||
"setup",
|
||||
"add_hook",
|
||||
"start_describe_definition",
|
||||
"add_test",
|
||||
"finish_describe_definition",
|
||||
"run_start",
|
||||
"run_describe_start",
|
||||
"test_start",
|
||||
"hook_start",
|
||||
"hook_success",
|
||||
"test_fn_start",
|
||||
"test_fn_success",
|
||||
"test_done",
|
||||
"run_describe_finish",
|
||||
"run_finish",
|
||||
"teardown",
|
||||
"test_fn_failure",
|
||||
];
|
||||
if (!ignoredEvents.includes(event.name)) {
|
||||
console.log(
|
||||
new Date().toString() + ` Unhandled event [${event.name}] ` + util.inspect(event)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DebugEnv;
|
|
@ -1,5 +0,0 @@
|
|||
module.exports = {
|
||||
"rootDir": "..",
|
||||
"testRegex": "./test/frontend.spec.js",
|
||||
};
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
module.exports = {
|
||||
"launch": {
|
||||
"dumpio": true,
|
||||
"slowMo": 500,
|
||||
"headless": process.env.HEADLESS_TEST || false,
|
||||
"userDataDir": "./data/test-chrome-profile",
|
||||
args: [
|
||||
"--disable-setuid-sandbox",
|
||||
"--disable-gpu",
|
||||
"--disable-dev-shm-usage",
|
||||
"--no-default-browser-check",
|
||||
"--no-experiments",
|
||||
"--no-first-run",
|
||||
"--no-pings",
|
||||
"--no-sandbox",
|
||||
"--no-zygote",
|
||||
"--single-process",
|
||||
],
|
||||
}
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
module.exports = {
|
||||
"verbose": true,
|
||||
"preset": "jest-puppeteer",
|
||||
"globals": {
|
||||
"__DEV__": true
|
||||
},
|
||||
"testRegex": "./test/e2e.spec.js",
|
||||
"testEnvironment": "./config/jest-debug-env.js",
|
||||
"rootDir": "..",
|
||||
"testTimeout": 30000,
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -25,8 +25,6 @@
|
|||
"build": "vite build --config ./config/vite.config.js",
|
||||
"test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test",
|
||||
"test-with-build": "npm run build && npm test",
|
||||
"jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend",
|
||||
"jest-frontend": "cross-env TEST_FRONTEND=1 jest --config=./config/jest-frontend.config.js",
|
||||
"jest-backend": "cross-env TEST_BACKEND=1 jest --config=./config/jest-backend.config.js",
|
||||
"tsc": "tsc",
|
||||
"vite-preview-dist": "vite preview --host --config ./config/vite.config.js",
|
||||
|
@ -140,12 +138,10 @@
|
|||
"eslint-plugin-vue": "~8.7.1",
|
||||
"favico.js": "^0.3.10",
|
||||
"jest": "~27.2.5",
|
||||
"jest-puppeteer": "~6.0.3",
|
||||
"postcss-html": "~1.5.0",
|
||||
"postcss-rtlcss": "~3.7.2",
|
||||
"postcss-scss": "~4.0.4",
|
||||
"prismjs": "^1.27.0",
|
||||
"puppeteer": "~13.1.3",
|
||||
"qrcode": "~1.5.0",
|
||||
"rollup-plugin-visualizer": "^5.6.0",
|
||||
"sass": "~1.42.1",
|
||||
|
|
|
@ -557,7 +557,7 @@ exports.doubleCheckPassword = async (socket, currentPassword) => {
|
|||
exports.startUnitTest = async () => {
|
||||
console.log("Starting unit test...");
|
||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||
const child = childProcess.spawn(npm, [ "run", "jest" ]);
|
||||
const child = childProcess.spawn(npm, [ "run", "jest-backend" ]);
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
console.log(data.toString());
|
||||
|
|
329
test/e2e.spec.js
329
test/e2e.spec.js
|
@ -1,329 +0,0 @@
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
const { Page, Browser } = require("puppeteer");
|
||||
const { sleep } = require("../src/util");
|
||||
|
||||
/**
|
||||
* Set back the correct data type for page object
|
||||
* @type {Page}
|
||||
*/
|
||||
page;
|
||||
|
||||
/**
|
||||
* @type {Browser}
|
||||
*/
|
||||
browser;
|
||||
|
||||
beforeAll(async () => {
|
||||
await page.setViewport({
|
||||
width: 1280,
|
||||
height: 720,
|
||||
deviceScaleFactor: 1,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
|
||||
});
|
||||
|
||||
const baseURL = "http://127.0.0.1:3002";
|
||||
|
||||
describe("Init", () => {
|
||||
const title = "Uptime Kuma";
|
||||
|
||||
beforeAll(async () => {
|
||||
await page.goto(baseURL);
|
||||
});
|
||||
|
||||
it(`should be titled "${title}"`, async () => {
|
||||
await expect(page.title()).resolves.toEqual(title);
|
||||
});
|
||||
|
||||
// Setup Page
|
||||
it("Setup", async () => {
|
||||
// Create an Admin
|
||||
await page.waitForSelector("#floatingInput");
|
||||
await page.waitForSelector("#repeat");
|
||||
await page.click("#floatingInput");
|
||||
await page.type("#floatingInput", "admin");
|
||||
await page.type("#floatingPassword", "admin123");
|
||||
await page.type("#repeat", "admin123");
|
||||
await page.click(".btn-primary[type=submit]");
|
||||
await sleep(3000);
|
||||
|
||||
// Go to /setup again
|
||||
await page.goto(baseURL + "/setup");
|
||||
await sleep(3000);
|
||||
let pathname = await page.evaluate(() => location.pathname);
|
||||
expect(pathname).toEqual("/dashboard");
|
||||
|
||||
// Go to /
|
||||
await page.goto(baseURL);
|
||||
await page.waitForSelector("h1.mb-3");
|
||||
pathname = await page.evaluate(() => location.pathname);
|
||||
expect(pathname).toEqual("/dashboard");
|
||||
});
|
||||
|
||||
it("should create monitor", async () => {
|
||||
// Create monitor
|
||||
await page.goto(baseURL + "/add");
|
||||
await page.waitForSelector("#name");
|
||||
|
||||
await page.type("#name", "Myself");
|
||||
await page.waitForSelector("#url");
|
||||
await page.click("#url", { clickCount: 3 });
|
||||
await page.keyboard.type(baseURL);
|
||||
await page.keyboard.press("Enter");
|
||||
|
||||
await page.waitForFunction(() => {
|
||||
const badge = document.querySelector("span.badge");
|
||||
return badge && badge.innerText == "100%";
|
||||
}, { timeout: 5000 });
|
||||
|
||||
});
|
||||
|
||||
// Settings Page
|
||||
/*
|
||||
describe("Settings", () => {
|
||||
beforeEach(async () => {
|
||||
await page.goto(baseURL + "/settings");
|
||||
});
|
||||
|
||||
it("Change Language", async () => {
|
||||
await page.goto(baseURL + "/settings/appearance");
|
||||
await page.waitForSelector("#language");
|
||||
|
||||
await page.select("#language", "zh-HK");
|
||||
let languageTitle = await page.evaluate(() => document.querySelector("[for=language]").innerText);
|
||||
expect(languageTitle).toEqual("語言");
|
||||
|
||||
await page.select("#language", "en");
|
||||
languageTitle = await page.evaluate(() => document.querySelector("[for=language]").innerText);
|
||||
expect(languageTitle).toEqual("Language");
|
||||
});
|
||||
|
||||
it("Change Theme", async () => {
|
||||
await page.goto(baseURL + "/settings/appearance");
|
||||
|
||||
// Dark
|
||||
await click(page, ".btn[for=btncheck2]");
|
||||
await page.waitForSelector("div.dark");
|
||||
|
||||
await page.waitForSelector(".btn[for=btncheck1]");
|
||||
|
||||
// Light
|
||||
await click(page, ".btn[for=btncheck1]");
|
||||
await page.waitForSelector("div.light");
|
||||
});
|
||||
|
||||
it("Change Heartbeat Bar Style", async () => {
|
||||
await page.goto(baseURL + "/settings/appearance");
|
||||
|
||||
// Bottom
|
||||
await click(page, ".btn[for=btncheck5]");
|
||||
await page.waitForSelector("div.hp-bar-big");
|
||||
|
||||
// None
|
||||
await click(page, ".btn[for=btncheck6]");
|
||||
await page.waitForSelector("div.hp-bar-big", {
|
||||
hidden: true,
|
||||
timeout: 1000
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Timezone
|
||||
|
||||
it("Search Engine Visibility", async () => {
|
||||
// Default
|
||||
let res = await axios.get(baseURL + "/robots.txt");
|
||||
expect(res.data).toContain("Disallow: /");
|
||||
|
||||
// Yes
|
||||
await click(page, "#searchEngineIndexYes");
|
||||
await click(page, "form > div > .btn[type=submit]");
|
||||
await sleep(1000);
|
||||
res = await axios.get(baseURL + "/robots.txt");
|
||||
expect(res.data).not.toContain("Disallow: /");
|
||||
|
||||
// No
|
||||
await click(page, "#searchEngineIndexNo");
|
||||
await click(page, "form > div > .btn[type=submit]");
|
||||
await sleep(1000);
|
||||
res = await axios.get(baseURL + "/robots.txt");
|
||||
expect(res.data).toContain("Disallow: /");
|
||||
});
|
||||
|
||||
it("Entry Page", async () => {
|
||||
const newPage = await browser.newPage();
|
||||
|
||||
// Default
|
||||
await newPage.goto(baseURL);
|
||||
await newPage.waitForSelector("h1.mb-3", { timeout: 3000 });
|
||||
let pathname = await newPage.evaluate(() => location.pathname);
|
||||
expect(pathname).toEqual("/dashboard");
|
||||
|
||||
// Status Page
|
||||
await click(page, "#entryPageNo");
|
||||
await click(page, "form > div > .btn[type=submit]");
|
||||
await sleep(1000);
|
||||
await newPage.goto(baseURL);
|
||||
await newPage.waitForSelector("img.logo", { timeout: 3000 });
|
||||
pathname = await newPage.evaluate(() => location.pathname);
|
||||
expect(pathname).toEqual("/status");
|
||||
|
||||
// Back to Dashboard
|
||||
await click(page, "#entryPageYes");
|
||||
await click(page, "form > div > .btn[type=submit]");
|
||||
await sleep(1000);
|
||||
await newPage.goto(baseURL);
|
||||
await newPage.waitForSelector("h1.mb-3", { timeout: 3000 });
|
||||
pathname = await newPage.evaluate(() => location.pathname);
|
||||
expect(pathname).toEqual("/dashboard");
|
||||
|
||||
await newPage.close();
|
||||
});
|
||||
|
||||
it("Change Password (wrong current password)", async () => {
|
||||
await page.goto(baseURL + "/settings/security");
|
||||
await page.waitForSelector("#current-password");
|
||||
|
||||
await page.type("#current-password", "wrong_passw$$d");
|
||||
await page.type("#new-password", "new_password123");
|
||||
await page.type("#repeat-new-password", "new_password123");
|
||||
|
||||
// Save
|
||||
await click(page, "form > div > .btn[type=submit]", 0);
|
||||
await sleep(1000);
|
||||
|
||||
await click(page, "#logout-btn");
|
||||
await login("admin", "new_password123");
|
||||
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length);
|
||||
expect(elementCount).toEqual(1);
|
||||
|
||||
await login("admin", "admin123");
|
||||
});
|
||||
|
||||
it("Change Password (wrong repeat)", async () => {
|
||||
await page.goto(baseURL + "/settings/security");
|
||||
await page.waitForSelector("#current-password");
|
||||
|
||||
await page.type("#current-password", "admin123");
|
||||
await page.type("#new-password", "new_password123");
|
||||
await page.type("#repeat-new-password", "new_password1234567898797898");
|
||||
|
||||
await click(page, "form > div > .btn[type=submit]", 0);
|
||||
await sleep(1000);
|
||||
|
||||
await click(page, "#logout-btn");
|
||||
await login("admin", "new_password123");
|
||||
|
||||
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length);
|
||||
expect(elementCount).toEqual(1);
|
||||
|
||||
await login("admin", "admin123");
|
||||
await page.waitForSelector("#current-password");
|
||||
let pathname = await page.evaluate(() => location.pathname);
|
||||
expect(pathname).toEqual("/settings/security");
|
||||
});
|
||||
|
||||
// TODO: 2FA
|
||||
|
||||
// TODO: Export Backup
|
||||
|
||||
// TODO: Import Backup
|
||||
|
||||
it("Should disable & enable auth", async () => {
|
||||
await page.goto(baseURL + "/settings/security");
|
||||
await click(page, "#disableAuth-btn");
|
||||
await click(page, ".btn.btn-danger[data-bs-dismiss='modal']", 2); // Not a good way to do it
|
||||
await page.waitForSelector("#enableAuth-btn", { timeout: 3000 });
|
||||
await page.waitForSelector("#logout-btn", {
|
||||
hidden: true,
|
||||
timeout: 3000
|
||||
});
|
||||
|
||||
const newPage = await browser.newPage();
|
||||
await newPage.goto(baseURL);
|
||||
await newPage.waitForSelector("span.badge", { timeout: 3000 });
|
||||
newPage.close();
|
||||
|
||||
await click(page, "#enableAuth-btn");
|
||||
await login("admin", "admin123");
|
||||
await page.waitForSelector("#disableAuth-btn", { timeout: 3000 });
|
||||
});
|
||||
|
||||
// it("Should clear all statistics", async () => {
|
||||
// await page.goto(baseURL + "/settings/monitor-history");
|
||||
// await click(page, "#clearAllStats-btn");
|
||||
// await click(page, ".btn.btn-danger");
|
||||
// await page.waitForFunction(() => {
|
||||
// const badge = document.querySelector("span.badge");
|
||||
// return badge && badge.innerText == "0%";
|
||||
// }, { timeout: 3000 });
|
||||
// });
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* Create Monitor - All type
|
||||
* Edit Monitor
|
||||
* Delete Monitor
|
||||
*
|
||||
* Create Notification (token problem, maybe hard to test)
|
||||
*
|
||||
*/
|
||||
|
||||
describe("Status Page", () => {
|
||||
const title = "Uptime Kuma";
|
||||
beforeAll(async () => {
|
||||
await page.goto(baseURL + "/status");
|
||||
});
|
||||
it(`should be titled "${title}"`, async () => {
|
||||
await expect(page.title()).resolves.toEqual(title);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test login
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
*/
|
||||
async function login(username, password) {
|
||||
await input(page, "#floatingInput", username);
|
||||
await input(page, "#floatingPassword", password);
|
||||
await page.click(".btn-primary[type=submit]");
|
||||
await sleep(5000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on an element on the page
|
||||
* @param {Page} page Puppeteer page instance
|
||||
* @param {string} selector
|
||||
* @param {number} elementIndex
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async function click(page, selector, elementIndex = 0) {
|
||||
await page.waitForSelector(selector, {
|
||||
timeout: 5000,
|
||||
});
|
||||
return await page.evaluate((s, i) => {
|
||||
return document.querySelectorAll(s)[i].click();
|
||||
}, selector, elementIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Input text into selected field
|
||||
* @param {Page} page Puppeteer page instance
|
||||
* @param {string} selector
|
||||
* @param {string} text Text to input
|
||||
*/
|
||||
async function input(page, selector, text) {
|
||||
await page.waitForSelector(selector, {
|
||||
timeout: 5000,
|
||||
});
|
||||
const element = await page.$(selector);
|
||||
await element.click({ clickCount: 3 });
|
||||
await page.keyboard.press("Backspace");
|
||||
await page.type(selector, text);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
// eslint-disable-next-line no-global-assign
|
||||
global.localStorage = {};
|
||||
global.navigator = {
|
||||
language: "en"
|
||||
};
|
||||
|
||||
const { currentLocale } = require("../src/i18n");
|
||||
|
||||
describe("Test i18n.js", () => {
|
||||
|
||||
it("currentLocale()", () => {
|
||||
expect(currentLocale()).toEqual("en");
|
||||
|
||||
navigator.language = "zh-HK";
|
||||
expect(currentLocale()).toEqual("zh-HK");
|
||||
|
||||
// Note that in Safari on iOS prior to 10.2, the country code returned is lowercase: "en-us", "fr-fr" etc.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language
|
||||
navigator.language = "zh-hk";
|
||||
expect(currentLocale()).toEqual("en");
|
||||
|
||||
navigator.language = "en-US";
|
||||
expect(currentLocale()).toEqual("en");
|
||||
|
||||
navigator.language = "ja-ZZ";
|
||||
expect(currentLocale()).toEqual("ja");
|
||||
|
||||
navigator.language = "zz";
|
||||
expect(currentLocale()).toEqual("en");
|
||||
|
||||
navigator.language = "zz-ZZ";
|
||||
expect(currentLocale()).toEqual("en");
|
||||
|
||||
localStorage.locale = "en";
|
||||
expect(currentLocale()).toEqual("en");
|
||||
|
||||
localStorage.locale = "zh-HK";
|
||||
expect(currentLocale()).toEqual("zh-HK");
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
const fs = require("fs");
|
||||
const rmSync = require("../extra/fs-rmSync.js");
|
||||
|
||||
const path = "./data/test-chrome-profile";
|
||||
|
||||
if (fs.existsSync(path)) {
|
||||
rmSync(path, {
|
||||
recursive: true,
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue