Files
BanGUI/e2e/resources/auth.resource
Lukas d4bab89cf3 fix(e2e): resolve SPA auth race conditions in Robot tests
- Rework Login As Admin: use sessionStorage flag + relative fetch login + polling loop
- Add data-testid to JailDetailPage error render path
- Add Collections library import for Get From List keyword
- Fix /jails API response extraction (returns {items, total} not plain list)
- Change Close Context to Close Browser for proper browser cleanup
- Add domcontentloaded + Sleep + polling to Config test to avoid premature timeout

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 06:53:09 +02:00

81 lines
3.3 KiB
Plaintext

*** Keywords ***
Login As Admin
[Documentation] Creates a new context and page and logs in via UI.
... Caller should NOT call New Context/New Page before this.
# Check setup status via HTTP API.
${response}= GET ${BACKEND_URL}/api/v1/setup
${body}= Set Variable ${response.json()}
Log Setup completed: ${body}[completed]
IF not ${body}[completed]
# Complete setup wizard via HTTP API.
${setup_payload}= Create Dictionary
... master_password=Hallo123!
... database_path=bangui.db
... fail2ban_socket=/var/run/fail2ban/fail2ban.sock
... timezone=UTC
... session_duration_minutes=60
POST ${BACKEND_URL}/api/v1/setup json=${setup_payload}
Log Setup POST completed.
END
# Create browser context.
New Context
New Page
Go To ${FRONTEND_URL}
Wait For Load State domcontentloaded
# Use fetch to call login API with browser credentials so the session cookie
# gets stored in the browser context. Use relative URL so Vite proxy handles it.
${login_result}= Evaluate JavaScript ${None}
... async () => {
... try {
... // Wait for React to fully initialize.
... await new Promise(r => setTimeout(r, 2000));
... const res = await fetch('/api/v1/auth/login', {
... method: 'POST',
... headers: { 'Content-Type': 'application/json' },
... body: JSON.stringify({ password: 'Hallo123!' }),
... credentials: 'include'
... });
... const data = await res.json().catch(() => ({}));
... return { ok: res.ok, status: res.status, data };
... } catch(e) {
... return { ok: false, error: String(e) };
... }
... }
Log API login result: ${login_result}
# Set sessionStorage so AuthProvider considers us authenticated without waiting
# for API re-validation on the next navigation.
Evaluate JavaScript ${None} () => sessionStorage.setItem('bangui_authenticated', 'true')
# Navigate directly to the dashboard instead of Reload. Reload causes a race
# where useSessionValidation's API call may redirect to /login before main renders.
# Going to / forces the SPA router to resolve routes while sessionStorage is already set.
Go To ${FRONTEND_URL}/
Wait For Load State domcontentloaded
# Poll for main to appear. The SPA remounts on navigation so domcontentloaded fires
# before React has finished authenticating and rendering the protected route.
${login_ok}= Set Variable ${TRUE}
FOR ${i} IN RANGE 1 16
${url}= Get URL
IF '/login' in '${url}'
# Still on /login after navigation — login did not succeed.
${login_ok}= Set Variable ${FALSE}
EXIT FOR LOOP
END
${found}= Run Keyword And Return Status Wait For Elements State css=main visible timeout=2s
IF ${found}
BREAK
END
END
IF not ${login_ok}
${last_result}= Set Variable ${login_result}
Fatal Error Login failed: ${last_result}
END
${final_url}= Get URL
Log Login complete. URL: ${final_url}