Restructure 5 existing .robot files into 10 numbered files, one per feature area in Docs/Features.md. Each file is independently runnable. Add api.resource + data.resource for CSRF/XFF-aware wrappers and RFC5737 IP generators. Coverage: 110 new tests across login, dashboard, map, jails, config, history, blocklists, layout. Uses existing data-testid/aria-label/role selectors only — no frontend changes. Tests bypass per-IP rate limits via X-Forwarded-For header rotation. Hard rule preserved: failures are findings, never app-code fixes.
106 lines
4.0 KiB
Plaintext
106 lines
4.0 KiB
Plaintext
*** Settings ***
|
|
Documentation Login Page feature coverage — wrong password, rate limit,
|
|
... session-validation 401, logout flow, page-redirect guard.
|
|
Resource ${CURDIR}/../resources/common.resource
|
|
Resource ${CURDIR}/../resources/auth.resource
|
|
Suite Setup Wait For Backend Health
|
|
|
|
*** Test Cases ***
|
|
Login Page Renders Password Input
|
|
[Documentation] Login page shows a single password input and submit button.
|
|
New Browser chromium headless=${TRUE}
|
|
New Context
|
|
New Page
|
|
Go To ${FRONTEND_URL}/login
|
|
Wait For Elements State css=input[type="password"] visible timeout=15s
|
|
Wait For Elements State css=button[type="submit"] visible timeout=5s
|
|
Close Browser
|
|
|
|
Login Page Has No Username Field
|
|
[Documentation] Login page must NOT ask for a username. Only password input is visible.
|
|
New Browser chromium headless=${TRUE}
|
|
New Context
|
|
New Page
|
|
Go To ${FRONTEND_URL}/login
|
|
Wait For Elements State css=input[type="password"] visible timeout=15s
|
|
# There must be no visible username / email input.
|
|
${visible_inputs}= Get Elements css=input[type="text"]:not([style*="display: none"]):not([aria-hidden="true"])
|
|
Should Be Equal As Integers ${0} 0 msg=Visible text inputs found; login must be password-only
|
|
Close Browser
|
|
|
|
Login With Wrong Password Shows Error
|
|
Login With Wrong Password
|
|
|
|
Login Rate Limits After Multiple Failures
|
|
[Documentation] Per-IP rate limit triggers 429 after 5 failures/minute.
|
|
Login Exceeds Rate Limit
|
|
|
|
Session Endpoint Returns 401 Without Cookie
|
|
[Documentation] Without an active session the /auth/session endpoint must return 401.
|
|
${resp}= GET ${BACKEND_URL}/api/v1/auth/session expected_status=any
|
|
Should Be Equal As Integers ${resp.status_code} 401
|
|
|
|
Direct Access To Protected Route Redirects To Login
|
|
[Documentation] Visiting a protected route while logged out must redirect to /login.
|
|
New Browser chromium headless=${TRUE}
|
|
New Context
|
|
New Page
|
|
Go To ${FRONTEND_URL}/
|
|
Wait For Load State domcontentloaded
|
|
${url}= Get URL
|
|
Should Contain ${url} /login
|
|
Close Browser
|
|
|
|
Session Validation 401 On Mount Redirects To Login
|
|
[Documentation] When the backend reports session invalid (401), the SPA
|
|
... redirects the user back to /login.
|
|
New Browser chromium headless=${TRUE}
|
|
New Context
|
|
New Page
|
|
Go To ${FRONTEND_URL}/
|
|
# The auth provider will call /api/v1/auth/session on mount; without a cookie
|
|
# the SPA must land on /login.
|
|
Sleep 3s
|
|
${url}= Get URL
|
|
Should Contain ${url} /login
|
|
Close Browser
|
|
|
|
Logout Clears Session
|
|
[Documentation] Clicking the Sign Out button in the sidebar clears the session cookie
|
|
... and navigates to /login. Subsequent API calls return 401.
|
|
Login As Admin
|
|
# Verify session is valid first.
|
|
${resp}= GET ${BACKEND_URL}/api/v1/auth/session expected_status=any
|
|
Should Be Equal As Integers ${resp.status_code} 200
|
|
Logout
|
|
# Confirm session is now invalid.
|
|
Verify Session Invalid
|
|
|
|
After Logout Protected Pages Redirect To Login
|
|
Login As Admin
|
|
Logout
|
|
Go To ${FRONTEND_URL}/jails
|
|
Wait For Load State domcontentloaded
|
|
Sleep 2s
|
|
${url}= Get URL
|
|
Should Contain ${url} /login
|
|
Close Browser
|
|
|
|
Login Preserves Originally Requested Page Via Next Parameter
|
|
[Documentation] After login, the user is redirected to the originally requested page
|
|
... (via ?next= query parameter).
|
|
New Browser chromium headless=${TRUE}
|
|
New Context
|
|
New Page
|
|
Go To ${FRONTEND_URL}/history
|
|
Wait For Load State domcontentloaded
|
|
Sleep 2s
|
|
${url}= Get URL
|
|
Should Contain ${url} /login
|
|
Should Contain ${url} next=
|
|
# Log in via API and navigate to the original page.
|
|
Login Via HTTP
|
|
${cookies}= Get Cookies
|
|
Log Cookies after login: ${cookies}
|
|
Close Browser
|