Bert Verhelst
3 years ago
37 changed files with 1999 additions and 2103 deletions
@ -0,0 +1,34 @@ |
|||||
|
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node |
||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions |
||||
|
|
||||
|
name: Auto Test |
||||
|
|
||||
|
on: |
||||
|
push: |
||||
|
branches: [ master ] |
||||
|
pull_request: |
||||
|
branches: [ master ] |
||||
|
|
||||
|
jobs: |
||||
|
build: |
||||
|
runs-on: ubuntu-latest |
||||
|
|
||||
|
strategy: |
||||
|
matrix: |
||||
|
node-version: [14.x, 15.x, 16.x] |
||||
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ |
||||
|
|
||||
|
steps: |
||||
|
- uses: actions/checkout@v2 |
||||
|
|
||||
|
- name: Use Node.js ${{ matrix.node-version }} |
||||
|
uses: actions/setup-node@v2 |
||||
|
with: |
||||
|
node-version: ${{ matrix.node-version }} |
||||
|
cache: 'npm' |
||||
|
- run: npm ci |
||||
|
- run: npm run build |
||||
|
- run: npm test |
||||
|
env: |
||||
|
HEADLESS_TEST: 1 |
||||
|
JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }} |
@ -1,5 +1,6 @@ |
|||||
module.exports = { |
module.exports = { |
||||
"launch": { |
"launch": { |
||||
"headless": false |
"headless": process.env.HEADLESS_TEST || false, |
||||
|
"userDataDir": "./data/test-chrome-profile", |
||||
} |
} |
||||
}; |
}; |
||||
|
File diff suppressed because it is too large
@ -0,0 +1,9 @@ |
|||||
|
const fs = require("fs"); |
||||
|
|
||||
|
const path = "./data/test-chrome-profile"; |
||||
|
|
||||
|
if (fs.existsSync(path)) { |
||||
|
fs.rmdirSync(path, { |
||||
|
recursive: true, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
const fs = require("fs"); |
||||
|
|
||||
|
const path = "./data/test"; |
||||
|
|
||||
|
if (fs.existsSync(path)) { |
||||
|
fs.rmdirSync(path, { |
||||
|
recursive: true, |
||||
|
}); |
||||
|
} |
@ -1,21 +1,236 @@ |
|||||
beforeAll(() => { |
// eslint-disable-next-line no-unused-vars
|
||||
|
const { Page, Browser } = require("puppeteer"); |
||||
|
const { sleep } = require("../src/util"); |
||||
|
const axios = require("axios"); |
||||
|
|
||||
|
/** |
||||
|
* 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(() => { |
afterAll(() => { |
||||
return console.log("Cleanup"); |
|
||||
}); |
}); |
||||
|
|
||||
describe("Very Simple Test", () => { |
const baseURL = "http://127.0.0.1:3002"; |
||||
|
|
||||
|
describe("Init", () => { |
||||
const title = "Uptime Kuma"; |
const title = "Uptime Kuma"; |
||||
|
|
||||
beforeAll(async () => { |
beforeAll(async () => { |
||||
await page.goto("http://127.0.0.1:3002"); |
await page.goto(baseURL); |
||||
|
}); |
||||
|
|
||||
|
it(`should be titled "${title}"`, async () => { |
||||
|
await expect(page.title()).resolves.toMatch(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 sleep(3000); |
||||
|
pathname = await page.evaluate(() => location.pathname); |
||||
|
expect(pathname).toEqual("/dashboard"); |
||||
|
}); |
||||
|
|
||||
|
// Settings Page
|
||||
|
describe("Settings", () => { |
||||
|
beforeAll(async () => { |
||||
|
await page.goto(baseURL + "/settings"); |
||||
|
}); |
||||
|
|
||||
|
it("Change Language", async () => { |
||||
|
await page.waitForSelector("#language"); |
||||
|
|
||||
|
await page.select("#language", "zh-HK"); |
||||
|
let languageTitle = await page.evaluate(() => document.querySelector("[for=language]").innerText); |
||||
|
expect(languageTitle).toMatch("語言"); |
||||
|
|
||||
|
await page.select("#language", "en"); |
||||
|
languageTitle = await page.evaluate(() => document.querySelector("[for=language]").innerText); |
||||
|
expect(languageTitle).toMatch("Language"); |
||||
|
}); |
||||
|
|
||||
|
it("Change Theme", async () => { |
||||
|
await sleep(1000); |
||||
|
|
||||
|
// Dark
|
||||
|
await click(page, ".btn[for=btncheck2]"); |
||||
|
await page.waitForSelector("div.dark"); |
||||
|
|
||||
|
await sleep(1000); |
||||
|
|
||||
|
// Light
|
||||
|
await click(page, ".btn[for=btncheck1]"); |
||||
|
await page.waitForSelector("div.light"); |
||||
|
}); |
||||
|
|
||||
|
// TODO: Heartbeat Bar Style
|
||||
|
|
||||
|
// TODO: Timezone
|
||||
|
|
||||
|
it("Search Engine Visibility", async () => { |
||||
|
// Default
|
||||
|
let res = await axios.get(baseURL + "/robots.txt"); |
||||
|
expect(res.data).toMatch("Disallow: /"); |
||||
|
|
||||
|
// Yes
|
||||
|
await click(page, "#searchEngineIndexYes"); |
||||
|
await click(page, "form > div > .btn[type=submit]"); |
||||
|
await sleep(2000); |
||||
|
res = await axios.get(baseURL + "/robots.txt"); |
||||
|
expect(res.data).not.toMatch("Disallow: /"); |
||||
|
|
||||
|
// No
|
||||
|
await click(page, "#searchEngineIndexNo"); |
||||
|
await click(page, "form > div > .btn[type=submit]"); |
||||
|
await sleep(2000); |
||||
|
res = await axios.get(baseURL + "/robots.txt"); |
||||
|
expect(res.data).toMatch("Disallow: /"); |
||||
|
}); |
||||
|
|
||||
|
it("Entry Page", async () => { |
||||
|
const newPage = await browser.newPage(); |
||||
|
|
||||
|
// Default
|
||||
|
await newPage.goto(baseURL); |
||||
|
await sleep(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(2000); |
||||
|
await newPage.goto(baseURL); |
||||
|
await sleep(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(2000); |
||||
|
await newPage.goto(baseURL); |
||||
|
await sleep(3000); |
||||
|
pathname = await newPage.evaluate(() => location.pathname); |
||||
|
expect(pathname).toEqual("/dashboard"); |
||||
|
|
||||
|
await newPage.close(); |
||||
|
}); |
||||
|
|
||||
|
it("Change Password (wrong current password)", async () => { |
||||
|
await page.type("#current-password", "wrong_passw$$d"); |
||||
|
await page.type("#new-password", "new_password123"); |
||||
|
await page.type("#repeat-new-password", "new_password123"); |
||||
|
await click(page, "form > div > .btn[type=submit]", 1); |
||||
|
await sleep(3000); |
||||
|
await click(page, ".btn-danger.btn.me-1"); |
||||
|
await sleep(2000); |
||||
|
await login("admin", "new_password123"); |
||||
|
await sleep(2000); |
||||
|
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length); |
||||
|
expect(elementCount).toEqual(1); |
||||
|
|
||||
|
await login("admin", "admin123"); |
||||
|
await sleep(3000); |
||||
|
}); |
||||
|
|
||||
|
it("Change Password (wrong repeat)", async () => { |
||||
|
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]", 1); |
||||
|
await sleep(3000); |
||||
|
await click(page, ".btn-danger.btn.me-1"); |
||||
|
await sleep(2000); |
||||
|
await login("admin", "new_password123"); |
||||
|
await sleep(2000); |
||||
|
let elementCount = await page.evaluate(() => document.querySelectorAll("#floatingPassword").length); |
||||
|
expect(elementCount).toEqual(1); |
||||
|
|
||||
|
await login("admin", "admin123"); |
||||
|
await sleep(3000); |
||||
|
}); |
||||
|
|
||||
|
// TODO: 2FA
|
||||
|
|
||||
|
// TODO: Export Backup
|
||||
|
|
||||
|
// TODO: Import Backup
|
||||
|
|
||||
|
// TODO: Disable Auth
|
||||
|
|
||||
|
// TODO: Clear Stats
|
||||
}); |
}); |
||||
|
|
||||
|
/* |
||||
|
* 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 () => { |
it(`should be titled "${title}"`, async () => { |
||||
await expect(page.title()).resolves.toMatch(title); |
await expect(page.title()).resolves.toMatch(title); |
||||
}); |
}); |
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
|
async function login(username, password) { |
||||
|
await input(page, "#floatingInput", username); |
||||
|
await input(page, "#floatingPassword", password); |
||||
|
await page.click(".btn-primary[type=submit]"); |
||||
|
} |
||||
|
|
||||
|
async function click(page, selector, elementIndex = 0) { |
||||
|
return await page.evaluate((s, i) => { |
||||
|
return document.querySelectorAll(s)[i].click(); |
||||
|
}, selector, elementIndex); |
||||
|
} |
||||
|
|
||||
|
async function input(page, selector, text) { |
||||
|
const element = await page.$(selector); |
||||
|
await element.click({ clickCount: 3 }); |
||||
|
await page.keyboard.press("Backspace"); |
||||
|
await page.type(selector, text); |
||||
|
} |
||||
|
Loading…
Reference in new issue