Skip to content

WEB-890: Implement storageState authentication bypass for Playwright E2E#3457

Open
DeathGun44 wants to merge 1 commit intoopenMF:devfrom
DeathGun44:WEB-890/playwright-auth-bypass
Open

WEB-890: Implement storageState authentication bypass for Playwright E2E#3457
DeathGun44 wants to merge 1 commit intoopenMF:devfrom
DeathGun44:WEB-890/playwright-auth-bypass

Conversation

@DeathGun44
Copy link
Copy Markdown
Contributor

@DeathGun44 DeathGun44 commented Mar 30, 2026

Description

Every Playwright E2E test currently goes through the full UI login flow, which is slow and fragile in CI. This PR adds a one-time auth setup that logs in once, saves the browser state, and reuses it across all tests — so they start pre-authenticated instantly.

Changes:

  • playwright/auth.setup.ts — New setup script that logs in once and saves auth state. Falls back gracefully when no backend is available.
  • playwright.config.ts — Added setup project so auth runs before all tests. Made base URL configurable via env var.
  • login.spec.ts & login-responsive.spec.ts — Wipe saved auth so login page tests still work normally.
  • authenticated-smoke.spec.ts — New test proving the bypass works (dashboard loads without redirect to login).
  • .gitignore — Exclude saved auth state files.

Related issues and discussion

#WEB-890

Screenshots, if any

N/A — no UI changes.

Checklist

  • If you have multiple commits please combine them into one commit by squashing them.
  • Read and understood the contribution guidelines at web-app/.github/CONTRIBUTING.md.

Summary by CodeRabbit

  • Chores

    • Exclude local Playwright authentication cache from version control
    • Make the end-to-end base URL configurable via environment
  • Tests

    • Add an automated authentication setup step to generate and persist E2E session state (CI-aware)
    • Add authenticated smoke tests to verify core logged-in flows
    • Ensure tests start with a clean storage state for isolation
    • Improve login test stability and use hash-based routes for navigation

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'pre_merge_checks'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9e72633c-f128-4207-8d2b-214fae47782b

📥 Commits

Reviewing files that changed from the base of the PR and between 03b5bf5 and f14a86d.

📒 Files selected for processing (6)
  • .gitignore
  • playwright.config.ts
  • playwright/auth.setup.ts
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright/tests/login-responsive.spec.ts
  • playwright/tests/login.spec.ts
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • playwright/auth.setup.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright/tests/login-responsive.spec.ts
  • playwright.config.ts
  • playwright/tests/login.spec.ts

Walkthrough

Adds Playwright E2E authentication: a global setup that logs in and persists storageState to playwright/.auth/user.json, updates Playwright config to run a setup project and reuse persisted auth for Chromium, adds authenticated smoke test, adjusts login tests, and ignores the auth folder in git.

Changes

Cohort / File(s) Summary
Gitignore
./.gitignore
Added /playwright/.auth/ to ignore persisted Playwright auth artifacts.
Playwright config
playwright.config.ts
Made use.baseURL environment-configurable (`process.env.E2E_BASE_URL
Auth setup script
playwright/auth.setup.ts
New global setup setup('authenticate', ...): ensures playwright/.auth exists, clears prior artifacts, reads E2E_USERNAME/E2E_PASSWORD, performs UI login, copies mifosXCredentials from sessionStorage to localStorage, writes storageState to playwright/.auth/user.json, verifies persisted auth.
Authenticated tests
playwright/tests/authenticated-smoke.spec.ts
New smoke test that skips if playwright/.auth/auth-failed exists; otherwise navigates to /#/, asserts no login redirect and that mat-toolbar is visible.
Login tests adjustments
playwright/tests/login.spec.ts, playwright/tests/login-responsive.spec.ts
Set file-level test.use({ storageState: { cookies: [], origins: [] } }) for clean state; switched absolute URLs to hash routes (/#/login); removed unconditional waits and improved timeout-based assertions; removed BOM from a file.

Sequence Diagram(s)

sequenceDiagram
    participant Config as Playwright Config
    participant Setup as Setup Project
    participant Auth as auth.setup.ts
    participant Browser as Browser Context
    participant Storage as Auth Storage
    participant Chromium as Chromium Project
    participant Tests as Test Specs

    Config->>Setup: run setup project (*.setup.ts)
    Setup->>Auth: execute authenticate routine
    Auth->>Browser: navigate to /#/login and submit credentials (from env)
    Browser->>Auth: render authenticated UI
    Auth->>Browser: copy mifosXCredentials sessionStorage -> localStorage
    Auth->>Storage: save browserContext.storageState(path: playwright/.auth/user.json)
    Auth->>Browser: create verification context using saved state and verify auth
    Config->>Chromium: run chromium project (depends on setup)
    Chromium->>Browser: launch with storageState from Storage
    Tests->>Browser: run authenticated tests against app
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • alberto-art3ch
  • IOhacker
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: implementing Playwright authentication state persistence via storageState, which is the central purpose of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
playwright/tests/login-responsive.spec.ts (1)

212-216: ⚠️ Potential issue | 🟡 Minor

Hardcoded URL bypasses configurable baseURL.

This test uses a hardcoded http://localhost:4200/login instead of a relative path, breaking compatibility with E2E_BASE_URL configuration added in playwright.config.ts.

🔧 Proposed fix
     for (const viewport of viewports) {
       await page.setViewportSize(viewport);
-      await page.goto('http://localhost:4200/login');
+      await page.goto('/#/login');
       await page.waitForLoadState('networkidle');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright/tests/login-responsive.spec.ts` around lines 212 - 216, The test
is using a hardcoded URL in the viewport loop (see the loop using viewports and
the page.goto call) which bypasses the configurable baseURL (E2E_BASE_URL in
playwright.config.ts); replace the hardcoded 'http://localhost:4200/login' with
a relative path so Playwright resolves it from the configured baseURL (e.g., use
'/login' with the existing page.goto call), or if you must read the env var,
derive base from E2E_BASE_URL and concatenate the path before calling page.goto;
update the page.goto invocation in the for (const viewport of viewports) loop
accordingly.
🧹 Nitpick comments (3)
playwright/auth.setup.ts (1)

59-63: Add timeout to verification assertion to avoid indefinite hang.

The verification assertion at line 62 lacks a timeout, unlike the similar assertions earlier (lines 36-37). If the verification navigation stalls, this could hang indefinitely.

⏱️ Proposed fix
   const verifyContext = await browser.newContext({ storageState: authFile });
   const verifyPage = await verifyContext.newPage();
   await verifyPage.goto('/#/');
-  await expect(verifyPage).not.toHaveURL(/.*login.*/);
+  await expect(verifyPage).not.toHaveURL(/.*login.*/, { timeout: 30000 });
   await verifyContext.close();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright/auth.setup.ts` around lines 59 - 63, The verification can hang
because the expect check on verifyPage has no timeout; update the expect call on
verifyPage (the expect(verifyPage).not.toHaveURL(/.*login.*/)) to include a
reasonable timeout option (e.g., { timeout: 5000 }) so the test fails fast if
navigation stalls, keeping the rest of the flow (verifyContext.close())
unchanged.
playwright/tests/login.spec.ts (1)

83-97: Replace brittle waitForTimeout with condition-based wait.

page.waitForTimeout(3000) introduces timing flakiness. Wait for a specific condition like the snackbar/error message visibility or URL stability instead.

As per coding guidelines for **/*.spec.ts: "encourage... minimal brittle timing dependencies."

⏱️ Proposed fix - wait for snackbar or URL stability
     // Attempt login with wrong password
     await loginPage.login('mifos', 'wrongpassword');
 
-    // Wait for the login attempt to process and any error notification to appear
-    // The app shows a snackbar notification for authentication errors
-    await page.waitForTimeout(3000);
+    // Wait for snackbar notification to appear (or URL to remain on login)
+    await expect(page.locator('simple-snack-bar, mat-snack-bar-container')).toBeVisible({ timeout: 10000 }).catch(() => {
+      // Snackbar may not appear in all error scenarios; URL check suffices
+    });
 
     // Should remain on login page after failed attempt (URL still contains /login)
     await expect(page).toHaveURL(/.*login.*/);

Alternatively, if snackbar selectors vary, simply rely on the URL assertion with an adequate timeout:

-    await page.waitForTimeout(3000);
-
-    // Should remain on login page after failed attempt (URL still contains /login)
-    await expect(page).toHaveURL(/.*login.*/);
+    // Should remain on login page after failed attempt
+    await expect(page).toHaveURL(/.*login.*/, { timeout: 10000 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright/tests/login.spec.ts` around lines 83 - 97, Replace the brittle
page.waitForTimeout(3000) in the "should handle invalid credentials gracefully"
test by awaiting a specific condition: either wait for the app's error
notification/snackbar to appear (e.g., await
expect(loginPage.errorSnackbar).toBeVisible()) after calling
loginPage.login('mifos', 'wrongpassword'), or rely on URL stability with a
timeout by using await expect(page).toHaveURL(/.*login.*/, { timeout: 5000 });
then proceed with the existing assertions (usernameInput/passwordInput
visibility); remove page.waitForTimeout entirely and use the targeted
expect-based wait instead.
playwright/tests/authenticated-smoke.spec.ts (1)

10-13: Consider adding a timeout to prevent indefinite waits.

While the test correctly skips in CI, when running locally against a slow backend, the default assertion timeouts may not be sufficient. Consider explicit timeouts for consistency with auth.setup.ts.

⏱️ Optional enhancement
   test('should load dashboard without login redirect', async ({ page }) => {
     await page.goto('/#/');
 
-    await expect(page).not.toHaveURL(/.*login.*/);
-    await expect(page.locator('mat-toolbar')).toBeVisible();
+    await expect(page).not.toHaveURL(/.*login.*/, { timeout: 30000 });
+    await expect(page.locator('mat-toolbar')).toBeVisible({ timeout: 10000 });
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright/tests/authenticated-smoke.spec.ts` around lines 10 - 13, The suite
'Authenticated Smoke Tests' currently skips in CI but lacks an explicit timeout,
so add a consistent test timeout (matching auth.setup.ts) to avoid indefinite
waits against slow backends: call test.setTimeout(...) at the top of the file
(before test.describe) or set a timeout option on the individual tests in the
'Authenticated Smoke Tests' describe block so that the suite or tests honor the
same timeout value used in auth.setup.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@playwright/tests/login-responsive.spec.ts`:
- Around line 212-216: The test is using a hardcoded URL in the viewport loop
(see the loop using viewports and the page.goto call) which bypasses the
configurable baseURL (E2E_BASE_URL in playwright.config.ts); replace the
hardcoded 'http://localhost:4200/login' with a relative path so Playwright
resolves it from the configured baseURL (e.g., use '/login' with the existing
page.goto call), or if you must read the env var, derive base from E2E_BASE_URL
and concatenate the path before calling page.goto; update the page.goto
invocation in the for (const viewport of viewports) loop accordingly.

---

Nitpick comments:
In `@playwright/auth.setup.ts`:
- Around line 59-63: The verification can hang because the expect check on
verifyPage has no timeout; update the expect call on verifyPage (the
expect(verifyPage).not.toHaveURL(/.*login.*/)) to include a reasonable timeout
option (e.g., { timeout: 5000 }) so the test fails fast if navigation stalls,
keeping the rest of the flow (verifyContext.close()) unchanged.

In `@playwright/tests/authenticated-smoke.spec.ts`:
- Around line 10-13: The suite 'Authenticated Smoke Tests' currently skips in CI
but lacks an explicit timeout, so add a consistent test timeout (matching
auth.setup.ts) to avoid indefinite waits against slow backends: call
test.setTimeout(...) at the top of the file (before test.describe) or set a
timeout option on the individual tests in the 'Authenticated Smoke Tests'
describe block so that the suite or tests honor the same timeout value used in
auth.setup.ts.

In `@playwright/tests/login.spec.ts`:
- Around line 83-97: Replace the brittle page.waitForTimeout(3000) in the
"should handle invalid credentials gracefully" test by awaiting a specific
condition: either wait for the app's error notification/snackbar to appear
(e.g., await expect(loginPage.errorSnackbar).toBeVisible()) after calling
loginPage.login('mifos', 'wrongpassword'), or rely on URL stability with a
timeout by using await expect(page).toHaveURL(/.*login.*/, { timeout: 5000 });
then proceed with the existing assertions (usernameInput/passwordInput
visibility); remove page.waitForTimeout entirely and use the targeted
expect-based wait instead.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b4ace1d1-160f-46fb-9abe-b7feb4ae4a45

📥 Commits

Reviewing files that changed from the base of the PR and between 4b9b2d4 and 358e26c.

📒 Files selected for processing (6)
  • .gitignore
  • playwright.config.ts
  • playwright/auth.setup.ts
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright/tests/login-responsive.spec.ts
  • playwright/tests/login.spec.ts

@DeathGun44 DeathGun44 force-pushed the WEB-890/playwright-auth-bypass branch from 358e26c to 5f7a618 Compare March 30, 2026 10:54
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
playwright/tests/login-responsive.spec.ts (1)

214-214: Good: Using relative hash-based route instead of hardcoded URL.

This correctly leverages the baseURL from playwright.config.ts. However, other tests in this file use loginPage.navigate() (via beforeEach). Consider using the same approach here for consistency:

♻️ Optional: Use LoginPage for navigation consistency
     for (const viewport of viewports) {
       await page.setViewportSize(viewport);
-      await page.goto('/#/login');
+      await loginPage.navigate();
       await page.waitForLoadState('networkidle');

This would align with the pattern used in other tests and ensure the URL is sourced from a single location (LoginPage.url).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright/tests/login-responsive.spec.ts` at line 214, Test uses
page.goto('/#/login') directly instead of the existing page object helper;
replace the direct navigation with the LoginPage helper by calling
loginPage.navigate() (or reference LoginPage.url if needed) so navigation is
consistent with other tests that use loginPage.navigate() in beforeEach; update
the test to use the loginPage.navigate() method and remove the page.goto call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@playwright/tests/login-responsive.spec.ts`:
- Line 214: Test uses page.goto('/#/login') directly instead of the existing
page object helper; replace the direct navigation with the LoginPage helper by
calling loginPage.navigate() (or reference LoginPage.url if needed) so
navigation is consistent with other tests that use loginPage.navigate() in
beforeEach; update the test to use the loginPage.navigate() method and remove
the page.goto call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de922a20-d6ef-4a2f-a469-19dc4d993cad

📥 Commits

Reviewing files that changed from the base of the PR and between 358e26c and 5f7a618.

📒 Files selected for processing (6)
  • .gitignore
  • playwright.config.ts
  • playwright/auth.setup.ts
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright/tests/login-responsive.spec.ts
  • playwright/tests/login.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (3)
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright.config.ts
  • playwright/auth.setup.ts

@DeathGun44 DeathGun44 force-pushed the WEB-890/playwright-auth-bypass branch from 5f7a618 to 0e4425b Compare March 30, 2026 11:09
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
playwright/tests/login-responsive.spec.ts (1)

212-215: Consider using the page object for consistency and stability.

This test uses direct page.goto() and networkidle wait while other tests in this file use loginPage.navigate() and loginPage.assertOnLoginPage(). The networkidle wait can be flaky in CI environments.

♻️ Suggested refactor for consistency
     for (const viewport of viewports) {
       await page.setViewportSize(viewport);
-      await page.goto('/#/login');
-      await page.waitForLoadState('networkidle');
+      await loginPage.navigate();
+      await loginPage.assertOnLoginPage();

       // Check no horizontal scroll

As per coding guidelines: "For tests: encourage clear Arrange-Act-Assert structure, stable selectors, and minimal brittle timing dependencies."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright/tests/login-responsive.spec.ts` around lines 212 - 215, Replace
the direct navigation and networkidle waiting in the viewport loop with the page
object helpers for consistency and stability: instead of calling
page.goto('/#/login') and page.waitForLoadState('networkidle') inside the loop
that uses page.setViewportSize(viewport), call loginPage.navigate() after
setting the viewport and then loginPage.assertOnLoginPage() to wait for a stable
page state; update any assertions that relied on networkidle to use the page
object's stable selectors/waits so tests follow the Arrange-Act-Assert pattern
and avoid flaky networkidle waits.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@playwright/tests/login-responsive.spec.ts`:
- Around line 212-215: Replace the direct navigation and networkidle waiting in
the viewport loop with the page object helpers for consistency and stability:
instead of calling page.goto('/#/login') and
page.waitForLoadState('networkidle') inside the loop that uses
page.setViewportSize(viewport), call loginPage.navigate() after setting the
viewport and then loginPage.assertOnLoginPage() to wait for a stable page state;
update any assertions that relied on networkidle to use the page object's stable
selectors/waits so tests follow the Arrange-Act-Assert pattern and avoid flaky
networkidle waits.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ffb80115-67ce-451b-ad58-a724f076b29d

📥 Commits

Reviewing files that changed from the base of the PR and between 5f7a618 and 0e4425b.

📒 Files selected for processing (6)
  • .gitignore
  • playwright.config.ts
  • playwright/auth.setup.ts
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright/tests/login-responsive.spec.ts
  • playwright/tests/login.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (4)
  • playwright/tests/login.spec.ts
  • playwright/tests/authenticated-smoke.spec.ts
  • playwright.config.ts
  • playwright/auth.setup.ts

@DeathGun44 DeathGun44 force-pushed the WEB-890/playwright-auth-bypass branch from 0e4425b to 03b5bf5 Compare March 30, 2026 11:29
@DeathGun44
Copy link
Copy Markdown
Contributor Author

DeathGun44 commented Mar 31, 2026

The failed check depends on #3459 ,i will rebase this pr when that one is approved and merged!

@DeathGun44 DeathGun44 force-pushed the WEB-890/playwright-auth-bypass branch from 03b5bf5 to 5a22264 Compare March 31, 2026 13:28
@DeathGun44 DeathGun44 marked this pull request as draft March 31, 2026 13:45
Signed-off-by: DeathGun44 <krishnamewara841@gmail.com>
@DeathGun44 DeathGun44 force-pushed the WEB-890/playwright-auth-bypass branch from 5a22264 to f14a86d Compare March 31, 2026 14:36
@DeathGun44 DeathGun44 marked this pull request as ready for review March 31, 2026 14:44
@DeathGun44
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant