From a4a163ebc87350c9f868dd721e194848fcfc6274 Mon Sep 17 00:00:00 2001 From: Joker Date: Wed, 9 Sep 2026 21:32:18 +0000 Subject: [PATCH] =?UTF-8?q?test(e2e):=20playwright=201.63=20test=20locks?= =?UTF-8?q?=20=E2=80=94=20serialize=20shared-state=20specs,=20unpin=20CI?= =?UTF-8?q?=20workers=20(card=2098fb84ec)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RCA: quick-wins empty-state specs assume no suites/executions exist while projects/execution/signup/checkout mutate that same backend state. With fullyParallel the runs raced (local flake); CI sidestepped it with the workers=1 antipattern (full serialization of a 46-test suite). Fix (@playwright/test 1.62.0 -> 1.63.0): - lock 'suites': projects create-suite/create-case, execution run-suite, quick-wins suites/executions empty-state (mutate/read shared suites state) - lock 'signup': signup create-user + existing-email (user table state) - lock 'billing': checkout subscribe (Stripe session creation) - playwright.config.ts: remove 'workers: 1' CI pin — same-lock tests are now mutually exclusive scheduler-side, rest of suite stays parallel Verified (jokerserver, self-hosted prod stack :3010/:8010): - CI suite (smoke+app) green x2: 11 passed / 3 skipped (auth tests skip by design without E2E_AUTH secrets) / 0 failed, 14 workers - lock semantics demo (ephemeral spec, not committed): 3 same-lock tests zero overlap (next starts only after prior end), unlocked 3 fully concurrent, 6 tests / 2.5s wall on 6 workers Deps bump is test-tooling only; CI workflows already install browsers per-run (e2e.yml 'Install Playwright browsers' step). --- dashboard/frontend/e2e/checkout.spec.ts | 2 +- dashboard/frontend/e2e/execution.spec.ts | 2 +- dashboard/frontend/e2e/projects.spec.ts | 4 ++-- dashboard/frontend/e2e/quick-wins.spec.ts | 4 ++-- dashboard/frontend/e2e/signup.spec.ts | 4 ++-- dashboard/frontend/package-lock.json | 28 +++++++++++------------ dashboard/frontend/package.json | 2 +- dashboard/frontend/playwright.config.ts | 6 ++++- 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/dashboard/frontend/e2e/checkout.spec.ts b/dashboard/frontend/e2e/checkout.spec.ts index c7dc8537..73ade6ae 100644 --- a/dashboard/frontend/e2e/checkout.spec.ts +++ b/dashboard/frontend/e2e/checkout.spec.ts @@ -25,7 +25,7 @@ test.describe('Stripe Checkout Flow', () => { } }); - test('Checkout button redirects to Stripe', async ({ page }) => { + test('Checkout button redirects to Stripe', { lock: 'billing' }, async ({ page }) => { // Navegar a pricing si existe const pricingLink = page.locator('a:has-text("Pricing"), a:has-text("Plans")').first(); diff --git a/dashboard/frontend/e2e/execution.spec.ts b/dashboard/frontend/e2e/execution.spec.ts index 53cac4f8..5ed0ab42 100644 --- a/dashboard/frontend/e2e/execution.spec.ts +++ b/dashboard/frontend/e2e/execution.spec.ts @@ -16,7 +16,7 @@ test.describe('Test Execution Flow', () => { await expect(page).toHaveURL(/.*executions.*/); }); - test('Run test suite', async ({ page }) => { + test('Run test suite', { lock: 'suites' }, async ({ page }) => { await page.click('text=Test Suites'); await page.waitForURL('**/suites'); diff --git a/dashboard/frontend/e2e/projects.spec.ts b/dashboard/frontend/e2e/projects.spec.ts index b55ad694..64537eeb 100644 --- a/dashboard/frontend/e2e/projects.spec.ts +++ b/dashboard/frontend/e2e/projects.spec.ts @@ -17,7 +17,7 @@ test.describe('Project Management Flow', () => { await expect(page).toHaveURL(/.*suites.*/); }); - test('Create new test suite', async ({ page }) => { + test('Create new test suite', { lock: 'suites' }, async ({ page }) => { await page.click('text=Test Suites'); await page.waitForURL('**/suites'); @@ -36,7 +36,7 @@ test.describe('Project Management Flow', () => { } }); - test('Create test case in suite', async ({ page }) => { + test('Create test case in suite', { lock: 'suites' }, async ({ page }) => { await page.click('text=Test Suites'); await page.waitForURL('**/suites'); diff --git a/dashboard/frontend/e2e/quick-wins.spec.ts b/dashboard/frontend/e2e/quick-wins.spec.ts index 5e0c5e56..2c711f26 100644 --- a/dashboard/frontend/e2e/quick-wins.spec.ts +++ b/dashboard/frontend/e2e/quick-wins.spec.ts @@ -29,7 +29,7 @@ test.describe('Quick Wins - Celebrations & Time Saved', () => { } }) - test('Empty State - Test Suites page shows empty state when no suites', async ({ page }) => { + test('Empty State - Test Suites page shows empty state when no suites', { lock: 'suites' }, async ({ page }) => { // Navigate to Test Suites page await page.click('text=Test Suites') @@ -59,7 +59,7 @@ test.describe('Quick Wins - Celebrations & Time Saved', () => { } }) - test('Empty State - Executions page shows empty state when no executions', async ({ page }) => { + test('Empty State - Executions page shows empty state when no executions', { lock: 'suites' }, async ({ page }) => { // Navigate to Executions page await page.click('text=Executions') diff --git a/dashboard/frontend/e2e/signup.spec.ts b/dashboard/frontend/e2e/signup.spec.ts index 2283d2fb..8b9cacdb 100644 --- a/dashboard/frontend/e2e/signup.spec.ts +++ b/dashboard/frontend/e2e/signup.spec.ts @@ -10,7 +10,7 @@ test.describe('Signup Flow', () => { await expect(inputs.first()).toBeVisible(); }); - test('Signup with valid data creates user', async ({ page }) => { + test('Signup with valid data creates user', { lock: 'signup' }, async ({ page }) => { await page.goto('/signup'); await page.waitForLoadState('networkidle'); @@ -30,7 +30,7 @@ test.describe('Signup Flow', () => { expect(url).not.toContain('/signup'); }); - test('Signup with existing email shows error', async ({ page }) => { + test('Signup with existing email shows error', { lock: 'signup' }, async ({ page }) => { await page.goto('/signup'); await page.waitForLoadState('networkidle'); diff --git a/dashboard/frontend/package-lock.json b/dashboard/frontend/package-lock.json index 430e7984..02c53ba5 100644 --- a/dashboard/frontend/package-lock.json +++ b/dashboard/frontend/package-lock.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.5", - "@playwright/test": "^1.62.0", + "@playwright/test": "^1.63.0", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^14.3.1", "@testing-library/user-event": "^14.6.1", @@ -1720,13 +1720,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.62.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", - "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "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.62.1" + "playwright": "1.63.0" }, "bin": { "playwright": "cli.js" @@ -2322,6 +2322,7 @@ "version": "18.3.28", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -6427,28 +6428,25 @@ "license": "MIT" }, "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==", + "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.62.1" + "playwright-core": "1.63.0" }, "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==", + "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": { diff --git a/dashboard/frontend/package.json b/dashboard/frontend/package.json index b8953228..caf3028e 100644 --- a/dashboard/frontend/package.json +++ b/dashboard/frontend/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.5", - "@playwright/test": "^1.62.0", + "@playwright/test": "^1.63.0", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^14.3.1", "@testing-library/user-event": "^14.6.1", diff --git a/dashboard/frontend/playwright.config.ts b/dashboard/frontend/playwright.config.ts index c609efd6..d4b70273 100644 --- a/dashboard/frontend/playwright.config.ts +++ b/dashboard/frontend/playwright.config.ts @@ -14,7 +14,11 @@ export default defineConfig({ fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, - workers: process.env.CI ? 1 : undefined, + // Card 98fb84ec: the `workers: 1` pin (full serialization to protect + // shared-state tests) is gone — @playwright/test 1.63 test locks now + // serialize ONLY the specs that mutate/read shared backend state (see + // `lock:` in projects/execution/quick-wins/signup/checkout specs). The + // rest of the suite runs parallel in CI like it already did locally. reporter: "html", use: { baseURL: E2E_BASE_URL ?? "http://localhost:4173",