mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-30 10:14:03 +00:00
Test: Fix tests
Test: Add clear stats test Test: Attempt to fix tests Test: Add test for disable auth Update README
This commit is contained in:
parent
f65cc655c0
commit
07742799ed
9 changed files with 101 additions and 35 deletions
|
@ -2,5 +2,11 @@ module.exports = {
|
||||||
"launch": {
|
"launch": {
|
||||||
"headless": process.env.HEADLESS_TEST || false,
|
"headless": process.env.HEADLESS_TEST || false,
|
||||||
"userDataDir": "./data/test-chrome-profile",
|
"userDataDir": "./data/test-chrome-profile",
|
||||||
|
args: [
|
||||||
|
"--no-sandbox",
|
||||||
|
"--disable-setuid-sandbox",
|
||||||
|
"--disable-gpu",
|
||||||
|
"--disable-dev-shm-usage"
|
||||||
|
],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"build": "vite build --config ./config/vite.config.js",
|
"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": "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",
|
"test-with-build": "npm run build && npm test",
|
||||||
"jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend && jest --config=./config/jest.config.js",
|
"jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend && jest --runInBand --config=./config/jest.config.js",
|
||||||
"jest-frontend": "cross-env TEST_FRONTEND=1 jest --config=./config/jest-frontend.config.js",
|
"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",
|
"jest-backend": "cross-env TEST_BACKEND=1 jest --config=./config/jest-backend.config.js",
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Database {
|
||||||
console.log(`Data Dir: ${Database.dataDir}`);
|
console.log(`Data Dir: ${Database.dataDir}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async connect() {
|
static async connect(testMode = false) {
|
||||||
const acquireConnectionTimeout = 120 * 1000;
|
const acquireConnectionTimeout = 120 * 1000;
|
||||||
|
|
||||||
const Dialect = require("knex/lib/dialects/sqlite3/index.js");
|
const Dialect = require("knex/lib/dialects/sqlite3/index.js");
|
||||||
|
@ -112,8 +112,13 @@ class Database {
|
||||||
await R.autoloadModels("./server/model");
|
await R.autoloadModels("./server/model");
|
||||||
|
|
||||||
await R.exec("PRAGMA foreign_keys = ON");
|
await R.exec("PRAGMA foreign_keys = ON");
|
||||||
|
if (testMode) {
|
||||||
|
// Change to MEMORY
|
||||||
|
await R.exec("PRAGMA journal_mode = MEMORY");
|
||||||
|
} else {
|
||||||
// Change to WAL
|
// Change to WAL
|
||||||
await R.exec("PRAGMA journal_mode = WAL");
|
await R.exec("PRAGMA journal_mode = WAL");
|
||||||
|
}
|
||||||
await R.exec("PRAGMA cache_size = -12000");
|
await R.exec("PRAGMA cache_size = -12000");
|
||||||
await R.exec("PRAGMA auto_vacuum = FULL");
|
await R.exec("PRAGMA auto_vacuum = FULL");
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ exports.entryPage = "dashboard";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
Database.init(args);
|
Database.init(args);
|
||||||
await initDatabase();
|
await initDatabase(testMode);
|
||||||
|
|
||||||
exports.entryPage = await setting("entryPage");
|
exports.entryPage = await setting("entryPage");
|
||||||
|
|
||||||
|
@ -1417,14 +1417,14 @@ async function getMonitorJSONList(userID) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initDatabase() {
|
async function initDatabase(testMode = false) {
|
||||||
if (! fs.existsSync(Database.path)) {
|
if (! fs.existsSync(Database.path)) {
|
||||||
console.log("Copying Database");
|
console.log("Copying Database");
|
||||||
fs.copyFileSync(Database.templatePath, Database.path);
|
fs.copyFileSync(Database.templatePath, Database.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Connecting to the Database");
|
console.log("Connecting to the Database");
|
||||||
await Database.connect();
|
await Database.connect(testMode);
|
||||||
console.log("Connected");
|
console.log("Connected");
|
||||||
|
|
||||||
// Patch the database
|
// Patch the database
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<div class="form-text mt-2 mb-4 ms-2">{{ $t("shrinkDatabaseDescription") }}</div>
|
<div class="form-text mt-2 mb-4 ms-2">{{ $t("shrinkDatabaseDescription") }}</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
id="clearAllStats-btn"
|
||||||
class="btn btn-outline-danger me-2 mb-2"
|
class="btn btn-outline-danger me-2 mb-2"
|
||||||
@click="confirmClearStatistics"
|
@click="confirmClearStatistics"
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<template v-if="!settings.disableAuth">
|
<template v-if="!settings.disableAuth">
|
||||||
<p>
|
<p>
|
||||||
{{ $t("Current User") }}: <strong>{{ username }}</strong>
|
{{ $t("Current User") }}: <strong>{{ username }}</strong>
|
||||||
<button v-if="! settings.disableAuth" class="btn btn-danger ms-4 me-2 mb-2" @click="$root.logout">{{ $t("Logout") }}</button>
|
<button v-if="! settings.disableAuth" id="logout-btn" class="btn btn-danger ms-4 me-2 mb-2" @click="$root.logout">{{ $t("Logout") }}</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h5 class="my-4">{{ $t("Change Password") }}</h5>
|
<h5 class="my-4">{{ $t("Change Password") }}</h5>
|
||||||
|
@ -81,8 +81,8 @@
|
||||||
<h5 class="my-4">{{ $t("Advanced") }}</h5>
|
<h5 class="my-4">{{ $t("Advanced") }}</h5>
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<button v-if="settings.disableAuth" class="btn btn-outline-primary me-2 mb-2" @click="enableAuth">{{ $t("Enable Auth") }}</button>
|
<button v-if="settings.disableAuth" id="enableAuth-btn" class="btn btn-outline-primary me-2 mb-2" @click="enableAuth">{{ $t("Enable Auth") }}</button>
|
||||||
<button v-if="! settings.disableAuth" class="btn btn-primary me-2 mb-2" @click="confirmDisableAuth">{{ $t("Disable Auth") }}</button>
|
<button v-if="! settings.disableAuth" id="disableAuth-btn" class="btn btn-primary me-2 mb-2" @click="confirmDisableAuth">{{ $t("Disable Auth") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
2. Create a language file (e.g. `zh-TW.js`). The filename must be ISO language code: http://www.lingoes.net/en/translator/langcode.htm
|
2. Create a language file (e.g. `zh-TW.js`). The filename must be ISO language code: http://www.lingoes.net/en/translator/langcode.htm
|
||||||
3. Run `npm run update-language-files`. You can also use this command to check if there are new strings to translate for your language.
|
3. Run `npm run update-language-files`. You can also use this command to check if there are new strings to translate for your language.
|
||||||
4. Your language file should be filled in. You can translate now.
|
4. Your language file should be filled in. You can translate now.
|
||||||
5. Translate `src/pages/Settings.vue` (search for a `Confirm` component with `rel="confirmDisableAuth"`).
|
5. Translate `src/components/settings/Security.vue` (search for a `Confirm` component with `rel="confirmDisableAuth"`).
|
||||||
6. Import your language file in `src/i18n.js` and add it to `languageList` constant.
|
6. Import your language file in `src/i18n.js` and add it to `languageList` constant.
|
||||||
7. Make a [pull request](https://github.com/louislam/uptime-kuma/pulls) when you have done.
|
7. Make a [pull request](https://github.com/louislam/uptime-kuma/pulls) when you have done.
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-5 mb-1">
|
<div class="mt-5 mb-1">
|
||||||
<button class="btn btn-primary" type="submit" :disabled="processing">{{ $t("Save") }}</button>
|
<button id="monitor-submit-btn" class="btn btn-primary" type="submit" :disabled="processing">{{ $t("Save") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
100
test/e2e.spec.js
100
test/e2e.spec.js
|
@ -59,18 +59,31 @@ describe("Init", () => {
|
||||||
|
|
||||||
// Go to /
|
// Go to /
|
||||||
await page.goto(baseURL);
|
await page.goto(baseURL);
|
||||||
await sleep(3000);
|
await page.waitForSelector("h1.mb-3");
|
||||||
pathname = await page.evaluate(() => location.pathname);
|
pathname = await page.evaluate(() => location.pathname);
|
||||||
expect(pathname).toEqual("/dashboard");
|
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");
|
||||||
|
});
|
||||||
|
|
||||||
// Settings Page
|
// Settings Page
|
||||||
describe("Settings", () => {
|
describe("Settings", () => {
|
||||||
beforeAll(async () => {
|
beforeEach(async () => {
|
||||||
await page.goto(baseURL + "/settings");
|
await page.goto(baseURL + "/settings");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Change Language", async () => {
|
it("Change Language", async () => {
|
||||||
|
await page.goto(baseURL + "/settings/appearance");
|
||||||
await page.waitForSelector("#language");
|
await page.waitForSelector("#language");
|
||||||
|
|
||||||
await page.select("#language", "zh-HK");
|
await page.select("#language", "zh-HK");
|
||||||
|
@ -83,20 +96,33 @@ describe("Init", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Change Theme", async () => {
|
it("Change Theme", async () => {
|
||||||
await sleep(1000);
|
await page.goto(baseURL + "/settings/appearance");
|
||||||
|
|
||||||
// Dark
|
// Dark
|
||||||
await click(page, ".btn[for=btncheck2]");
|
await click(page, ".btn[for=btncheck2]");
|
||||||
await page.waitForSelector("div.dark");
|
await page.waitForSelector("div.dark");
|
||||||
|
|
||||||
await sleep(1000);
|
await page.waitForSelector(".btn[for=btncheck1]");
|
||||||
|
|
||||||
// Light
|
// Light
|
||||||
await click(page, ".btn[for=btncheck1]");
|
await click(page, ".btn[for=btncheck1]");
|
||||||
await page.waitForSelector("div.light");
|
await page.waitForSelector("div.light");
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Heartbeat Bar Style
|
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
|
// TODO: Timezone
|
||||||
|
|
||||||
|
@ -108,14 +134,14 @@ describe("Init", () => {
|
||||||
// Yes
|
// Yes
|
||||||
await click(page, "#searchEngineIndexYes");
|
await click(page, "#searchEngineIndexYes");
|
||||||
await click(page, "form > div > .btn[type=submit]");
|
await click(page, "form > div > .btn[type=submit]");
|
||||||
await sleep(2000);
|
await sleep(1000);
|
||||||
res = await axios.get(baseURL + "/robots.txt");
|
res = await axios.get(baseURL + "/robots.txt");
|
||||||
expect(res.data).not.toContain("Disallow: /");
|
expect(res.data).not.toContain("Disallow: /");
|
||||||
|
|
||||||
// No
|
// No
|
||||||
await click(page, "#searchEngineIndexNo");
|
await click(page, "#searchEngineIndexNo");
|
||||||
await click(page, "form > div > .btn[type=submit]");
|
await click(page, "form > div > .btn[type=submit]");
|
||||||
await sleep(2000);
|
await sleep(1000);
|
||||||
res = await axios.get(baseURL + "/robots.txt");
|
res = await axios.get(baseURL + "/robots.txt");
|
||||||
expect(res.data).toContain("Disallow: /");
|
expect(res.data).toContain("Disallow: /");
|
||||||
});
|
});
|
||||||
|
@ -125,25 +151,25 @@ describe("Init", () => {
|
||||||
|
|
||||||
// Default
|
// Default
|
||||||
await newPage.goto(baseURL);
|
await newPage.goto(baseURL);
|
||||||
await sleep(3000);
|
await newPage.waitForSelector("h1.mb-3", { timeout: 3000 });
|
||||||
let pathname = await newPage.evaluate(() => location.pathname);
|
let pathname = await newPage.evaluate(() => location.pathname);
|
||||||
expect(pathname).toEqual("/dashboard");
|
expect(pathname).toEqual("/dashboard");
|
||||||
|
|
||||||
// Status Page
|
// Status Page
|
||||||
await click(page, "#entryPageNo");
|
await click(page, "#entryPageNo");
|
||||||
await click(page, "form > div > .btn[type=submit]");
|
await click(page, "form > div > .btn[type=submit]");
|
||||||
await sleep(4000);
|
await sleep(1000);
|
||||||
await newPage.goto(baseURL);
|
await newPage.goto(baseURL);
|
||||||
await sleep(4000);
|
await newPage.waitForSelector("img.logo", { timeout: 3000 });
|
||||||
pathname = await newPage.evaluate(() => location.pathname);
|
pathname = await newPage.evaluate(() => location.pathname);
|
||||||
expect(pathname).toEqual("/status");
|
expect(pathname).toEqual("/status");
|
||||||
|
|
||||||
// Back to Dashboard
|
// Back to Dashboard
|
||||||
await click(page, "#entryPageYes");
|
await click(page, "#entryPageYes");
|
||||||
await click(page, "form > div > .btn[type=submit]");
|
await click(page, "form > div > .btn[type=submit]");
|
||||||
await sleep(4000);
|
await sleep(1000);
|
||||||
await newPage.goto(baseURL);
|
await newPage.goto(baseURL);
|
||||||
await sleep(4000);
|
await newPage.waitForSelector("h1.mb-3", { timeout: 3000 });
|
||||||
pathname = await newPage.evaluate(() => location.pathname);
|
pathname = await newPage.evaluate(() => location.pathname);
|
||||||
expect(pathname).toEqual("/dashboard");
|
expect(pathname).toEqual("/dashboard");
|
||||||
|
|
||||||
|
@ -151,7 +177,7 @@ describe("Init", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Change Password (wrong current password)", async () => {
|
it("Change Password (wrong current password)", async () => {
|
||||||
await page.goto(baseURL + "/settings");
|
await page.goto(baseURL + "/settings/security");
|
||||||
await page.waitForSelector("#current-password");
|
await page.waitForSelector("#current-password");
|
||||||
|
|
||||||
await page.type("#current-password", "wrong_passw$$d");
|
await page.type("#current-password", "wrong_passw$$d");
|
||||||
|
@ -159,10 +185,10 @@ describe("Init", () => {
|
||||||
await page.type("#repeat-new-password", "new_password123");
|
await page.type("#repeat-new-password", "new_password123");
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
await click(page, "form > div > .btn[type=submit]", 1);
|
await click(page, "form > div > .btn[type=submit]", 0);
|
||||||
await sleep(4000);
|
await sleep(1000);
|
||||||
|
|
||||||
await click(page, ".btn-danger.btn.me-2");
|
await click(page, "#logout-btn");
|
||||||
await login("admin", "new_password123");
|
await login("admin", "new_password123");
|
||||||
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length);
|
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length);
|
||||||
expect(elementCount).toEqual(1);
|
expect(elementCount).toEqual(1);
|
||||||
|
@ -171,24 +197,26 @@ describe("Init", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Change Password (wrong repeat)", async () => {
|
it("Change Password (wrong repeat)", async () => {
|
||||||
await page.goto(baseURL + "/settings");
|
await page.goto(baseURL + "/settings/security");
|
||||||
await page.waitForSelector("#current-password");
|
await page.waitForSelector("#current-password");
|
||||||
|
|
||||||
await page.type("#current-password", "admin123");
|
await page.type("#current-password", "admin123");
|
||||||
await page.type("#new-password", "new_password123");
|
await page.type("#new-password", "new_password123");
|
||||||
await page.type("#repeat-new-password", "new_password1234567898797898");
|
await page.type("#repeat-new-password", "new_password1234567898797898");
|
||||||
|
|
||||||
await click(page, "form > div > .btn[type=submit]", 1);
|
await click(page, "form > div > .btn[type=submit]", 0);
|
||||||
await sleep(4000);
|
await sleep(1000);
|
||||||
|
|
||||||
await click(page, ".btn-danger.btn.me-2");
|
await click(page, "#logout-btn");
|
||||||
await login("admin", "new_password123");
|
await login("admin", "new_password123");
|
||||||
|
|
||||||
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length);
|
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length);
|
||||||
expect(elementCount).toEqual(1);
|
expect(elementCount).toEqual(1);
|
||||||
|
|
||||||
await login("admin", "admin123");
|
await login("admin", "admin123");
|
||||||
await sleep(3000);
|
await page.waitForSelector("#current-password");
|
||||||
|
let pathname = await page.evaluate(() => location.pathname);
|
||||||
|
expect(pathname).toEqual("/settings/security");
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: 2FA
|
// TODO: 2FA
|
||||||
|
@ -197,9 +225,35 @@ describe("Init", () => {
|
||||||
|
|
||||||
// TODO: Import Backup
|
// TODO: Import Backup
|
||||||
|
|
||||||
// TODO: Disable Auth
|
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
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: Clear Stats
|
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 });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue