Files
Charon/docs/reports/archive/DNS_BUTTON_FIX_COMPLETE.md
2026-03-04 18:34:49 +00:00

6.0 KiB

DNS Provider "Add Provider" Button Fix - Complete

Date: 2026-02-12 Issue: DNS provider tests failing with "button not found" error Status: RESOLVED - All 18 tests passing

Root Cause Analysis

Problem Chain:

  1. Cookie Domain Mismatch (Initial):

    • Playwright config used 127.0.0.1:8080 as baseURL
    • Auth setup saved cookies for localhost
    • Cookies wouldn't transfer between different domains
  2. localStorage Token Missing (Primary):

    • Frontend AuthContext checks localStorage.getItem('charon_auth_token') on mount
    • If token not found in localStorage, authentication fails immediately
    • httpOnly cookies (secure!) aren't accessible to JavaScript
    • Auth setup only saved cookies, didn't populate localStorage
    • Frontend redirected to login despite valid httpOnly cookie

Fixes Applied

Fix 1: Domain Consistency (playwright.config.js & global-setup.ts)

Changed: http://127.0.0.1:8080http://localhost:8080

Files Modified:

  • /projects/Charon/playwright.config.js (line 126)
  • /projects/Charon/tests/global-setup.ts (lines 101, 108, 138, 165, 394)

Reason: Cookies are domain-specific. Both auth setup and tests must use identical hostname for cookie sharing.

Fix 2: localStorage Token Storage (auth.setup.ts)

Added: Token extraction from login response and localStorage population in storage state

Changes:

// Extract token from login API response
const loginData = await loginResponse.json();
const token = loginData.token;

// Add localStorage to storage state
savedState.origins = [{
  origin: baseURL,
  localStorage: [
    { name: 'charon_auth_token', value: token }
  ]
}];

Reason: Frontend requires token in localStorage to initialize auth context, even though httpOnly cookie handles actual authentication.

Verification Results

DNS Provider CRUD Tests (18 total)

PLAYWRIGHT_COVERAGE=0 npx playwright test tests/dns-provider-crud.spec.ts --project=firefox

Result: 18/18 PASSED (31.8s)

Test Categories:

  • Create Provider (4 tests)

    • Manual DNS provider
    • Webhook DNS provider
    • Validation errors
    • URL format validation
  • Provider List (3 tests)

    • Display list/empty state
    • Show Add Provider button
    • Show provider details
  • Edit Provider (2 tests)

    • Open edit dialog
    • Update provider name
  • Delete Provider (1 test)

    • Show delete confirmation
  • API Operations (4 tests)

    • List providers
    • Create provider
    • Reject invalid type
    • Get single provider
  • Accessibility (4 tests)

    • Accessible form labels
    • Keyboard navigation
    • Error announcements

Technical Details

Authentication Flow (Fixed)

  1. Auth Setup (runs before tests):

    • POST /api/v1/auth/login with credentials
    • Backend returns {"token": "..."} in response body
    • Backend sets httpOnly auth_token cookie
    • Setup extracts token and saves to storage state:
      • cookies: [httpOnly auth_token cookie]
      • origins.localStorage: [charon_auth_token: token value]
  2. Browser Tests (inherit storage state):

    • Playwright loads cookies from storage state
    • Playwright injects localStorage from storage state
    • Frontend AuthContext checks localStorage → finds token ✓
    • Frontend calls /api/v1/auth/me (with httpOnly cookie) → 200 ✓
    • User authenticated, protected routes accessible ✓
  • httpOnly Cookie: Secure auth token (not accessible to JavaScript, protects from XSS)
  • localStorage Token: Frontend auth state trigger (tells React app user is logged in)
  • Both Required: Backend validates cookie, frontend needs localStorage for initialization

Impact Analysis

Tests Fixed:

  • tests/dns-provider-crud.spec.ts - All 18 tests

Tests Potentially Affected:

Any test navigating to protected routes after authentication. All should now work correctly with the fixed storage state.

No Regressions Expected:

  • Change is backwards compatible
  • Only affects E2E test authentication
  • Production auth flow unchanged

Files Modified

  1. playwright.config.js

    • Changed baseURL default for non-coverage mode to localhost:8080
    • Updated documentation to explain cookie domain requirements
  2. tests/global-setup.ts

    • Changed all IP references from 127.0.0.1 to localhost
    • Updated 5 locations for consistency
  3. tests/auth.setup.ts

    • Added token extraction from login response
    • Added localStorage population in storage state
    • Added imports: writeFileSync, existsSync, dirname
    • Added validation logging for localStorage creation

Lessons Learned

  1. Cookie Domains Matter: Even 127.0.0.1 vs localhost breaks cookie sharing
  2. Dual Auth Strategy: httpOnly cookies + localStorage both serve important purposes
  3. Storage State Power: Playwright storage state supports both cookies AND localStorage
  4. Auth Flow Alignment: E2E auth must match production auth exactly
  5. Debug First: Network monitoring revealed the real issue (localStorage check)

Next Steps

  1. All DNS provider tests passing
  2. ⏭️ Monitor other test suites for similar auth issues
  3. ⏭️ Consider documenting auth flow for future developers
  4. ⏭️ Verify coverage mode (Vite) still works with new auth setup

Commands for Future Reference

Run DNS provider tests

PLAYWRIGHT_COVERAGE=0 npx playwright test tests/dns-provider-crud.spec.ts --project=firefox

Regenerate auth state (if needed)

rm -f playwright/.auth/user.json
npx playwright test tests/auth.setup.ts

Check auth state contents

cat playwright/.auth/user.json | jq .

Conclusion

The "Add Provider" button was always present on the DNS Providers page. The issue was a broken authentication flow preventing tests from reaching the authenticated page state. By fixing cookie domain consistency and adding localStorage token storage to the auth setup, all DNS provider tests now pass reliably.

Impact: 18 previously failing tests now passing, 0 regressions introduced.