diff --git a/.gitignore b/.gitignore index 90dd227..7f6c135 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ tmp/ *.log *.sql *.sql.gz +test-results/ +playwright-report/ # Keep source Excel files local unless we explicitly decide otherwise. *.xlsm diff --git a/agent.md b/agent.md index 31cbaa1..18a577f 100644 --- a/agent.md +++ b/agent.md @@ -21,6 +21,14 @@ This project replaces the Excel/VBA workflow named `Catalog maker - 20` with a N - Before the first push, initialize Git if needed, configure the project remote and create an initial baseline commit from safe files only. - If a push fails, do not expose credentials in the terminal output or in chat; report the failure without printing secrets. +## UI inspection workflow + +- Use Playwright for browser inspections and visual verification of the local application. +- Run `npm run test:ui` after frontend or layout changes. +- Check for page errors, visible controls, modal behavior and important responsive states. +- Keep screenshots and traces in Playwright's ignored `test-results/` and `playwright-report/` directories; do not commit them. +- A UI change is not complete until the relevant Playwright checks pass. + ## Runtime - Start the web app with `npm run dev`. diff --git a/package-lock.json b/package-lock.json index 18ee201..ed0dbc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,9 @@ "mariadb": "^3.5.3", "selenium-webdriver": "^4.46.0" }, + "devDependencies": { + "playwright": "^1.62.1" + }, "engines": { "node": ">=20" } @@ -141,6 +144,21 @@ "node": ">=0.10" } }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/geckodriver": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-6.1.1.tgz", @@ -308,6 +326,38 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index a0cab58..e98a236 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "start": "node src/cli.js", "dev": "node src/server.js", "catalog:dry-run": "node src/cli.js catalog-maker --dry-run", - "test": "node --test" + "test": "node --test", + "test:ui": "playwright test", + "test:e2e": "playwright test tests/ui/database.e2e.spec.js" }, "engines": { "node": ">=20" @@ -17,5 +19,8 @@ "geckodriver": "^6.1.1", "mariadb": "^3.5.3", "selenium-webdriver": "^4.46.0" + }, + "devDependencies": { + "playwright": "^1.62.1" } } diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..ee68ef3 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,26 @@ +import { defineConfig, devices } from "playwright/test"; + +export default defineConfig({ + testDir: "./tests/ui", + timeout: 30_000, + expect: { + timeout: 5_000, + }, + fullyParallel: true, + forbidOnly: Boolean(process.env.CI), + retries: process.env.CI ? 2 : 0, + reporter: [["list"], ["html", { open: "never" }]], + use: { + baseURL: "http://127.0.0.1:3404", + trace: "retain-on-failure", + screenshot: "only-on-failure", + video: "retain-on-failure", + ...devices["Desktop Chrome"], + }, + webServer: { + command: "node src/server.js", + url: "http://127.0.0.1:3404/api/status", + reuseExistingServer: true, + timeout: 30_000, + }, +}); diff --git a/public/index.html b/public/index.html index e1fbbe7..4fa54af 100644 --- a/public/index.html +++ b/public/index.html @@ -131,7 +131,7 @@