mirror of
https://github.com/usememos/memos.git
synced 2024-12-26 04:42:54 +03:00
feat: add e2e test (#1486)
* add i18n * add base e2e test * add multiple test for e2e * extract the funciton of write memo * change test sturct * deteled unused dir * use fixture * add fixture * restruced the project * feat: add workflow * feat: change playwright test position * feat: change playwright test position * using yarn intead of npm * change install method * only enable sign in test * adjust the order of test * change report pos * fix style of e2e workflow * add review test * unify locale * randome write content * change report pos * reduce unused wait time * reduce unused folder * stash * merge upstream locale * change test name * add test item * change action name * add lanuage setting * add shotscreen * change name of test * fix the error of import dep * fix the error of import dep * fix the error of filename * fix the format of workflow * fix the name error of test case * feat: change the describe of test case * feat: remove unused test * feat: change the fixtures name * feat: remove unused config * feat: change docker action * feat: change the generate method * feat: extrace screenshot * feat: change extra path * feat: change extra path * feat: screenshot and upload * feat: change upload filename * feat: change login method * feat: change e2e method * feat: change e2e test * feat: add wait for login --------- Co-authored-by: CorrectRoadH <a778917369@gmail.comå>
This commit is contained in:
parent
b5c665cb7e
commit
81d4f01b7f
62
.github/workflows/e2e-test.yml
vendored
Normal file
62
.github/workflows/e2e-test.yml
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
name: "E2E Test"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build and Run Memos With E2E Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: ./
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: false
|
||||||
|
tags: neosmemo/memos:e2e
|
||||||
|
labels: neosmemo/memos:e2e
|
||||||
|
|
||||||
|
- name: Run Docker container
|
||||||
|
run: docker run -d -p 5230:5230 neosmemo/memos:e2e
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
cache: 'yarn'
|
||||||
|
cache-dependency-path: ./web/yarn.lock
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: web
|
||||||
|
run: yarn
|
||||||
|
|
||||||
|
- name: Install Playwright Browsers
|
||||||
|
working-directory: web
|
||||||
|
run: npx playwright install --with-deps
|
||||||
|
|
||||||
|
- name: Run Playwright tests
|
||||||
|
working-directory: web
|
||||||
|
run: npx playwright test
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-report
|
||||||
|
path: web/playwright-report/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-screenshot
|
||||||
|
path: web/playwright-screenshot/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
- name: Stop Docker container
|
||||||
|
run: docker stop $(docker ps -q)
|
4
web/.gitignore
vendored
4
web/.gitignore
vendored
@ -5,3 +5,7 @@ dist-ssr
|
|||||||
*.local
|
*.local
|
||||||
|
|
||||||
.yarn/*
|
.yarn/*
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
/playwright-screenshot/
|
13
web/e2e-tests/001-setup.spec.ts
Normal file
13
web/e2e-tests/001-setup.spec.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { test } from "@playwright/test";
|
||||||
|
import { signUp } from "./utils";
|
||||||
|
|
||||||
|
test.use({
|
||||||
|
locale: "en-US",
|
||||||
|
timezoneId: "Europe/Berlin",
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe("Sign up a host account", async () => {
|
||||||
|
test("Sign Up", async ({ page }) => {
|
||||||
|
await signUp(page, "admin", "admin");
|
||||||
|
});
|
||||||
|
});
|
37
web/e2e-tests/002-basic.spec.ts
Normal file
37
web/e2e-tests/002-basic.spec.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
import { review, login, writeMemo } from "./utils";
|
||||||
|
import randomstring from "randomstring";
|
||||||
|
|
||||||
|
test.use({
|
||||||
|
locale: "en-US",
|
||||||
|
timezoneId: "Europe/Berlin",
|
||||||
|
});
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await login(page, "admin", "admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe("Write some memos", async () => {
|
||||||
|
test("Write memos", async ({ page }) => {
|
||||||
|
const content = `${randomstring.generate()} from Write memos`;
|
||||||
|
await writeMemo(page, content);
|
||||||
|
await expect(page.getByText(content)).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Write memos with Tag", async ({ page }) => {
|
||||||
|
const tag = randomstring.generate(5);
|
||||||
|
const content = `#${tag} ${randomstring.generate()} from Write memos with Tag`;
|
||||||
|
await writeMemo(page, content);
|
||||||
|
// 1.memo contentg 2.tags list of memos editor 3.tags list
|
||||||
|
await expect(page.getByText(tag)).toHaveCount(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe("Daily Review", async () => {
|
||||||
|
test("Daily Review", async ({ page }) => {
|
||||||
|
const content = randomstring.generate();
|
||||||
|
await writeMemo(page, content);
|
||||||
|
await review(page);
|
||||||
|
await expect(page.getByText(content)).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
2
web/e2e-tests/fixtures.ts
Normal file
2
web/e2e-tests/fixtures.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const baseHost = "http://localhost:5230";
|
||||||
|
export { baseHost };
|
52
web/e2e-tests/utils.ts
Normal file
52
web/e2e-tests/utils.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { expect, Page } from "@playwright/test";
|
||||||
|
import locale from "../src/locales/en.json";
|
||||||
|
import { baseHost } from "./fixtures";
|
||||||
|
|
||||||
|
async function screenshot(page: Page, name: string) {
|
||||||
|
await page.screenshot({ path: `playwright-screenshot/${name}.png`, fullPage: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeMemo(page: Page, content: string) {
|
||||||
|
await expect(page.getByRole("button", { name: locale.editor.save })).toBeDisabled();
|
||||||
|
await page.getByPlaceholder("Any thoughts...").fill(content);
|
||||||
|
await expect(page.getByRole("button", { name: locale.editor.save })).toBeEnabled();
|
||||||
|
await page.getByRole("button", { name: locale.editor.save }).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function login(page: Page, username: string, password: string) {
|
||||||
|
page.goto(`${baseHost}/`);
|
||||||
|
await screenshot(page, "explore-page");
|
||||||
|
await page.waitForURL("**/explore");
|
||||||
|
await screenshot(page, "explore-page-after-wait");
|
||||||
|
await page.getByRole("link", { name: locale.common["sign-in"] }).click();
|
||||||
|
await screenshot(page, "auth-page");
|
||||||
|
await page.waitForURL("**/auth");
|
||||||
|
await page.locator('input[type="text"]').click();
|
||||||
|
await page.locator('input[type="text"]').fill(username);
|
||||||
|
await page.locator('input[type="password"]').click();
|
||||||
|
await page.locator('input[type="password"]').fill(password);
|
||||||
|
await page.getByRole("button", { name: locale.common["sign-in"] }).click();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
await screenshot(page, "home-page-login-success");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signUp(page: Page, username: string, password: string) {
|
||||||
|
await page.goto(`${baseHost}/`);
|
||||||
|
await page.waitForURL("**/auth");
|
||||||
|
await screenshot(page, "sign-up-page");
|
||||||
|
await page.locator('input[type="text"]').click();
|
||||||
|
await page.locator('input[type="text"]').fill(username);
|
||||||
|
await page.locator('input[type="password"]').click();
|
||||||
|
await page.locator('input[type="password"]').fill(password);
|
||||||
|
await page.getByRole("button", { name: locale.auth["signup-as-host"] }).click();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
await screenshot(page, "home-page-sign-up-success");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function review(page: Page) {
|
||||||
|
await page.goto(`${baseHost}/`);
|
||||||
|
await page.getByRole("link", { name: locale["daily-review"]["title"] }).click();
|
||||||
|
await screenshot(page, "review");
|
||||||
|
}
|
||||||
|
|
||||||
|
export { writeMemo, login, signUp, review };
|
@ -22,6 +22,7 @@
|
|||||||
"lucide-react": "^0.105.0",
|
"lucide-react": "^0.105.0",
|
||||||
"qrcode.react": "^3.1.0",
|
"qrcode.react": "^3.1.0",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
|
"randomstring": "^1.2.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hot-toast": "^2.4.0",
|
"react-hot-toast": "^2.4.0",
|
||||||
@ -34,6 +35,7 @@
|
|||||||
"zustand": "^4.3.6"
|
"zustand": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.32.2",
|
||||||
"@tailwindcss/line-clamp": "^0.4.2",
|
"@tailwindcss/line-clamp": "^0.4.2",
|
||||||
"@types/lodash-es": "^4.17.5",
|
"@types/lodash-es": "^4.17.5",
|
||||||
"@types/node": "^18.0.3",
|
"@types/node": "^18.0.3",
|
||||||
|
19
web/playwright.config.ts
Normal file
19
web/playwright.config.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: "./e2e-tests",
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
workers: 1,
|
||||||
|
reporter: [["html", { outputFolder: "playwright-report", open: "never" }]],
|
||||||
|
use: {
|
||||||
|
trace: "on-first-retry",
|
||||||
|
},
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: "chromium",
|
||||||
|
use: { ...devices["Desktop Chrome"] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
@ -487,6 +487,16 @@
|
|||||||
"@nodelib/fs.scandir" "2.1.5"
|
"@nodelib/fs.scandir" "2.1.5"
|
||||||
fastq "^1.6.0"
|
fastq "^1.6.0"
|
||||||
|
|
||||||
|
"@playwright/test@^1.32.2":
|
||||||
|
version "1.32.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.32.2.tgz#3cbd76b3f94d0f7f50bf054dbd02e504e85e3865"
|
||||||
|
integrity sha512-nhaTSDpEdTTttdkDE8Z6K3icuG1DVRxrl98Qq0Lfc63SS9a2sjc9+x8ezysh7MzCKz6Y+nArml3/mmt+gqRmQQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
playwright-core "1.32.2"
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents "2.3.2"
|
||||||
|
|
||||||
"@popperjs/core@^2.11.6":
|
"@popperjs/core@^2.11.6":
|
||||||
version "2.11.6"
|
version "2.11.6"
|
||||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
|
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
|
||||||
@ -787,6 +797,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
|
||||||
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
|
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
|
||||||
|
|
||||||
|
"@types/node@*":
|
||||||
|
version "18.15.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"
|
||||||
|
integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==
|
||||||
|
|
||||||
"@types/node@^18.0.3":
|
"@types/node@^18.0.3":
|
||||||
version "18.11.18"
|
version "18.11.18"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
|
||||||
@ -1032,6 +1047,11 @@ array-union@^2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
||||||
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
|
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
|
||||||
|
|
||||||
|
array-uniq@1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.npmmirror.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d"
|
||||||
|
integrity sha512-GVYjmpL05al4dNlKJm53mKE4w9OOLiuVHWorsIA3YVz+Hu0hcn6PtE3Ydl0EqU7v+7ABC4mjjWsnLUxbpno+CA==
|
||||||
|
|
||||||
array.prototype.flatmap@^1.3.1:
|
array.prototype.flatmap@^1.3.1:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183"
|
resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183"
|
||||||
@ -1785,7 +1805,7 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
fsevents@~2.3.2:
|
fsevents@2.3.2, fsevents@~2.3.2:
|
||||||
version "2.3.2"
|
version "2.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||||
@ -2595,6 +2615,11 @@ pify@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
|
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
|
||||||
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
|
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
|
||||||
|
|
||||||
|
playwright-core@1.32.2:
|
||||||
|
version "1.32.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.32.2.tgz#608810c3c4486fb86a224732ac0d3560a96ded8b"
|
||||||
|
integrity sha512-zD7aonO+07kOTthsrCR3YCVnDcqSHIJpdFUtZEMOb6//1Rc7/6mZDRdw+nlzcQiQltOOsiqI3rrSyn/SlyjnJQ==
|
||||||
|
|
||||||
postcss-import@^14.1.0:
|
postcss-import@^14.1.0:
|
||||||
version "14.1.0"
|
version "14.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
|
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
|
||||||
@ -2706,6 +2731,19 @@ quick-lru@^5.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||||
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||||
|
|
||||||
|
randombytes@2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.npmmirror.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec"
|
||||||
|
integrity sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==
|
||||||
|
|
||||||
|
randomstring@^1.2.3:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.npmmirror.com/randomstring/-/randomstring-1.2.3.tgz#49d2bc34ff6bc2bd0f6bb8e7d876e1d4433564c8"
|
||||||
|
integrity sha512-3dEFySepTzp2CvH6W/ASYGguPPveBuz5MpZ7MuoUkoVehmyNl9+F9c9GFVrz2QPbM9NXTIHGcmJDY/3j4677kQ==
|
||||||
|
dependencies:
|
||||||
|
array-uniq "1.0.2"
|
||||||
|
randombytes "2.0.3"
|
||||||
|
|
||||||
react-dom@^18.2.0:
|
react-dom@^18.2.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||||
|
Loading…
Reference in New Issue
Block a user