From ef18074618575084bf7019bfc474d8ddc39f8616 Mon Sep 17 00:00:00 2001 From: Maximilian Mayer Date: Tue, 8 Sep 2026 21:02:50 +0200 Subject: [PATCH] test: add Playwright e2e setup and initial editor tests --- .gitignore | 4 +++ e2e/add-signature.spec.ts | 15 +++++++++ e2e/demo.spec.ts | 9 +++++ e2e/load-pdf.spec.ts | 10 ++++++ package-lock.json | 69 +++++++++++++++++++++++++++++++++++---- package.json | 7 ++-- playwright.config.ts | 24 ++++++++++++++ 7 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 e2e/add-signature.spec.ts create mode 100644 e2e/demo.spec.ts create mode 100644 e2e/load-pdf.spec.ts create mode 100644 playwright.config.ts diff --git a/.gitignore b/.gitignore index eb81cec..5e5daf7 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,10 @@ lerna-debug.log* coverage/ .nyc_output +# Playwright +test-results/ +playwright-report/ + # Misc .env .env.local diff --git a/e2e/add-signature.spec.ts b/e2e/add-signature.spec.ts new file mode 100644 index 0000000..4b1a1fe --- /dev/null +++ b/e2e/add-signature.spec.ts @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { test, expect } from "@playwright/test"; + +test("add a signature element", async({page}) => { + await page.goto("/"); + await page.getByRole("button", {name: "Load sample PDF"}).click(); + await expect(page.locator("canvas").first()).toBeVisible(); + await page.getByRole("button", {name: "Add Signature"}).click(); + await expect(page.getByRole("button", {name: "Click to place"})).toBeVisible(); + await page.locator(".overlay").first().click({position: {x:100,y:100}}); + await expect(page.locator(".signature-box").first()).toBeVisible(); + +}) diff --git a/e2e/demo.spec.ts b/e2e/demo.spec.ts new file mode 100644 index 0000000..225cbfb --- /dev/null +++ b/e2e/demo.spec.ts @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { test, expect } from "@playwright/test"; + +test("demo loads", async({ page }) => { + await page.goto("/"); + await expect(page.getByRole("button", {name: "Load sample PDF"})).toBeVisible(); +}) diff --git a/e2e/load-pdf.spec.ts b/e2e/load-pdf.spec.ts new file mode 100644 index 0000000..bb6335f --- /dev/null +++ b/e2e/load-pdf.spec.ts @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { test, expect } from "@playwright/test"; + +test("load pdf", async({page}) => { + await page.goto("/"); + await page.getByRole("button", {name: "Load sample PDF"}).click(); + await expect(page.locator("canvas").first()).toBeVisible(); +}) diff --git a/package-lock.json b/package-lock.json index 94ad093..512be64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@nextcloud/browserslist-config": "^3.1.2", + "@playwright/test": "^1.63.0", "@types/node": "^26.4.1", "@typescript-eslint/eslint-plugin": "^8.58.0", "@typescript-eslint/parser": "^8.58.0", @@ -645,6 +646,22 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@playwright/test": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz", + "integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@rolldown/binding-android-arm-eabi": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", @@ -1002,6 +1019,7 @@ "integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.69.0", @@ -1031,6 +1049,7 @@ "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/types": "8.69.0", @@ -1382,6 +1401,7 @@ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-core": "3.5.42", "@vue/shared": "3.5.42" @@ -1420,6 +1440,7 @@ "integrity": "sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", @@ -1515,6 +1536,7 @@ "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1608,7 +1630,6 @@ "integrity": "sha512-Grytf1xOxOEMTGRwx6rLGKkTabd4vMg3VrKdj/7joCmV0qgh4QwMMO6xh34YEXQqirAuUdgQGa5orJQQ+69RBw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "baseline-browser-mapping": "dist/cli.cjs" }, @@ -1733,8 +1754,7 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "CC-BY-4.0", - "peer": true + "license": "CC-BY-4.0" }, "node_modules/chai": { "version": "6.2.2", @@ -1975,8 +1995,7 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.413.tgz", "integrity": "sha512-F1XPKvt7HVfly5WND90ec16nFsdr4g5x/cVUP3EqjeyXynupabGDqpMa84wwvuYGDnldXLBz6DLXyZXWO9TPvw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/entities": { "version": "7.0.1", @@ -2026,6 +2045,7 @@ "integrity": "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==", "dev": true, "license": "MIT", + "peer": true, "workspaces": [ "packages/*" ], @@ -2446,6 +2466,7 @@ "integrity": "sha512-4bRh1KzRvKDnFNTlLhzT1RZTpkKhQbQDl9j+7GXszWsvuspYdo29k6OHRf4PwiM6oLb8r/pMWeYiJjkfod5AvQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", @@ -2649,6 +2670,7 @@ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -3091,7 +3113,6 @@ "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -3304,6 +3325,35 @@ "pathe": "^2.0.3" } }, + "node_modules/playwright": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/postcss": { "version": "8.5.28", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", @@ -3429,6 +3479,7 @@ "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/types": "=0.146.0", "@rolldown/pluginutils": "^1.0.0" @@ -3662,6 +3713,7 @@ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3775,7 +3827,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -3810,6 +3861,7 @@ "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", @@ -3914,6 +3966,7 @@ "integrity": "sha512-gpsMNoRhMjMktVxPtstOH4/PJuPyovVaMDr4oDilXaGH1EcqM2OE96SoHT2VIQ6fTGtTjqmHDrEu2X9RQiXf8Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/mocker": "5.0.0", @@ -4013,6 +4066,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.42.tgz", "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.42", "@vue/compiler-sfc": "3.5.42", @@ -4042,6 +4096,7 @@ "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.0", "eslint-scope": "^8.2.0 || ^9.0.0", diff --git a/package.json b/package.json index 2a5f789..c2ae096 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,8 @@ "prepack": "npm run build && npm run validate:dist", "test": "vitest run", "test:watch": "vitest", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", "lint": "eslint . --ext .vue,.ts,.js --max-warnings=0", "lint:fix": "eslint . --ext .vue,.ts,.js --fix" }, @@ -56,6 +58,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@nextcloud/browserslist-config": "^3.1.2", + "@playwright/test": "^1.63.0", "@types/node": "^26.4.1", "@typescript-eslint/eslint-plugin": "^8.58.0", "@typescript-eslint/parser": "^8.58.0", @@ -63,15 +66,15 @@ "@vitest/eslint-plugin": "^1.6.14", "@vue/language-core": "^3.3.11", "@vue/test-utils": "^2.4.6", - "eslint-plugin-vue": "^10.8.0", "eslint": "^10.1.0", + "eslint-plugin-vue": "^10.8.0", "globals": "^17.4.0", "happy-dom": "^20.7.0", "postcss": "^8.5.6", "rollup-plugin-visualizer": "^7.0.0", "typescript": "^6.0.2", - "vite-plugin-dts": "^5.0.3", "vite": "^8.0.2", + "vite-plugin-dts": "^5.0.3", "vitest": "^5.0.0", "vue-eslint-parser": "^10.4.0", "vue-tsc": "^3.2.4" diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..c82d9a1 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2026 LibreCode coop and contributors +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { defineConfig, devices } from "@playwright/test"; + +export default defineConfig({ + testDir: "e2e", + use: { + baseURL: "http://localhost:5173/", + trace: "on-first-retry" + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, +], + webServer: { + command: "npm run dev", + url: "http://localhost:5173/", + reuseExistingServer: !process.env.CI + } + +});