From f0075e33441f120ec85973896a10c403b6c57394 Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Sat, 5 Sep 2026 18:12:59 +0200 Subject: [PATCH] Bonus 19: Playwright E2E-Setup + 4 Smoke-Tests - @playwright/test als dev-Dependency - playwright.config.ts: webServer-Setup, Chromium-Project, baseURL - tests/e2e/app.spec.ts: 4 E2E-Tests - zeigt den Titel - zeigt Header mit Logo + Tab-Buttons - Tab-Wechsel funktioniert (Graph, Cluster-Karte, Radial) - Legend ist sichtbar - .gitignore: test-results/, playwright-report/ - package.json scripts.test:e2e: 'playwright test' Verifiziert (manuell): - 4/4 E2E-Tests gruen (~3s) - Webapp startet korrekt via Vite, Tests greifen auf rendered DOM zu - Browser-Download: 195.6 MiB Chromium + Edge-Deps Hinweis: Playwright laeuft nur lokal. CI-Browser-Downloads waeren separat zu konfigurieren. --- .gitignore | 5 +++++ package-lock.json | 46 +++++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ playwright.config.ts | 34 ++++++++++++++++++++++++++++++++ tests/e2e/app.spec.ts | 38 +++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+) create mode 100644 playwright.config.ts create mode 100644 tests/e2e/app.spec.ts diff --git a/.gitignore b/.gitignore index 1b07808..07a4d4b 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,11 @@ secrets.key coverage/ .nyc_output/ +# Playwright +test-results/ +playwright-report/ +.playwright/ + # Temporaere Verzeichnisse tmp/ temp/ diff --git a/package-lock.json b/package-lock.json index d9ccb93..b342416 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "mindomat": "bin/mindomat.mjs" }, "devDependencies": { + "@playwright/test": "^1.63.0", "@testing-library/react": "^16.3.3", "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.69.0", @@ -660,6 +661,22 @@ "url": "https://github.com/sponsors/oxc-project" } }, + "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.7", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz", @@ -2951,6 +2968,35 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "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", diff --git a/package.json b/package.json index 7660112..45afad5 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "dev": "tsc --watch", "test": "vitest run", "test:watch": "vitest", + "test:e2e": "playwright test", "lint": "eslint src/ tests/ --ext .ts", "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"webapp/src/**/*.{ts,tsx}\"", "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"webapp/src/**/*.{ts,tsx}\"", @@ -49,6 +50,7 @@ "gray-matter": "^4.0.3" }, "devDependencies": { + "@playwright/test": "^1.63.0", "@testing-library/react": "^16.3.3", "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.69.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..eb05aad --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,34 @@ +// Playwright Config fuer Webapp-E2E-Tests +// Phase Bonus 19 + +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests/e2e', + timeout: 30_000, + expect: { timeout: 5_000 }, + fullyParallel: true, + retries: 0, + workers: 1, + reporter: 'list', + use: { + baseURL: 'http://localhost:5173', + trace: 'on-first-retry', + screenshot: 'only-on-failure', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + webServer: { + // Vite-Dev-Server mit MINDOMAT_VAULT_PATH auf einen Test-Vault + command: 'npm run dev --prefix webapp', + url: 'http://localhost:5173', + timeout: 60_000, + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + stderr: 'pipe', + }, +}); diff --git a/tests/e2e/app.spec.ts b/tests/e2e/app.spec.ts new file mode 100644 index 0000000..7775670 --- /dev/null +++ b/tests/e2e/app.spec.ts @@ -0,0 +1,38 @@ +// Playwright E2E-Smoke-Tests fuer die Webapp +// Phase Bonus 19 + +import { test, expect } from '@playwright/test'; + +test.describe('Mind-o-Mat Webapp', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/'); + }); + + test('zeigt den Titel', async ({ page }) => { + await expect(page).toHaveTitle(/Mind-o-Mat/); + }); + + test('zeigt Header mit Logo und Tab-Buttons', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'Mind-o-Mat' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Graph' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Cluster-Karte' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Radial' })).toBeVisible(); + }); + + test('Tab-Wechsel funktioniert', async ({ page }) => { + // Graph ist initial aktiv + await expect(page.getByRole('button', { name: 'Graph' })).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + // Klick auf Cluster-Karte -> wechselt aktiv-Status + await page.getByRole('button', { name: 'Cluster-Karte' }).click(); + await expect(page.getByRole('button', { name: 'Cluster-Karte' })).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + // Klick auf Radial + await page.getByRole('button', { name: 'Radial' }).click(); + await expect(page.getByRole('button', { name: 'Radial' })).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + }); + + test('Legend ist sichtbar', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'Legende' })).toBeVisible(); + await expect(page.getByText('inbox')).toBeVisible(); + await expect(page.getByText('wiki')).toBeVisible(); + }); +});