add playwright e2e tests for onboarding, contact tracker
- install playwright, configure for chromium with vite dev server - add onboarding flow test: redirect, form fill, navigation to prozess - add contact tracker test: create contact, verify in list - fix onboarding form navigating to /onboarding instead of /prozess - fix date rendering crash in contact list (cast datum to text) - exclude @electric-sql/pglite from vite optimizeDeps (WASM bundle) - add test-results/, playwright-report/ to .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,6 +11,10 @@ dist/
|
|||||||
# Mise local overrides
|
# Mise local overrides
|
||||||
.mise.local.toml
|
.mise.local.toml
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
test-results/
|
||||||
|
playwright-report/
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
|||||||
9
bun.lock
9
bun.lock
@@ -25,6 +25,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.4.6",
|
"@biomejs/biome": "^2.4.6",
|
||||||
|
"@playwright/test": "^1.58.2",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
"@types/node": "^25.4.0",
|
"@types/node": "^25.4.0",
|
||||||
@@ -352,6 +353,8 @@
|
|||||||
|
|
||||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||||
|
|
||||||
|
"@playwright/test": ["@playwright/test@1.58.2", "", { "dependencies": { "playwright": "1.58.2" }, "bin": { "playwright": "cli.js" } }, "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA=="],
|
||||||
|
|
||||||
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
||||||
|
|
||||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||||
@@ -1112,6 +1115,10 @@
|
|||||||
|
|
||||||
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||||
|
|
||||||
|
"playwright": ["playwright@1.58.2", "", { "dependencies": { "playwright-core": "1.58.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A=="],
|
||||||
|
|
||||||
|
"playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="],
|
||||||
|
|
||||||
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||||
|
|
||||||
"postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="],
|
"postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="],
|
||||||
@@ -1480,6 +1487,8 @@
|
|||||||
|
|
||||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||||
|
|
||||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||||
|
|||||||
29
e2e/kontakte.spec.ts
Normal file
29
e2e/kontakte.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto("/onboarding");
|
||||||
|
// Wait for PGlite to initialize and the form to render
|
||||||
|
await page.getByLabel("Name").waitFor({ timeout: 15000 });
|
||||||
|
|
||||||
|
await page.getByLabel("Name").fill("Test User");
|
||||||
|
await page.getByLabel("PLZ").fill("10115");
|
||||||
|
await page.getByLabel("Ort").fill("Berlin");
|
||||||
|
await page.getByLabel("Krankenkasse").fill("TK");
|
||||||
|
await page.getByRole("button", { name: "Weiter" }).click();
|
||||||
|
await expect(page).toHaveURL(/prozess/, { timeout: 10000 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add a new contact and see it in the list", async ({ page }) => {
|
||||||
|
await page.getByRole("link", { name: "Kontakte" }).click();
|
||||||
|
await expect(page).toHaveURL(/kontakte/);
|
||||||
|
|
||||||
|
await page.getByRole("link", { name: /Neu/ }).click();
|
||||||
|
await expect(page).toHaveURL(/kontakte\/neu/);
|
||||||
|
|
||||||
|
await page.getByLabel("Name", { exact: false }).first().fill("Dr. Schmidt");
|
||||||
|
await page.getByLabel("Stadt").fill("Berlin");
|
||||||
|
await page.getByRole("button", { name: "Speichern" }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(/\/kontakte$/, { timeout: 10000 });
|
||||||
|
await expect(page.getByText("Dr. Schmidt")).toBeVisible({ timeout: 10000 });
|
||||||
|
});
|
||||||
18
e2e/onboarding.spec.ts
Normal file
18
e2e/onboarding.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
test("onboarding flow redirects new user and saves profile", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
await page.goto("/");
|
||||||
|
// PGlite WASM initialization takes time; wait for the redirect to complete
|
||||||
|
await expect(page).toHaveURL(/onboarding/, { timeout: 15000 });
|
||||||
|
|
||||||
|
await page.getByLabel("Name").fill("Max Mustermann");
|
||||||
|
await page.getByLabel("PLZ").fill("10115");
|
||||||
|
await page.getByLabel("Ort").fill("Berlin");
|
||||||
|
await page.getByLabel("Krankenkasse").fill("TK");
|
||||||
|
await page.getByRole("button", { name: "Weiter" }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(/prozess/, { timeout: 10000 });
|
||||||
|
await expect(page.getByText("Dein Fortschritt")).toBeVisible();
|
||||||
|
});
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.4.6",
|
"@biomejs/biome": "^2.4.6",
|
||||||
|
"@playwright/test": "^1.58.2",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
"@types/node": "^25.4.0",
|
"@types/node": "^25.4.0",
|
||||||
|
|||||||
13
playwright.config.ts
Normal file
13
playwright.config.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { defineConfig } from "@playwright/test";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: "e2e",
|
||||||
|
webServer: {
|
||||||
|
command: "bun dev",
|
||||||
|
port: 5173,
|
||||||
|
reuseExistingServer: true,
|
||||||
|
},
|
||||||
|
use: {
|
||||||
|
baseURL: "http://localhost:5173",
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -25,7 +25,7 @@ export function useTherapeutenListe() {
|
|||||||
return useDbQuery<TherapeutMitKontakte>(`
|
return useDbQuery<TherapeutMitKontakte>(`
|
||||||
SELECT
|
SELECT
|
||||||
t.id, t.name, t.stadt, t.therapieform,
|
t.id, t.name, t.stadt, t.therapieform,
|
||||||
(SELECT k.datum FROM kontakt k WHERE k.therapeut_id = t.id ORDER BY k.datum DESC LIMIT 1) as letzter_kontakt,
|
(SELECT k.datum::text FROM kontakt k WHERE k.therapeut_id = t.id ORDER BY k.datum DESC LIMIT 1) as letzter_kontakt,
|
||||||
(SELECT k.ergebnis FROM kontakt k WHERE k.therapeut_id = t.id ORDER BY k.datum DESC LIMIT 1) as letztes_ergebnis,
|
(SELECT k.ergebnis FROM kontakt k WHERE k.therapeut_id = t.id ORDER BY k.datum DESC LIMIT 1) as letztes_ergebnis,
|
||||||
(SELECT COUNT(*) FROM kontakt k WHERE k.therapeut_id = t.id) as kontakte_gesamt
|
(SELECT COUNT(*) FROM kontakt k WHERE k.therapeut_id = t.id) as kontakte_gesamt
|
||||||
FROM therapeut t
|
FROM therapeut t
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function OnboardingForm() {
|
|||||||
value.aktueller_schritt,
|
value.aktueller_schritt,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
navigate({ to: "/onboarding" });
|
navigate({ to: "/prozess" });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ export default defineConfig({
|
|||||||
manifest: false,
|
manifest: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
optimizeDeps: {
|
||||||
|
exclude: ["@electric-sql/pglite"],
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
|||||||
Reference in New Issue
Block a user