From cbb9f230129947dc1aab7a01888b34a0a6757a0f Mon Sep 17 00:00:00 2001 From: default Date: Sun, 7 Jun 2026 06:34:54 +0000 Subject: [PATCH] chore: fix playwright config + gitignore test-results - playwright.config.ts: add testMatch pattern so playwright only picks up *.spec.ts (skipping tests/unit/*.test.ts which are vitest's domain). Before this, 'npx playwright test' would fail trying to run vitest tests. - .gitignore: exclude test-results/ and playwright-report/ (generated by 'npx playwright test', not source files). --- .gitignore | 4 + playwright.config.ts | 4 + test-results/.last-run.json | 8 - .../error-context.md | 152 ------------------ .../error-context.md | 152 ------------------ .../error-context.md | 152 ------------------ 6 files changed, 8 insertions(+), 464 deletions(-) delete mode 100644 test-results/.last-run.json delete mode 100644 test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md delete mode 100644 test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md delete mode 100644 test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md diff --git a/.gitignore b/.gitignore index 81d5216..1790433 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,10 @@ next-env.d.ts # Supabase supabase/.temp/ +# Playwright test results (generated, not source) +test-results/ +playwright-report/ + # IDE / local config .mcp.json .env* diff --git a/playwright.config.ts b/playwright.config.ts index d71384a..87aeb58 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,6 +10,10 @@ export default defineConfig({ forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: 1, + // Playwright should only run E2E specs — vitest owns everything under + // tests/unit/. The glob below matches *.spec.ts at the top of tests/ and + // tests/e2e/ and tests/login/ but skips the .test.ts files (vitest). + testMatch: /(tests\/(smoke|e2e|login)\/.*|\/[^/]+\.spec\.ts$)/, reporter: "list", use: { baseURL: LOCAL_BASE, diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index 9e24987..0000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "status": "failed", - "failedTests": [ - "9baefabce98ea24ee76d-2f6f670dfe942637faf7", - "9baefabce98ea24ee76d-f58eca1309366ec2998a", - "9baefabce98ea24ee76d-4a32d345869f5c6ceb12" - ] -} \ No newline at end of file diff --git a/test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md b/test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md deleted file mode 100644 index 9122b57..0000000 --- a/test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md +++ /dev/null @@ -1,152 +0,0 @@ -# Instructions - -- Following Playwright test failed. -- Explain why, be concise, respect Playwright best practices. -- Provide a snippet of code with the fix, if possible. - -# Test info - -- Name: login/login-flow.spec.ts >> admin session persists across page reloads -- Location: tests/login/login-flow.spec.ts:65:5 - -# Error details - -``` -Error: page.fill: value: expected string, got undefined -``` - -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - banner [ref=e2]: - - generic [ref=e3]: - - link "Route Commerce" [ref=e4] [cursor=pointer]: - - /url: / - - navigation [ref=e5]: - - link "Tuxedo" [ref=e6] [cursor=pointer]: - - /url: /tuxedo - - link "IRD" [ref=e7] [cursor=pointer]: - - /url: /indian-river-direct - - link "Admin" [ref=e8] [cursor=pointer]: - - /url: /admin - - button "Switch to dark mode" [ref=e9]: - - img [ref=e10] - - link "Cart (0)" [ref=e12] [cursor=pointer]: - - /url: /cart - - main [ref=e13]: - - generic [ref=e14]: - - generic [ref=e15]: - - heading "Admin Login" [level=1] [ref=e16] - - paragraph [ref=e17]: Sign in with your account. - - generic [ref=e18]: - - generic [ref=e19]: - - generic [ref=e20]: Email - - textbox "Email" [ref=e21]: - - /placeholder: admin@example.com - - generic [ref=e22]: - - generic [ref=e23]: Password - - textbox "Password" [ref=e24]: - - /placeholder: •••••••• - - button "Sign In" [ref=e25] - - button "Forgot password?" [ref=e26] - - link "← Back to storefront" [ref=e27] [cursor=pointer]: - - /url: / - - contentinfo [ref=e28]: - - generic [ref=e30]: - - paragraph [ref=e31]: © 2026 Route Commerce. All rights reserved. - - navigation [ref=e32]: - - link "Privacy Policy" [ref=e33] [cursor=pointer]: - - /url: /privacy-policy - - link "Terms & Conditions" [ref=e34] [cursor=pointer]: - - /url: /terms-and-conditions - - link "Powered by Route Commerce" [ref=e35] [cursor=pointer]: - - /url: https://cielohermosa.com - - alert [ref=e36] -``` - -# Test source - -```ts - 1 | import { test, expect } from "@playwright/test"; - 2 | - 3 | // ───────────────────────────────────────────────────────────── - 4 | // Login flow: credentials → /api/login JSON → redirect to /admin - 5 | // ───────────────────────────────────────────────────────────── - 6 | test("login with valid credentials redirects to /admin and shows admin dashboard", async ({ - 7 | page, - 8 | }) => { - 9 | // Navigate to login page - 10 | await page.goto("/login"); - 11 | - 12 | // Fill credentials - 13 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - 14 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!); - 15 | - 16 | // Submit form - 17 | await page.click('button[type="submit"]'); - 18 | - 19 | // Wait for navigation to /admin — the JSON response + client nav must happen - 20 | await page.waitForURL("**/admin", { timeout: 10000 }); - 21 | - 22 | // Admin dashboard must be rendered (Control Center heading or admin layout) - 23 | await expect(page.locator("body")).not.toContainText("Access Denied"); - 24 | await expect(page.locator("body")).not.toContainText("Login failed"); - 25 | }); - 26 | - 27 | // ───────────────────────────────────────────────────────────── - 28 | // Login failure: bad password shows error, stays on /login - 29 | // ───────────────────────────────────────────────────────────── - 30 | test("login with wrong password shows error and stays on /login", async ({ - 31 | page, - 32 | }) => { - 33 | await page.goto("/login"); - 34 | - 35 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - 36 | await page.fill("#password", "wrongpassword123!"); - 37 | - 38 | await page.click('button[type="submit"]'); - 39 | - 40 | // Error message should appear - 41 | await expect(page.locator('[role="alert"]')).toBeVisible({ timeout: 5000 }); - 42 | // Should NOT navigate away from login - 43 | await expect(page).toHaveURL(/\/login/); - 44 | }); - 45 | - 46 | // ───────────────────────────────────────────────────────────── - 47 | // Login with missing fields shows validation error - 48 | // ───────────────────────────────────────────────────────────── - 49 | test("login with missing email shows validation error", async ({ page }) => { - 50 | await page.goto("/login"); - 51 | - 52 | // Don't fill email, only password - 53 | await page.fill("#password", "something"); - 54 | - 55 | await page.click('button[type="submit"]'); - 56 | - 57 | // Browser validation should fire (email required) - 58 | await expect(page.locator("#email")).toHaveAttribute("required", ""); - 59 | }); - 60 | - 61 | // ───────────────────────────────────────────────────────────── - 62 | // Session persistence: after login, navigating to /admin - 63 | // should load without re-authenticating - 64 | // ───────────────────────────────────────────────────────────── - 65 | test("admin session persists across page reloads", async ({ page }) => { - 66 | // Login first - 67 | await page.goto("/login"); -> 68 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - | ^ Error: page.fill: value: expected string, got undefined - 69 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!); - 70 | await page.click('button[type="submit"]'); - 71 | await page.waitForURL("**/admin", { timeout: 10000 }); - 72 | - 73 | // Reload the page - 74 | await page.reload(); - 75 | - 76 | // Should still be on /admin (session cookie keeps user logged in) - 77 | await expect(page).toHaveURL(/\/admin/); - 78 | await expect(page.locator("body")).not.toContainText("Access Denied"); - 79 | }); - 80 | -``` \ No newline at end of file diff --git a/test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md b/test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md deleted file mode 100644 index 3daf2c5..0000000 --- a/test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md +++ /dev/null @@ -1,152 +0,0 @@ -# Instructions - -- Following Playwright test failed. -- Explain why, be concise, respect Playwright best practices. -- Provide a snippet of code with the fix, if possible. - -# Test info - -- Name: login/login-flow.spec.ts >> login with wrong password shows error and stays on /login -- Location: tests/login/login-flow.spec.ts:30:5 - -# Error details - -``` -Error: page.fill: value: expected string, got undefined -``` - -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - banner [ref=e2]: - - generic [ref=e3]: - - link "Route Commerce" [ref=e4] [cursor=pointer]: - - /url: / - - navigation [ref=e5]: - - link "Tuxedo" [ref=e6] [cursor=pointer]: - - /url: /tuxedo - - link "IRD" [ref=e7] [cursor=pointer]: - - /url: /indian-river-direct - - link "Admin" [ref=e8] [cursor=pointer]: - - /url: /admin - - button "Switch to dark mode" [ref=e9]: - - img [ref=e10] - - link "Cart (0)" [ref=e12] [cursor=pointer]: - - /url: /cart - - main [ref=e13]: - - generic [ref=e14]: - - generic [ref=e15]: - - heading "Admin Login" [level=1] [ref=e16] - - paragraph [ref=e17]: Sign in with your account. - - generic [ref=e18]: - - generic [ref=e19]: - - generic [ref=e20]: Email - - textbox "Email" [ref=e21]: - - /placeholder: admin@example.com - - generic [ref=e22]: - - generic [ref=e23]: Password - - textbox "Password" [ref=e24]: - - /placeholder: •••••••• - - button "Sign In" [ref=e25] - - button "Forgot password?" [ref=e26] - - link "← Back to storefront" [ref=e27] [cursor=pointer]: - - /url: / - - contentinfo [ref=e28]: - - generic [ref=e30]: - - paragraph [ref=e31]: © 2026 Route Commerce. All rights reserved. - - navigation [ref=e32]: - - link "Privacy Policy" [ref=e33] [cursor=pointer]: - - /url: /privacy-policy - - link "Terms & Conditions" [ref=e34] [cursor=pointer]: - - /url: /terms-and-conditions - - link "Powered by Route Commerce" [ref=e35] [cursor=pointer]: - - /url: https://cielohermosa.com - - alert [ref=e36] -``` - -# Test source - -```ts - 1 | import { test, expect } from "@playwright/test"; - 2 | - 3 | // ───────────────────────────────────────────────────────────── - 4 | // Login flow: credentials → /api/login JSON → redirect to /admin - 5 | // ───────────────────────────────────────────────────────────── - 6 | test("login with valid credentials redirects to /admin and shows admin dashboard", async ({ - 7 | page, - 8 | }) => { - 9 | // Navigate to login page - 10 | await page.goto("/login"); - 11 | - 12 | // Fill credentials - 13 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - 14 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!); - 15 | - 16 | // Submit form - 17 | await page.click('button[type="submit"]'); - 18 | - 19 | // Wait for navigation to /admin — the JSON response + client nav must happen - 20 | await page.waitForURL("**/admin", { timeout: 10000 }); - 21 | - 22 | // Admin dashboard must be rendered (Control Center heading or admin layout) - 23 | await expect(page.locator("body")).not.toContainText("Access Denied"); - 24 | await expect(page.locator("body")).not.toContainText("Login failed"); - 25 | }); - 26 | - 27 | // ───────────────────────────────────────────────────────────── - 28 | // Login failure: bad password shows error, stays on /login - 29 | // ───────────────────────────────────────────────────────────── - 30 | test("login with wrong password shows error and stays on /login", async ({ - 31 | page, - 32 | }) => { - 33 | await page.goto("/login"); - 34 | -> 35 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - | ^ Error: page.fill: value: expected string, got undefined - 36 | await page.fill("#password", "wrongpassword123!"); - 37 | - 38 | await page.click('button[type="submit"]'); - 39 | - 40 | // Error message should appear - 41 | await expect(page.locator('[role="alert"]')).toBeVisible({ timeout: 5000 }); - 42 | // Should NOT navigate away from login - 43 | await expect(page).toHaveURL(/\/login/); - 44 | }); - 45 | - 46 | // ───────────────────────────────────────────────────────────── - 47 | // Login with missing fields shows validation error - 48 | // ───────────────────────────────────────────────────────────── - 49 | test("login with missing email shows validation error", async ({ page }) => { - 50 | await page.goto("/login"); - 51 | - 52 | // Don't fill email, only password - 53 | await page.fill("#password", "something"); - 54 | - 55 | await page.click('button[type="submit"]'); - 56 | - 57 | // Browser validation should fire (email required) - 58 | await expect(page.locator("#email")).toHaveAttribute("required", ""); - 59 | }); - 60 | - 61 | // ───────────────────────────────────────────────────────────── - 62 | // Session persistence: after login, navigating to /admin - 63 | // should load without re-authenticating - 64 | // ───────────────────────────────────────────────────────────── - 65 | test("admin session persists across page reloads", async ({ page }) => { - 66 | // Login first - 67 | await page.goto("/login"); - 68 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - 69 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!); - 70 | await page.click('button[type="submit"]'); - 71 | await page.waitForURL("**/admin", { timeout: 10000 }); - 72 | - 73 | // Reload the page - 74 | await page.reload(); - 75 | - 76 | // Should still be on /admin (session cookie keeps user logged in) - 77 | await expect(page).toHaveURL(/\/admin/); - 78 | await expect(page.locator("body")).not.toContainText("Access Denied"); - 79 | }); - 80 | -``` \ No newline at end of file diff --git a/test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md b/test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md deleted file mode 100644 index daa973b..0000000 --- a/test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md +++ /dev/null @@ -1,152 +0,0 @@ -# Instructions - -- Following Playwright test failed. -- Explain why, be concise, respect Playwright best practices. -- Provide a snippet of code with the fix, if possible. - -# Test info - -- Name: login/login-flow.spec.ts >> login with valid credentials redirects to /admin and shows admin dashboard -- Location: tests/login/login-flow.spec.ts:6:5 - -# Error details - -``` -Error: page.fill: value: expected string, got undefined -``` - -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - banner [ref=e2]: - - generic [ref=e3]: - - link "Route Commerce" [ref=e4] [cursor=pointer]: - - /url: / - - navigation [ref=e5]: - - link "Tuxedo" [ref=e6] [cursor=pointer]: - - /url: /tuxedo - - link "IRD" [ref=e7] [cursor=pointer]: - - /url: /indian-river-direct - - link "Admin" [ref=e8] [cursor=pointer]: - - /url: /admin - - button "Switch to dark mode" [ref=e9]: - - img [ref=e10] - - link "Cart (0)" [ref=e12] [cursor=pointer]: - - /url: /cart - - main [ref=e13]: - - generic [ref=e14]: - - generic [ref=e15]: - - heading "Admin Login" [level=1] [ref=e16] - - paragraph [ref=e17]: Sign in with your account. - - generic [ref=e18]: - - generic [ref=e19]: - - generic [ref=e20]: Email - - textbox "Email" [ref=e21]: - - /placeholder: admin@example.com - - generic [ref=e22]: - - generic [ref=e23]: Password - - textbox "Password" [ref=e24]: - - /placeholder: •••••••• - - button "Sign In" [ref=e25] - - button "Forgot password?" [ref=e26] - - link "← Back to storefront" [ref=e27] [cursor=pointer]: - - /url: / - - contentinfo [ref=e28]: - - generic [ref=e30]: - - paragraph [ref=e31]: © 2026 Route Commerce. All rights reserved. - - navigation [ref=e32]: - - link "Privacy Policy" [ref=e33] [cursor=pointer]: - - /url: /privacy-policy - - link "Terms & Conditions" [ref=e34] [cursor=pointer]: - - /url: /terms-and-conditions - - link "Powered by Route Commerce" [ref=e35] [cursor=pointer]: - - /url: https://cielohermosa.com - - alert [ref=e36] -``` - -# Test source - -```ts - 1 | import { test, expect } from "@playwright/test"; - 2 | - 3 | // ───────────────────────────────────────────────────────────── - 4 | // Login flow: credentials → /api/login JSON → redirect to /admin - 5 | // ───────────────────────────────────────────────────────────── - 6 | test("login with valid credentials redirects to /admin and shows admin dashboard", async ({ - 7 | page, - 8 | }) => { - 9 | // Navigate to login page - 10 | await page.goto("/login"); - 11 | - 12 | // Fill credentials -> 13 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - | ^ Error: page.fill: value: expected string, got undefined - 14 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!); - 15 | - 16 | // Submit form - 17 | await page.click('button[type="submit"]'); - 18 | - 19 | // Wait for navigation to /admin — the JSON response + client nav must happen - 20 | await page.waitForURL("**/admin", { timeout: 10000 }); - 21 | - 22 | // Admin dashboard must be rendered (Control Center heading or admin layout) - 23 | await expect(page.locator("body")).not.toContainText("Access Denied"); - 24 | await expect(page.locator("body")).not.toContainText("Login failed"); - 25 | }); - 26 | - 27 | // ───────────────────────────────────────────────────────────── - 28 | // Login failure: bad password shows error, stays on /login - 29 | // ───────────────────────────────────────────────────────────── - 30 | test("login with wrong password shows error and stays on /login", async ({ - 31 | page, - 32 | }) => { - 33 | await page.goto("/login"); - 34 | - 35 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - 36 | await page.fill("#password", "wrongpassword123!"); - 37 | - 38 | await page.click('button[type="submit"]'); - 39 | - 40 | // Error message should appear - 41 | await expect(page.locator('[role="alert"]')).toBeVisible({ timeout: 5000 }); - 42 | // Should NOT navigate away from login - 43 | await expect(page).toHaveURL(/\/login/); - 44 | }); - 45 | - 46 | // ───────────────────────────────────────────────────────────── - 47 | // Login with missing fields shows validation error - 48 | // ───────────────────────────────────────────────────────────── - 49 | test("login with missing email shows validation error", async ({ page }) => { - 50 | await page.goto("/login"); - 51 | - 52 | // Don't fill email, only password - 53 | await page.fill("#password", "something"); - 54 | - 55 | await page.click('button[type="submit"]'); - 56 | - 57 | // Browser validation should fire (email required) - 58 | await expect(page.locator("#email")).toHaveAttribute("required", ""); - 59 | }); - 60 | - 61 | // ───────────────────────────────────────────────────────────── - 62 | // Session persistence: after login, navigating to /admin - 63 | // should load without re-authenticating - 64 | // ───────────────────────────────────────────────────────────── - 65 | test("admin session persists across page reloads", async ({ page }) => { - 66 | // Login first - 67 | await page.goto("/login"); - 68 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!); - 69 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!); - 70 | await page.click('button[type="submit"]'); - 71 | await page.waitForURL("**/admin", { timeout: 10000 }); - 72 | - 73 | // Reload the page - 74 | await page.reload(); - 75 | - 76 | // Should still be on /admin (session cookie keeps user logged in) - 77 | await expect(page).toHaveURL(/\/admin/); - 78 | await expect(page.locator("body")).not.toContainText("Access Denied"); - 79 | }); - 80 | -``` \ No newline at end of file