Merge pull request #1780 from tamasmagyar/test/add-cypress-tests

test: added cypress framework and tests for setup page
This commit is contained in:
Louis Lam 2022-09-09 21:05:12 +08:00 committed by GitHub
commit b22176d218
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 138 additions and 10 deletions

View file

@ -1,6 +1,7 @@
/.idea /.idea
/node_modules /node_modules
/data /data
/cypress
/out /out
/test /test
/kubernetes /kubernetes

View file

@ -50,3 +50,19 @@ jobs:
cache: 'npm' cache: 'npm'
- run: npm install - run: npm install
- run: npm run lint - run: npm run lint
e2e-tests:
needs: [ check-linters ]
runs-on: ubuntu-latest
steps:
- run: git config --global core.autocrlf false # Mainly for Windows
- uses: actions/checkout@v3
- name: Use Node.js 14
uses: actions/setup-node@v3
with:
node-version: 14
cache: 'npm'
- run: npm install
- run: npm run build
- run: npm run cy:test

3
.gitignore vendored
View file

@ -13,3 +13,6 @@ dist-ssr
/out /out
/tmp /tmp
.env .env
cypress/videos
cypress/screenshots

15
cypress.config.ts Normal file
View file

@ -0,0 +1,15 @@
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",
},
});

24
cypress/e2e/setup.cy.ts Normal file
View file

@ -0,0 +1,24 @@
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.");
});
});

0
cypress/plugins/index.js Normal file
View file

View file

@ -0,0 +1,8 @@
import { SetupTask } from "../tasks/setup-task";
class Actor {
setupTask: SetupTask = new SetupTask();
}
const actor = new Actor();
export { actor };

View file

View file

@ -0,0 +1,4 @@
export const DEFAULT_USER_DATA = {
username: "testuser",
password: "testuser123",
};

1
cypress/support/e2e.ts Normal file
View file

@ -0,0 +1 @@
import "./commands";

View file

@ -0,0 +1,3 @@
export const DashboardPage = {
url: Cypress.env("baseUrl") + "/dashboard",
};

View file

@ -0,0 +1,7 @@
export const SetupPage = {
url: Cypress.env("baseUrl") + "/setup",
usernameInput: '[data-cy="username-input"]',
passWordInput: '[data-cy="password-input"]',
passwordRepeatInput: '[data-cy="password-repeat-input"]',
submitSetupForm: '[data-cy="submit-setup-form"]',
};

View file

@ -0,0 +1,15 @@
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();
}
}

View file

@ -60,7 +60,9 @@
"release-beta": "node extra/beta/update-version.js && npm run build && node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:beta . --target release --push && node ./extra/press-any-key.js && npm run upload-artifacts", "release-beta": "node extra/beta/update-version.js && npm run build && node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:beta . --target release --push && node ./extra/press-any-key.js && npm run upload-artifacts",
"git-remove-tag": "git tag -d", "git-remove-tag": "git tag -d",
"build-dist-and-restart": "npm run build && npm run start-server-dev", "build-dist-and-restart": "npm run build && npm run start-server-dev",
"start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev" "start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev",
"cy:test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --e2e",
"cy:run": "npx cypress run --browser chrome --headless"
}, },
"dependencies": { "dependencies": {
"@louislam/sqlite3": "~15.0.6", "@louislam/sqlite3": "~15.0.6",
@ -130,6 +132,8 @@
"concurrently": "^7.1.0", "concurrently": "^7.1.0",
"core-js": "~3.18.3", "core-js": "~3.18.3",
"cross-env": "~7.0.3", "cross-env": "~7.0.3",
"cypress": "^10.1.0",
"delay": "^5.0.0",
"dns2": "~2.0.1", "dns2": "~2.0.1",
"eslint": "~8.14.0", "eslint": "~8.14.0",
"eslint-plugin-vue": "~8.7.1", "eslint-plugin-vue": "~8.7.1",

View file

@ -61,7 +61,7 @@ log.info("server", "Importing this project modules");
log.debug("server", "Importing Monitor"); log.debug("server", "Importing Monitor");
const Monitor = require("./model/monitor"); const Monitor = require("./model/monitor");
log.debug("server", "Importing Settings"); log.debug("server", "Importing Settings");
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, doubleCheckPassword } = require("./util-server"); const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, doubleCheckPassword, startE2eTests } = require("./util-server");
log.debug("server", "Importing Notification"); log.debug("server", "Importing Notification");
const { Notification } = require("./notification"); const { Notification } = require("./notification");
@ -112,6 +112,7 @@ const twoFAVerifyOptions = {
* @type {boolean} * @type {boolean}
*/ */
const testMode = !!args["test"] || false; const testMode = !!args["test"] || false;
const e2eTestMode = !!args["e2e"] || false;
if (config.demoMode) { if (config.demoMode) {
log.info("server", "==== Demo Mode ===="); log.info("server", "==== Demo Mode ====");
@ -1486,6 +1487,10 @@ let needSetup = false;
if (testMode) { if (testMode) {
startUnitTest(); startUnitTest();
} }
if (e2eTestMode) {
startE2eTests();
}
}); });
initBackgroundJobs(args); initBackgroundJobs(args);

