Logging in once and reusing the session across tests is one of the biggest speed and reliability wins in an E2E suite. The standard mechanism is storageState, a JSON file containing cookies and localStorage that Playwright can preload into a context via test.use({ storageState: 'storageState.json' }). The recommended place to create that file is a globalSetup script that programmatically logs in (ideally through a test-only auth endpoint rather than the full UI) and writes the result into an .auth directory under the test project, e.g. e2e/.auth/storageState.json. Real-user secrets must never be committed; read credentials from env vars and treat the state file as an artifact.
Different roles deserve different sessions. Generate storageState.admin.json and storageState.user.json separately, then attach them with test.use({ storageState: ... }) inside the relevant describe blocks or projects. SSO and 2FA flows are notoriously brittle under UI automation, so prefer a storageState created manually once, an API-based test login, or a non-production auth bypass. After login, assert both the URL change and a unique logged-in UI element (such as a user menu) so a false-positive login is hard to slip through. Storage states should be paired with separate browser contexts per test to prevent auth or cookie bleed.
Deterministic tests need deterministic data. Create test-only seed/reset endpoints and call them from the built-in request fixture (await request.post('/api/test/seed', { data })) in test.beforeEach or beforeAll where appropriate. Be cautious with beforeAll for UI state: shared mutable data across workers is a frequent source of flakiness, so prefer per-test isolation or API seeding. For per-test uniqueness, prefix data with a run id (timestamp or UUID) and store it on testInfo or in an env var so cleanup scripts can find what each test created.