From 09cd10692ee7311f4321acf0e417096f6ce2cfa0 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Mon, 18 May 2026 04:45:30 +0200 Subject: [PATCH] test(fase-12): hermetic beforeEach reset for SV-01..03 The full `just test-all` first run surfaced state leakage from prior suites (tasks tests) into SV-02/SV-03: another spec had left the collective row's feature_flags populated, so by the time the SV suite ran the realtime test was hitting a noisy baseline. Add a symmetric beforeEach + afterEach that resets BOTH user.feature_flags (Ana + Borja, each via their own context to satisfy RLS) and collectives.feature_flags (seed collective, via Ana). Cost: ~6s per spec in setup overhead; benefit: 5 sequential `just test-all` runs green. Co-Authored-By: Claude Opus 4.7 --- apps/web/tests/e2e/section-visibility.test.ts | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/apps/web/tests/e2e/section-visibility.test.ts b/apps/web/tests/e2e/section-visibility.test.ts index e87d090..eee8db2 100644 --- a/apps/web/tests/e2e/section-visibility.test.ts +++ b/apps/web/tests/e2e/section-visibility.test.ts @@ -66,24 +66,45 @@ async function tabBarHasSection(page: Page, section: string): Promise { .count(); } +async function resetAllFlags(browser: import('@playwright/test').Browser): Promise { + // Reset the seed rows via Ana (the only user authoritative for both her own + // row AND the seed collective row). Patching another user's row from Ana + // would be blocked by RLS, so we open a second context for Borja. + const anaCtx = await browser.newContext(); + const anaPage = await anaCtx.newPage(); + try { + await loginAs(anaPage, USERS.ana); + await patchRow(anaPage, 'users', USERS.ana.id, { feature_flags: {} }); + await patchRow(anaPage, 'collectives', SEED_COLLECTIVE_ID, { feature_flags: {} }); + } catch { + /* don't mask original failure */ + } finally { + await anaCtx.close(); + } + + const borjaCtx = await browser.newContext(); + const borjaPage = await borjaCtx.newPage(); + try { + await loginAs(borjaPage, USERS.borja); + await patchRow(borjaPage, 'users', USERS.borja.id, { feature_flags: {} }); + } catch { + /* don't mask original failure */ + } finally { + await borjaCtx.close(); + } +} + test.describe('Section visibility', () => { + // Reset BOTH before and after every test. The before-each guards against + // state leakage from prior suites (the broader `just test-all` run shares + // the same Docker database with whatever tasks/lists tests ran before). + // The after-each keeps subsequent suites clean. + test.beforeEach(async ({ browser }) => { + await resetAllFlags(browser); + }); + test.afterEach(async ({ browser }) => { - // Best-effort cleanup as Ana so the collective row resets too. We only - // touch the seed rows — extra collectives created mid-test are left in - // place (the integration suite already covers the cross-collective path - // without leaking, and Playwright's seed.sql is rebuilt by `just db-reset`). - const ctx = await browser.newContext(); - const page = await ctx.newPage(); - try { - await loginAs(page, USERS.ana); - await patchRow(page, 'users', USERS.ana.id, { feature_flags: {} }); - await patchRow(page, 'users', USERS.borja.id, { feature_flags: {} }); - await patchRow(page, 'collectives', SEED_COLLECTIVE_ID, { feature_flags: {} }); - } catch { - /* don't mask the original failure */ - } finally { - await ctx.close(); - } + await resetAllFlags(browser); }); test('SV-01: Ana hides Tasks in /settings — sidebar + tab bar drop it, /tasks redirects to /lists', async ({