commit
91f9e10c94
@ -0,0 +1,28 @@
|
|||||||
|
const { defineConfig } = require("cypress");
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
projectId: "vyjuem",
|
||||||
|
e2e: {
|
||||||
|
experimentalStudio: true,
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
|
||||||
|
},
|
||||||
|
fixturesFolder: "test/cypress/fixtures",
|
||||||
|
screenshotsFolder: "test/cypress/screenshots",
|
||||||
|
videosFolder: "test/cypress/videos",
|
||||||
|
downloadsFolder: "test/cypress/downloads",
|
||||||
|
supportFile: "test/cypress/support/e2e.js",
|
||||||
|
baseUrl: "http://localhost:3002",
|
||||||
|
defaultCommandTimeout: 10000,
|
||||||
|
pageLoadTimeout: 60000,
|
||||||
|
viewportWidth: 1920,
|
||||||
|
viewportHeight: 1080,
|
||||||
|
specPattern: [
|
||||||
|
"test/cypress/e2e/setup.cy.js",
|
||||||
|
"test/cypress/e2e/**/*.js"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
baseUrl: "http://localhost:3002",
|
||||||
|
},
|
||||||
|
});
|
@ -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,
|
|
||||||
};
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
import { defineConfig } from "cypress";
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
e2e: {
|
|
||||||
baseUrl: "http://localhost:3002",
|
|
||||||
defaultCommandTimeout: 10000,
|
|
||||||
pageLoadTimeout: 60000,
|
|
||||||
viewportWidth: 1920,
|
|
||||||
viewportHeight: 1080,
|
|
||||||
specPattern: ["cypress/e2e/setup.cy.ts", "cypress/e2e/**/*.ts"],
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
baseUrl: "http://localhost:3002",
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,24 +0,0 @@
|
|||||||
import { actor } from "../support/actors/actor";
|
|
||||||
import { DEFAULT_USER_DATA } from "../support/const/user-data";
|
|
||||||
import { DashboardPage } from "../support/pages/dasboard-page";
|
|
||||||
import { SetupPage } from "../support/pages/setup-page";
|
|
||||||
|
|
||||||
describe("user can create a new account on setup page", () => {
|
|
||||||
before(() => {
|
|
||||||
cy.visit("/setup");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("user can create new account", () => {
|
|
||||||
cy.url().should("be.equal", SetupPage.url);
|
|
||||||
actor.setupTask.fillAndSubmitSetupForm(
|
|
||||||
DEFAULT_USER_DATA.username,
|
|
||||||
DEFAULT_USER_DATA.password,
|
|
||||||
DEFAULT_USER_DATA.password
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.url().should("be.equal", DashboardPage.url);
|
|
||||||
cy.get('[role="alert"]')
|
|
||||||
.should("be.visible")
|
|
||||||
.and("contain.text", "Added Successfully.");
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,8 +0,0 @@
|
|||||||
import { SetupTask } from "../tasks/setup-task";
|
|
||||||
|
|
||||||
class Actor {
|
|
||||||
setupTask: SetupTask = new SetupTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
const actor = new Actor();
|
|
||||||
export { actor };
|
|
@ -1 +0,0 @@
|
|||||||
import "./commands";
|
|
@ -1,15 +0,0 @@
|
|||||||
import { SetupPage } from "../pages/setup-page";
|
|
||||||
|
|
||||||
export class SetupTask {
|
|
||||||
fillAndSubmitSetupForm(
|
|
||||||
username: string,
|
|
||||||
password: string,
|
|
||||||
passwordRepeat: string
|
|
||||||
) {
|
|
||||||
cy.get(SetupPage.usernameInput).type(username);
|
|
||||||
cy.get(SetupPage.passWordInput).type(password);
|
|
||||||
cy.get(SetupPage.passwordRepeatInput).type(passwordRepeat);
|
|
||||||
|
|
||||||
cy.get(SetupPage.submitSetupForm).click();
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class FreeMobile extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "FreeMobile";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
try {
|
||||||
|
await axios.post(`https://smsapi.free-mobile.fr/sendmsg?msg=${encodeURIComponent(msg.replace("🔴", "⛔️"))}`, {
|
||||||
|
"user": notification.freemobileUser,
|
||||||
|
"pass": notification.freemobilePass,
|
||||||
|
});
|
||||||
|
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = FreeMobile;
|
@ -0,0 +1,76 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN } = require("../../src/util");
|
||||||
|
|
||||||
|
class Squadcast extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "squadcast";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
let config = {};
|
||||||
|
let data = {
|
||||||
|
message: msg,
|
||||||
|
description: "",
|
||||||
|
tags: {},
|
||||||
|
heartbeat: heartbeatJSON,
|
||||||
|
source: "uptime-kuma"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (heartbeatJSON !== null) {
|
||||||
|
data.description = heartbeatJSON["msg"];
|
||||||
|
data.event_id = heartbeatJSON["monitorID"];
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] === DOWN) {
|
||||||
|
data.message = `${monitorJSON["name"]} is DOWN`;
|
||||||
|
data.status = "trigger";
|
||||||
|
} else {
|
||||||
|
data.message = `${monitorJSON["name"]} is UP`;
|
||||||
|
data.status = "resolve";
|
||||||
|
}
|
||||||
|
|
||||||
|
let address;
|
||||||
|
switch (monitorJSON["type"]) {
|
||||||
|
case "ping":
|
||||||
|
address = monitorJSON["hostname"];
|
||||||
|
break;
|
||||||
|
case "port":
|
||||||
|
case "dns":
|
||||||
|
case "steam":
|
||||||
|
address = monitorJSON["hostname"];
|
||||||
|
if (monitorJSON["port"]) {
|
||||||
|
address += ":" + monitorJSON["port"];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
address = monitorJSON["url"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.tags["AlertAddress"] = address;
|
||||||
|
|
||||||
|
monitorJSON["tags"].forEach(tag => {
|
||||||
|
data.tags[tag["name"]] = {
|
||||||
|
value: tag["value"]
|
||||||
|
};
|
||||||
|
if (tag["color"] !== null) {
|
||||||
|
data.tags[tag["name"]]["color"] = tag["color"];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.post(notification.squadcastWebhookURL, data, config);
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Squadcast;
|
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="freemobileUser" class="form-label">{{ $t("Free Mobile User Identifier") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="freemobileUser" v-model="$parent.notification.freemobileUser" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="freemobilePass" class="form-label">{{ $t("Free Mobile API Key") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||||
|
<input id="freemobilePass" v-model="$parent.notification.freemobilePass" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="webhook-url" class="form-label">{{ $t("Post URL") }}</label>
|
||||||
|
<input id="webhook-url" v-model="$parent.notification.squadcastWebhookURL" type="url" pattern="https?://.+" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,18 @@
|
|||||||
|
const actor = require("../support/actors/actor");
|
||||||
|
const userData = require("../support/const/user-data");
|
||||||
|
const dashboardPage = require("../support/pages/dashboard-page");
|
||||||
|
const setupPage = require("../support/pages/setup-page");
|
||||||
|
|
||||||
|
describe("user can create a new account on setup page", () => {
|
||||||
|
before(() => {
|
||||||
|
cy.visit("/setup");
|
||||||
|
});
|
||||||
|
it("user can create new account", () => {
|
||||||
|
cy.url().should("be.equal", setupPage.SetupPage.url);
|
||||||
|
actor.actor.setupTask.fillAndSubmitSetupForm(userData.DEFAULT_USER_DATA.username, userData.DEFAULT_USER_DATA.password, userData.DEFAULT_USER_DATA.password);
|
||||||
|
cy.url().should("be.equal", dashboardPage.DashboardPage.url);
|
||||||
|
cy.get('[role="alert"]')
|
||||||
|
.should("be.visible")
|
||||||
|
.and("contain.text", "Added Successfully.");
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,8 @@
|
|||||||
|
const setupTask = require("../tasks/setup-task");
|
||||||
|
class Actor {
|
||||||
|
constructor() {
|
||||||
|
this.setupTask = new setupTask.SetupTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const actor = new Actor();
|
||||||
|
exports.actor = actor;
|
@ -1,4 +1,4 @@
|
|||||||
export const DEFAULT_USER_DATA = {
|
exports.DEFAULT_USER_DATA = {
|
||||||
username: "testuser",
|
username: "testuser",
|
||||||
password: "testuser123",
|
password: "testuser123",
|
||||||
};
|
};
|
@ -0,0 +1 @@
|
|||||||
|
require("./commands");
|
@ -1,3 +1,3 @@
|
|||||||
export const DashboardPage = {
|
exports.DashboardPage = {
|
||||||
url: Cypress.env("baseUrl") + "/dashboard",
|
url: Cypress.env("baseUrl") + "/dashboard",
|
||||||
};
|
};
|
@ -1,4 +1,4 @@
|
|||||||
export const SetupPage = {
|
exports.SetupPage = {
|
||||||
url: Cypress.env("baseUrl") + "/setup",
|
url: Cypress.env("baseUrl") + "/setup",
|
||||||
usernameInput: '[data-cy="username-input"]',
|
usernameInput: '[data-cy="username-input"]',
|
||||||
passWordInput: '[data-cy="password-input"]',
|
passWordInput: '[data-cy="password-input"]',
|
@ -0,0 +1,11 @@
|
|||||||
|
const setupPage = require("../pages/setup-page");
|
||||||
|
|
||||||
|
class SetupTask {
|
||||||
|
fillAndSubmitSetupForm(username, password, passwordRepeat) {
|
||||||
|
cy.get(setupPage.SetupPage.usernameInput).type(username);
|
||||||
|
cy.get(setupPage.SetupPage.passWordInput).type(password);
|
||||||
|
cy.get(setupPage.SetupPage.passwordRepeatInput).type(passwordRepeat);
|
||||||
|
cy.get(setupPage.SetupPage.submitSetupForm).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.SetupTask = SetupTask;
|
@ -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