test(e2e): split suite by feature area with shared resources
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.
This commit is contained in:
@@ -1,10 +1,22 @@
|
||||
*** Settings ***
|
||||
Library Browser
|
||||
Library RequestsLibrary
|
||||
Library Collections
|
||||
Library String
|
||||
Documentation Shared auth keywords. Use Login As Admin for browser flows;
|
||||
... Login Via HTTP for API-only assertions. Logout, Verify Session Invalid,
|
||||
... Login With Wrong Password, and Login Exceeds Rate Limit are extended helpers.
|
||||
|
||||
*** Keywords ***
|
||||
Login Via HTTP
|
||||
[Documentation] Login via HTTP and store session cookie for RequestsLibrary.
|
||||
... Call this before any RequestsLibrary keyword that needs auth.
|
||||
... Call this before any RequestsLibrary keyword that needs auth.
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
IF "${XFF_HEADER}" != ""
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
END
|
||||
Create Session bangsess ${BACKEND_URL} headers=${headers}
|
||||
${login_payload}= Create Dictionary password Hallo123!
|
||||
${login_payload}= Create Dictionary password ${TEST_PASSWORD}
|
||||
${login_resp}= POST On Session bangsess /api/v1/auth/login
|
||||
... json=${login_payload}
|
||||
... expected_status=200
|
||||
@@ -22,7 +34,7 @@ Login As Admin
|
||||
IF not ${body}[completed]
|
||||
# Complete setup wizard via HTTP API.
|
||||
${setup_payload}= Create Dictionary
|
||||
... master_password=Hallo123!
|
||||
... master_password=${TEST_PASSWORD}
|
||||
... database_path=bangui.db
|
||||
... fail2ban_socket=/var/run/fail2ban/fail2ban.sock
|
||||
... timezone=UTC
|
||||
@@ -50,7 +62,7 @@ Login As Admin
|
||||
... const res = await fetch('/api/v1/auth/login', {
|
||||
... method: 'POST',
|
||||
... headers: { 'Content-Type': 'application/json' },
|
||||
... body: JSON.stringify({ password: 'Hallo123!' }),
|
||||
... body: JSON.stringify({ password: '${TEST_PASSWORD}' }),
|
||||
... credentials: 'include'
|
||||
... });
|
||||
... const data = await res.json().catch(() => ({}));
|
||||
@@ -99,4 +111,61 @@ Login As Admin
|
||||
END
|
||||
|
||||
${final_url}= Get URL
|
||||
Log Login complete. URL: ${final_url}
|
||||
Log Login complete. URL: ${final_url}
|
||||
|
||||
Logout
|
||||
[Documentation] Logs out the current browser session via UI Sign Out button.
|
||||
Click css=[aria-label="Sign out"]
|
||||
Wait For Load State domcontentloaded
|
||||
# Should land on /login.
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
|
||||
Verify Session Invalid
|
||||
[Documentation] Calls GET /api/v1/auth/session with no cookie. Must return 401.
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/auth/session expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 401
|
||||
|
||||
Login With Wrong Password
|
||||
[Documentation] Browser-driven: type a wrong password, expect error message.
|
||||
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
|
||||
Fill Text css=input[type="password"] WrongPass99!
|
||||
Click css=button[type="submit"]
|
||||
# Expect to stay on /login.
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
# Wait briefly for error to render.
|
||||
Sleep 2s
|
||||
# The MessageBar shows an error string. Assert at least one error-pattern element visible.
|
||||
${error_visible}= Run Keyword And Return Status Wait For Elements State
|
||||
... css=[role="alert"] visible timeout=5s
|
||||
Should Be True ${error_visible} msg=No error message shown for wrong password
|
||||
Close Browser
|
||||
|
||||
Login Exceeds Rate Limit
|
||||
[Documentation] Posts 6 failed logins in a row from the same X-Forwarded-For.
|
||||
... Expects 429 on at least one attempt (limit is 5/min/IP).
|
||||
Set Random Xff Header
|
||||
${headers}= Create Dictionary
|
||||
... X-BanGUI-Request 1
|
||||
... X-Forwarded-For ${XFF_HEADER}
|
||||
... Content-Type application/json
|
||||
Create Session ratelim ${BACKEND_URL} headers=${headers}
|
||||
${payload}= Create Dictionary password wrongpass1!
|
||||
${got_429}= Set Variable ${FALSE}
|
||||
FOR ${i} IN RANGE 1 8
|
||||
${resp}= POST On Session ratelim /api/v1/auth/login
|
||||
... json=${payload} expected_status=any
|
||||
Log Attempt ${i}: status=${resp.status_code}
|
||||
IF ${resp.status_code} == 429
|
||||
${got_429}= Set Variable ${TRUE}
|
||||
BREAK
|
||||
END
|
||||
Sleep 0.5
|
||||
END
|
||||
Should Be True ${got_429} msg=Expected a 429 response after multiple failed logins
|
||||
Delete All Sessions
|
||||
Reference in New Issue
Block a user