View file

@ -573,6 +573,26 @@ exports.startUnitTest = async () => {
}); });
}; };
/** Start end-to-end tests */
exports.startE2eTests = async () => {
console.log("Starting unit test...");
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
const child = childProcess.spawn(npm, [ "run", "cy:run" ]);
child.stdout.on("data", (data) => {
console.log(data.toString());
});
child.stderr.on("data", (data) => {
console.log(data.toString());
});
child.on("close", function (code) {
console.log("Jest exit code: " + code);
process.exit(code);
});
};
/** /**
* Convert unknown string to UTF8 * Convert unknown string to UTF8
* @param {Uint8Array} body Buffer * @param {Uint8Array} body Buffer

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="form-container"> <div class="form-container" data-cy="setup-form">
<div class="form"> <div class="form">
<form @submit.prevent="submit"> <form @submit.prevent="submit">
<div> <div>
@ -23,21 +23,21 @@
</div> </div>
<div class="form-floating mt-3"> <div class="form-floating mt-3">
<input id="floatingInput" v-model="username" type="text" class="form-control" placeholder="Username" required> <input id="floatingInput" v-model="username" type="text" class="form-control" placeholder="Username" required data-cy="username-input">
<label for="floatingInput">{{ $t("Username") }}</label> <label for="floatingInput">{{ $t("Username") }}</label>
</div> </div>
<div class="form-floating mt-3"> <div class="form-floating mt-3">
<input id="floatingPassword" v-model="password" type="password" class="form-control" placeholder="Password" required> <input id="floatingPassword" v-model="password" type="password" class="form-control" placeholder="Password" required data-cy="password-input">
<label for="floatingPassword">{{ $t("Password") }}</label> <label for="floatingPassword">{{ $t("Password") }}</label>
</div> </div>
<div class="form-floating mt-3"> <div class="form-floating mt-3">
<input id="repeat" v-model="repeatPassword" type="password" class="form-control" placeholder="Repeat Password" required> <input id="repeat" v-model="repeatPassword" type="password" class="form-control" placeholder="Repeat Password" required data-cy="password-repeat-input">
<label for="repeat">{{ $t("Repeat Password") }}</label> <label for="repeat">{{ $t("Repeat Password") }}</label>
</div> </div>
<button class="w-100 btn btn-primary mt-3" type="submit" :disabled="processing"> <button class="w-100 btn btn-primary mt-3" type="submit" :disabled="processing" data-cy="submit-setup-form">
{{ $t("Create") }} {{ $t("Create") }}
</button> </button>
</form> </form>

View file

@ -11,9 +11,11 @@
"removeComments": false, "removeComments": false,
"preserveConstEnums": true, "preserveConstEnums": true,
"sourceMap": false, "sourceMap": false,
"strict": true "strict": true,
"types": ["cypress"]
}, },
"files": [ "files": [
"./src/util.ts" "./src/util.ts",
] ],
"include": ["cypress/**/*.ts"]
} }