backup
This commit is contained in:
@@ -31,7 +31,7 @@ services:
|
||||
PUID: 0
|
||||
PGID: 0
|
||||
volumes:
|
||||
- ./fail2ban-dev-config:/config
|
||||
- ../data/fail2ban-dev-config:/config
|
||||
- fail2ban-dev-run:/var/run/fail2ban
|
||||
- /var/log:/var/log:ro
|
||||
- ./logs:/remotelogs/bangui
|
||||
@@ -70,9 +70,9 @@ services:
|
||||
volumes:
|
||||
- ../backend/app:/app/app:z
|
||||
- ../fail2ban-master:/app/fail2ban-master:ro,z
|
||||
- ../data:/data
|
||||
- ../data/data:/data
|
||||
- fail2ban-dev-run:/var/run/fail2ban:ro
|
||||
- ./fail2ban-dev-config:/config:rw
|
||||
- ../data/fail2ban-dev-config:/config:rw
|
||||
ports:
|
||||
- "${BANGUI_BACKEND_PORT:-8000}:8000"
|
||||
command:
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
[blocklist-import]
|
||||
|
||||
enabled = false
|
||||
filter =
|
||||
logpath = /dev/null
|
||||
backend = auto
|
||||
maxretry = 1
|
||||
findtime = 1d
|
||||
bantime = 86400
|
||||
ignoreip = 127.0.0.0/8 ::1 172.16.0.0/12
|
||||
@@ -1,10 +0,0 @@
|
||||
[manual-Jail]
|
||||
|
||||
enabled = false
|
||||
filter = manual-Jail
|
||||
logpath = /remotelogs/bangui/auth.log
|
||||
backend = polling
|
||||
maxretry = 3
|
||||
findtime = 120
|
||||
bantime = 60
|
||||
ignoreip = 127.0.0.0/8 ::1 172.16.0.0/12
|
||||
@@ -1 +0,0 @@
|
||||
https://lists.blocklist.de/lists/all.txt
|
||||
240
e2e/Instructions.md
Normal file
240
e2e/Instructions.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# AI Agent — General Instructions
|
||||
|
||||
You are an autonomous coding agent working on **BanGUI**, a web application for monitoring, managing, and configuring fail2ban through a clean web interface. This document defines how you operate, what rules you follow, and which workflow you repeat for every task.
|
||||
|
||||
Read this document completely before starting any work.
|
||||
|
||||
---
|
||||
|
||||
## 1. Project Context
|
||||
|
||||
BanGUI consists of two main parts:
|
||||
|
||||
| Layer | Stack | Docs |
|
||||
|---|---|---|
|
||||
| **Backend** | Python 3.12+, FastAPI, Pydantic v2, aiosqlite, structlog | [Backend-Development.md](Backend-Development.md) |
|
||||
| **Frontend** | TypeScript, React, Fluent UI v9, Vite | [Web-Development.md](Web-Development.md) |
|
||||
|
||||
Supporting documentation you must know and respect:
|
||||
|
||||
| Document | Purpose |
|
||||
|---|---|
|
||||
| [Features.md](Features.md) | Complete feature list and expected behaviour |
|
||||
| [Architekture.md](Architekture.md) | System architecture, component relationships, data flow |
|
||||
| [Web-Design.md](Web-Design.md) | Visual design rules, theming, layout, spacing, motion |
|
||||
| [Backend-Development.md](Backend-Development.md) | Backend coding rules, project structure, conventions |
|
||||
| [Web-Development.md](Web-Development.md) | Frontend coding rules, project structure, conventions |
|
||||
|
||||
**Always** consult the relevant document before writing code. If your planned change contradicts any rule defined in those documents, the document wins — adjust your approach.
|
||||
|
||||
---
|
||||
|
||||
## 2. General Rules
|
||||
|
||||
### 2.1 Follow the Docs
|
||||
|
||||
- Every coding convention, naming rule, project structure decision, and library choice is defined in the development docs. Do not deviate.
|
||||
- Backend code follows [Backend-Development.md](Backend-Development.md) — strict typing, async only, structlog, Pydantic models, layered architecture (routers → services → repositories).
|
||||
- Frontend code follows [Web-Development.md](Web-Development.md) — strict TypeScript, Fluent UI v9 only, `makeStyles` for styling, typed API calls, hooks for state.
|
||||
- Visual decisions follow [Web-Design.md](Web-Design.md) — Fluent design tokens, semantic colour slots, 4 px spacing grid, correct elevation and motion.
|
||||
|
||||
### 2.2 Write Production-Quality Code
|
||||
|
||||
- Write code as if it ships today. No TODOs, no placeholders, no half-implementations.
|
||||
- Every function has explicit type annotations (Python) or type signatures (TypeScript).
|
||||
- Every public function has a docstring (Python — Google style) or JSDoc comment (TypeScript).
|
||||
- No `any` in TypeScript. No `Any` in Python (unless justified with a comment).
|
||||
- No magic numbers or strings — use named constants.
|
||||
- No dead code, no commented-out blocks, no unused imports.
|
||||
|
||||
### 2.3 Keep It Small and Focused
|
||||
|
||||
- One function does one thing.
|
||||
- One component per file.
|
||||
- One service per domain.
|
||||
- If a file grows beyond ~150 lines (components) or ~200 lines (services), split it.
|
||||
|
||||
### 2.4 Never Break Existing Code
|
||||
|
||||
- Before changing any file, understand what it does and who depends on it.
|
||||
- Run the existing test suite before and after your changes. If tests fail after your change, fix them before moving on.
|
||||
- Do not remove or rename public APIs without updating all callers.
|
||||
|
||||
### 2.5 Think Before You Code
|
||||
|
||||
- Read the task description carefully. If it is ambiguous, check [Features.md](Features.md) and [Architekture.md](Architekture.md) for clarification.
|
||||
- Plan your changes before writing code. Identify which files are affected, which layers are involved, and what tests are needed.
|
||||
- Prefer the simplest correct solution. Do not over-engineer.
|
||||
|
||||
---
|
||||
|
||||
## 3. Task Workflow
|
||||
|
||||
Repeat the following cycle for every task. Do not skip steps.
|
||||
|
||||
|
||||
### Step 1 — Plan Your Steps
|
||||
|
||||
- Break the task into concrete implementation steps.
|
||||
- Identify which files need to be created, modified, or deleted.
|
||||
- Identify which layers are affected (router, service, repository, model, component, hook, page, type, etc.).
|
||||
- Identify edge cases and error scenarios.
|
||||
- Write down your plan before touching any code.
|
||||
|
||||
### Step 2 — Write Code
|
||||
|
||||
- Implement the feature or fix following the plan.
|
||||
- Follow all rules from the relevant development docs:
|
||||
- Backend → [Backend-Development.md](Backend-Development.md)
|
||||
- Frontend → [Web-Development.md](Web-Development.md)
|
||||
- Design → [Web-Design.md](Web-Design.md)
|
||||
- Architecture → [Architekture.md](Architekture.md)
|
||||
- Write clean, well-structured, fully typed code.
|
||||
- Keep commits atomic — one logical change per commit.
|
||||
|
||||
### Step 3 — Add Logging
|
||||
|
||||
- Add structured log statements at key points in new or modified code.
|
||||
- Backend: use **structlog** with contextual key-value pairs — never `print()`.
|
||||
- Log at appropriate levels: `info` for operational events, `warning` for recoverable issues, `error` for failures.
|
||||
- Never log sensitive data (passwords, tokens, session IDs).
|
||||
|
||||
### Step 4 — Write Tests
|
||||
|
||||
- Write tests for every new or changed piece of functionality.
|
||||
- Backend: use `pytest` + `pytest-asyncio` + `httpx.AsyncClient`. See [Backend-Development.md § 9](Backend-Development.md).
|
||||
- Frontend: test components and hooks according to the frontend test setup.
|
||||
- Test the happy path **and** error/edge cases.
|
||||
- Mock external dependencies — tests must never touch real infrastructure.
|
||||
- Follow the naming pattern: `test_<unit>_<scenario>_<expected>`.
|
||||
|
||||
### Step 5 — Review Your Code
|
||||
|
||||
Run a thorough self-review before considering the task done. Check **all** of the following:
|
||||
|
||||
#### 5.1 — Warnings and Errors
|
||||
|
||||
- Backend: run `ruff check` and `mypy --strict` (or `pyright --strict`). Fix every warning and error.
|
||||
- Frontend: run `tsc --noEmit` and `eslint`. Fix every warning and error.
|
||||
- Zero warnings, zero errors — no exceptions.
|
||||
|
||||
#### 5.2 — Test Coverage
|
||||
|
||||
- Run the test suite with coverage enabled.
|
||||
- Aim for **>80 % line coverage** overall.
|
||||
- Critical paths (auth, banning, scheduling, API endpoints) must be **100 %** covered.
|
||||
- If coverage is below the threshold, write additional tests before proceeding.
|
||||
|
||||
#### 5.3 — Coding Principles
|
||||
|
||||
Verify your code against the coding principles defined in [Backend-Development.md § 13](Backend-Development.md) and [Web-Development.md](Web-Development.md):
|
||||
|
||||
- [ ] **Clean Code** — Meaningful names, small functions, no magic values, guard clauses over deep nesting.
|
||||
- [ ] **Separation of Concerns** — Each module has a single, well-defined responsibility. Layers are not mixed.
|
||||
- [ ] **Single Responsibility Principle** — Every class and function has one reason to change.
|
||||
- [ ] **DRY** — No duplicated logic. Shared behaviour is extracted.
|
||||
- [ ] **KISS** — The simplest correct solution is used. No over-engineering.
|
||||
- [ ] **Type Safety** — All types are explicit. No `any` / `Any`. No `# type: ignore` without justification.
|
||||
|
||||
#### 5.4 — Architecture Compliance
|
||||
|
||||
Verify against [Architekture.md](Architekture.md) and the project structure rules:
|
||||
|
||||
- [ ] Files are in the correct directories (routers in `routers/`, services in `services/`, components in `components/`, etc.).
|
||||
- [ ] Dependencies flow in the right direction (routers → services → repositories; pages → components → hooks).
|
||||
- [ ] No circular imports.
|
||||
- [ ] No business logic in routers or components.
|
||||
- [ ] No HTTP/framework concerns in services or repositories.
|
||||
- [ ] Pydantic models separate request, response, and domain shapes.
|
||||
- [ ] Frontend types live in `types/`, not scattered across components.
|
||||
|
||||
### Step 6 — Update Documentation
|
||||
|
||||
- If your change introduces new features, new endpoints, new components, or changes existing behaviour, update the relevant docs:
|
||||
- [Features.md](Features.md) — if feature behaviour changed.
|
||||
- [Architekture.md](Architekture.md) — if new modules, services, or data flows were added.
|
||||
- [Backend-Development.md](Backend-Development.md) or [Web-Development.md](Web-Development.md) — if new conventions were established.
|
||||
- Keep documentation accurate and in sync with the code. Outdated docs are worse than no docs.
|
||||
|
||||
|
||||
## 5. When You Are Stuck
|
||||
|
||||
- Re-read the task description and the relevant docs.
|
||||
- Search the existing codebase for similar patterns — follow established conventions.
|
||||
- Check the fail2ban source code in `fail2ban-master/` if you need to understand how fail2ban works internally.
|
||||
- If a decision is genuinely ambiguous and no document covers it, choose the simplest option that is consistent with existing code and document your reasoning in a code comment.
|
||||
|
||||
---
|
||||
|
||||
## 6. What You Must Never Do
|
||||
|
||||
- **Never** commit code that does not compile or has type errors.
|
||||
- **Never** commit code without tests.
|
||||
- **Never** use libraries that are explicitly forbidden in the development docs.
|
||||
- **Never** bypass the linter or type checker with blanket ignores.
|
||||
- **Never** hard-code secrets, passwords, or tokens.
|
||||
- **Never** push directly to `main` — always use feature branches.
|
||||
- **Never** skip the review step — sloppy code compounds over time.
|
||||
- **Never** leave a task half-done — finish it or revert it.
|
||||
|
||||
---
|
||||
|
||||
## 7. First-Run Setup
|
||||
|
||||
### Initialize the Development Environment
|
||||
|
||||
Before starting the stack for the first time, set up the required environment variables:
|
||||
|
||||
1. **Copy the example environment file:**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
2. **Generate a session secret:**
|
||||
```bash
|
||||
python -c 'import secrets; print(secrets.token_hex(32))'
|
||||
```
|
||||
Copy the output and paste it as the value for `BANGUI_SESSION_SECRET` in your `.env` file.
|
||||
|
||||
3. **Optional: Customize other settings**
|
||||
- Edit `.env` to adjust timezone, port numbers, or other settings
|
||||
- Default values are sensible for development (UTC, ports 8000/5173)
|
||||
|
||||
4. **Start the stack:**
|
||||
```bash
|
||||
make up
|
||||
```
|
||||
|
||||
**Note:** The session secret is critical for security. Do not commit `.env` to version control — it is already in `.gitignore`. Each environment (dev, staging, production) must have its own unique secret.
|
||||
|
||||
---
|
||||
|
||||
## 8. Dev Quick-Reference
|
||||
|
||||
### Start / stop the stack
|
||||
|
||||
```bash
|
||||
make up # start all containers (from repo root)
|
||||
make down # stop all containers
|
||||
make logs # tail logs
|
||||
```
|
||||
|
||||
Backend: `http://127.0.0.1:8000` · Frontend (Vite proxy): `http://127.0.0.1:5173`
|
||||
|
||||
### API login (dev)
|
||||
|
||||
The frontend SHA256-hashes the password before sending it to the API.
|
||||
The initial setup password must be at least 8 characters long and include one uppercase letter, one number, and one special character from `!@#$%^&*()`.
|
||||
The session cookie is named `bangui_session`.
|
||||
|
||||
```bash
|
||||
# Dev master password: Hallo123!
|
||||
HASHED=$(echo -n "Hallo123!" | sha256sum | awk '{print $1}')
|
||||
TOKEN=$(curl -s -X POST http://127.0.0.1:8000/api/v1/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"password\":\"$HASHED\"}" \
|
||||
| python3 -c 'import sys,json; print(json.load(sys.stdin)["token"])')
|
||||
|
||||
# Use token in subsequent requests:
|
||||
curl -H "Cookie: bangui_session=$TOKEN" http://127.0.0.1:8000/api/v1/dashboard/status
|
||||
```
|
||||
2467
e2e/log.html
Normal file
2467
e2e/log.html
Normal file
File diff suppressed because one or more lines are too long
1520
e2e/output.xml
Normal file
1520
e2e/output.xml
Normal file
File diff suppressed because it is too large
Load Diff
93
e2e/playwright-log.txt
Normal file
93
e2e/playwright-log.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
{"level":30,"time":"2026-05-05T17:39:03.866Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Listening on 127.0.0.1:59711"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.908Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method newBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.955Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Adding browser to stack: chromium, version: 147.0.7727.15"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.955Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Adding 0 contexts to browser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.955Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method newBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.961Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method newPage"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.961Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"currentBrowser: {\"_contextStack\":[],\"browser\":{\"_type\":\"Browser\",\"_guid\":\"browser@55901c3a866b7fa3f570ea6e32bf6b10\"},\"name\":\"chromium\",\"id\":\"browser=247dd9e8-ea2c-4d1d-8907-8af4f70dce6e\",\"headless\":true}"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.969Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Setting default timeout for context context=238efdc3-cf83-4059-8956-d047f1446895 to 10000"}
|
||||
{"level":30,"time":"2026-05-05T17:39:03.969Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Changed active context: context=238efdc3-cf83-4059-8956-d047f1446895"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.009Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Video path: undefined"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.010Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Changed active page"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.016Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method newPage"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.020Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method goTo"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.515Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method goTo"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.520Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method waitForElementState"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.520Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Strict mode is enabled, find Locator with css=form in page."}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.633Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method waitForElementState"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.636Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getText"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.636Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Strict mode is enabled, find Locator with css=body in page."}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.658Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Retrieved text for element css=body containing BanGUI\nEnter your master password to continue.\nPassword*\nSign in"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.658Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getText"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.663Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method closeBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.667Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Removed page=fb0bbd95-3fca-4460-9169-e7cffa907f78 from context=238efdc3-cf83-4059-8956-d047f1446895 page stack"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.687Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method closeBrowser"}
|
||||
================= Original suppressed error =================
|
||||
Error: Browser has been closed.
|
||||
at PlaywrightState.getActiveBrowser (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/index.js:8777:13)
|
||||
at PlaywrightServer.getActiveBrowser (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/index.js:9689:52)
|
||||
at PlaywrightServer.setTimeout (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/index.js:9887:56)
|
||||
at Object.onReceiveHalfClose (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/node_modules/@grpc/grpc-js/build/src/server.js:1464:25)
|
||||
at BaseServerInterceptingCall.maybePushNextMessage (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/node_modules/@grpc/grpc-js/build/src/server-interceptors.js:595:31)
|
||||
at BaseServerInterceptingCall.handleEndEvent (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/node_modules/@grpc/grpc-js/build/src/server-interceptors.js:635:14)
|
||||
at ServerHttp2Stream.<anonymous> (/home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/node_modules/@grpc/grpc-js/build/src/server-interceptors.js:394:18)
|
||||
at ServerHttp2Stream.emit (node:events:531:35)
|
||||
at endReadableNT (node:internal/streams/readable:1698:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:89:21)
|
||||
=============================================================
|
||||
{"level":30,"time":"2026-05-05T17:39:04.692Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.692Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.694Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.694Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.697Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method newBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.749Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Adding browser to stack: chromium, version: 147.0.7727.15"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.749Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Adding 0 contexts to browser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.749Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method newBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.785Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.785Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.787Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.788Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.791Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.791Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.814Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.814Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.816Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.816Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.818Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.818Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.839Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.839Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.840Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.841Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.843Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.843Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.866Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.866Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.868Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.869Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.871Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.871Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.891Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.891Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.892Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.892Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.896Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.896Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.912Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.912Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.914Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.914Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.916Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.916Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.933Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.933Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.934Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.935Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.936Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.936Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method switchBrowser"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.955Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.955Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.957Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:04.957Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method getBrowserCatalog"}
|
||||
{"level":30,"time":"2026-05-05T17:39:05.067Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"Start of node method closeAllBrowsers"}
|
||||
{"level":30,"time":"2026-05-05T17:39:05.079Z","pid":252953,"hostname":"lukas-20tdcto1ww","msg":"End of node method closeAllBrowsers"}
|
||||
2729
e2e/report.html
Normal file
2729
e2e/report.html
Normal file
File diff suppressed because one or more lines are too long
@@ -1,31 +1,32 @@
|
||||
*** Settings ***
|
||||
Resource ${CURDIR}/common.resource
|
||||
Library Collections
|
||||
|
||||
*** Keywords ***
|
||||
Login As Admin
|
||||
# Check setup status.
|
||||
${response}= GET ${BACKEND_URL}/api/setup/status
|
||||
${response}= GET ${BACKEND_URL}/api/v1/setup
|
||||
${body}= Set Variable ${response.json()}
|
||||
|
||||
IF ${body}[setup_complete] == ${false}
|
||||
IF ${body}[completed] == ${false}
|
||||
# Complete the setup wizard with the dev master password ("Hallo123!").
|
||||
${password}= Set Variable Hallo123!
|
||||
${hashed}= Evaluate "sha256('${password}'.encode()).hexdigest()" modules=hashlib
|
||||
${setup_payload}= Create Dictionary password=${hashed}
|
||||
POST ${BACKEND_URL}/api/setup/complete json=${setup_payload}
|
||||
${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}
|
||||
|
||||
# Retry login after setup.
|
||||
${response}= GET ${BACKEND_URL}/api/auth/login
|
||||
${response}= POST ${BACKEND_URL}/api/v1/auth/login
|
||||
END
|
||||
|
||||
# Perform login.
|
||||
${password}= Set Variable Hallo123!
|
||||
${hashed}= Evaluate "sha256('${password}'.encode()).hexdigest()" modules=hashlib
|
||||
${login_payload}= Create Dictionary password=${hashed}
|
||||
${response}= POST ${BACKEND_URL}/api/auth/login json=${login_payload}
|
||||
${login_payload}= Create Dictionary password=Hallo123!
|
||||
${response}= POST ${BACKEND_URL}/api/v1/auth/login json=${login_payload}
|
||||
|
||||
# Store session cookie for subsequent requests.
|
||||
${cookies}= Get Cookies
|
||||
${session_cookie}= Get Cookie Value bangui_session
|
||||
Set Browser Variables session_cookie=${session_cookie}
|
||||
${session_cookie}= Get Cookie bangui_session
|
||||
Set Suite Variable ${session_cookie} ${session_cookie}
|
||||
Log Logged in as admin.
|
||||
@@ -15,7 +15,7 @@ Wait For Backend Health
|
||||
WHILE True
|
||||
${now}= Evaluate time.time()
|
||||
IF ${now} >= ${deadline} FAIL Backend did not become healthy within ${timeout} seconds
|
||||
${response}= GET ${BACKEND_URL}/api/health expected_status=200
|
||||
${response}= GET ${BACKEND_URL}/api/v1/health expected_status=200
|
||||
IF ${response.status} == 200 BREAK
|
||||
Sleep ${interval}
|
||||
END
|
||||
|
||||
@@ -52,7 +52,7 @@ Jail Detail Page Loads Without Error
|
||||
Login As Admin
|
||||
|
||||
# Guard: find an active jail before navigating to /jails/:name
|
||||
${response}= GET ${BACKEND_URL}/api/jails
|
||||
${response}= GET ${BACKEND_URL}/api/v1/jails
|
||||
${jails}= Set Variable ${response.json()}
|
||||
${count}= Get Length ${jails}
|
||||
|
||||
|
||||
899
output.xml
Normal file
899
output.xml
Normal file
@@ -0,0 +1,899 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<robot generator="Robot 7.4.2 (Python 3.12.3 on linux)" generated="2026-05-05T19:08:15.507887" rpa="false" schemaversion="5">
|
||||
<suite id="s1" name="05 Setup" source="/home/lukas/Volume/repo/BanGUI/e2e/tests/05_setup.robot">
|
||||
<kw name="Wait For Backend Health" owner="common" type="SETUP">
|
||||
<kw name="Evaluate" owner="BuiltIn">
|
||||
<var>${deadline}</var>
|
||||
<arg>time.time() + ${timeout}</arg>
|
||||
<doc>Evaluates the given expression in Python and returns the result.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.740159" elapsed="0.000384"/>
|
||||
</kw>
|
||||
<while condition="True">
|
||||
<iter>
|
||||
<kw name="Evaluate" owner="BuiltIn">
|
||||
<var>${now}</var>
|
||||
<arg>time.time()</arg>
|
||||
<doc>Evaluates the given expression in Python and returns the result.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.741110" elapsed="0.000327"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition="${now} >= ${deadline}">
|
||||
<kw name="Fail" owner="BuiltIn">
|
||||
<arg>Backend did not become healthy within ${timeout} seconds</arg>
|
||||
<doc>Fails the test with the given message and optionally alters its tags.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.741774" elapsed="0.000221"/>
|
||||
</kw>
|
||||
<status status="PASS" start="2026-05-05T19:08:15.741588" elapsed="0.000468"/>
|
||||
</branch>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.741558" elapsed="0.000550"/>
|
||||
</if>
|
||||
<kw name="GET" owner="RequestsLibrary">
|
||||
<var>${response}</var>
|
||||
<arg>${BACKEND_URL}/api/health</arg>
|
||||
<arg>expected_status=200</arg>
|
||||
<doc>Sends a GET request.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.742209" elapsed="0.000117"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition="${response.status} == 200">
|
||||
<break>
|
||||
<status status="PASS" start="2026-05-05T19:08:15.742528" elapsed="0.000068"/>
|
||||
</break>
|
||||
<status status="PASS" start="2026-05-05T19:08:15.742424" elapsed="0.000219"/>
|
||||
</branch>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.742404" elapsed="0.000277"/>
|
||||
</if>
|
||||
<kw name="Sleep" owner="BuiltIn">
|
||||
<arg>${interval}</arg>
|
||||
<doc>Pauses the test executed for the given time.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.742774" elapsed="0.000218"/>
|
||||
</kw>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.740686" elapsed="0.002366"/>
|
||||
</iter>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.740683" elapsed="0.002414"/>
|
||||
</while>
|
||||
<kw name="Log" owner="BuiltIn">
|
||||
<arg>Backend is healthy.</arg>
|
||||
<doc>Logs the given message with the given level.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.743215" elapsed="0.000260"/>
|
||||
</kw>
|
||||
<status status="PASS" start="2026-05-05T19:08:15.739266" elapsed="0.004473"/>
|
||||
</kw>
|
||||
<test id="s1-t1" name="Setup Page Renders All Form Fields" line="8">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.745093" elapsed="0.000515"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.745776" elapsed="0.000361"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=form</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.746289" elapsed="0.000619"/>
|
||||
</kw>
|
||||
<kw name="Get Element States" owner="Browser">
|
||||
<arg>css=input[autocomplete="username"]</arg>
|
||||
<arg>contains</arg>
|
||||
<arg>hidden</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Get the active states from the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.747066" elapsed="0.000378"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.747589" elapsed="0.000376"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Confirm Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.748120" elapsed="0.000348"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Database Path"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.748600" elapsed="0.000364"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="fail2ban Socket Path"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.749110" elapsed="0.000356"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Timezone"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.749601" elapsed="0.000379"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Session Duration (minutes)"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.750118" elapsed="0.000351"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.750597" elapsed="0.000349"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<arg>equals</arg>
|
||||
<arg>Complete Setup</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.751090" elapsed="0.003246"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:15.754577" elapsed="0.000388"/>
|
||||
</kw>
|
||||
<msg time="2026-05-05T19:08:15.762296" level="INFO">Starting Browser process /home/lukas/Volume/repo/BanGUI/.venv/lib/python3.12/site-packages/Browser/wrapper/index.js using at 127.0.0.1:34013</msg>
|
||||
<doc>Verify all setup wizard fields are present and labelled correctly.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:15.744062" elapsed="0.011088"/>
|
||||
</test>
|
||||
<test id="s1-t2" name="Password Strength Indicator Updates On Input" line="31">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.310648" elapsed="0.000409"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.311180" elapsed="0.000268"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.311537" elapsed="0.000286"/>
|
||||
</kw>
|
||||
<kw name="Get Elements" owner="Browser">
|
||||
<var>${segments}</var>
|
||||
<arg>css=.passwordStrengthSegment</arg>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns a reference to Playwright [https://playwright.dev/docs/api/class-locator|Locator]
|
||||
for all matched elements by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.311913" elapsed="0.000414"/>
|
||||
</kw>
|
||||
<kw name="Set Variable" owner="BuiltIn">
|
||||
<var>${active_count}</var>
|
||||
<arg>0</arg>
|
||||
<doc>Returns the given values which can then be assigned to a variables.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.312456" elapsed="0.000204"/>
|
||||
</kw>
|
||||
<for flavor="IN">
|
||||
<iter>
|
||||
<kw name="Get Attribute" owner="Browser">
|
||||
<var>${classes}</var>
|
||||
<arg>${seg}</arg>
|
||||
<arg>class</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns the HTML ``attribute`` of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.313169" elapsed="0.000313"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition=""Active" in """${classes}"""">
|
||||
<kw name="Evaluate" owner="BuiltIn">
|
||||
<var>${active_count}</var>
|
||||
<arg>${active_count} + 1</arg>
|
||||
<doc>Evaluates the given expression in Python and returns the result.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.313783" elapsed="0.000196"/>
|
||||
</kw>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.313609" elapsed="0.000430"/>
|
||||
</branch>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.313586" elapsed="0.000492"/>
|
||||
</if>
|
||||
<var name="${seg}"/>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.313007" elapsed="0.001092"/>
|
||||
</iter>
|
||||
<var>${seg}</var>
|
||||
<value>@{segments}</value>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.312756" elapsed="0.001379"/>
|
||||
</for>
|
||||
<kw name="Should Be Equal As Integers" owner="BuiltIn">
|
||||
<arg>${active_count}</arg>
|
||||
<arg>0</arg>
|
||||
<doc>Fails if objects are unequal after converting them to integers.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.314223" elapsed="0.000152"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>WeakPass</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.314455" elapsed="0.000211"/>
|
||||
</kw>
|
||||
<kw name="Set Variable" owner="BuiltIn">
|
||||
<var>${active_count}</var>
|
||||
<arg>0</arg>
|
||||
<doc>Returns the given values which can then be assigned to a variables.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.314754" elapsed="0.000162"/>
|
||||
</kw>
|
||||
<kw name="Get Elements" owner="Browser">
|
||||
<var>${segments}</var>
|
||||
<arg>css=.passwordStrengthSegment</arg>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns a reference to Playwright [https://playwright.dev/docs/api/class-locator|Locator]
|
||||
for all matched elements by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.314994" elapsed="0.000204"/>
|
||||
</kw>
|
||||
<for flavor="IN">
|
||||
<iter>
|
||||
<kw name="Get Attribute" owner="Browser">
|
||||
<var>${classes}</var>
|
||||
<arg>${seg}</arg>
|
||||
<arg>class</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns the HTML ``attribute`` of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.315479" elapsed="0.000193"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition=""Active" in """${classes}"""">
|
||||
<kw name="Evaluate" owner="BuiltIn">
|
||||
<var>${active_count}</var>
|
||||
<arg>${active_count} + 1</arg>
|
||||
<doc>Evaluates the given expression in Python and returns the result.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.315871" elapsed="0.000138"/>
|
||||
</kw>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.315745" elapsed="0.000307"/>
|
||||
</branch>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.315731" elapsed="0.000351"/>
|
||||
</if>
|
||||
<var name="${seg}"/>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.315383" elapsed="0.000717"/>
|
||||
</iter>
|
||||
<var>${seg}</var>
|
||||
<value>@{segments}</value>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.315254" elapsed="0.000877"/>
|
||||
</for>
|
||||
<kw name="Should Be Equal As Integers" owner="BuiltIn">
|
||||
<arg>${active_count}</arg>
|
||||
<arg>1</arg>
|
||||
<doc>Fails if objects are unequal after converting them to integers.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.316210" elapsed="0.000163"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.316448" elapsed="0.000183"/>
|
||||
</kw>
|
||||
<doc>The four-segment strength bar and rule count reflect password complexity.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.308758" elapsed="0.007965"/>
|
||||
</test>
|
||||
<test id="s1-t3" name="Password Mismatch Shows Validation Error" line="62">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.326594" elapsed="0.000369"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.327084" elapsed="0.000236"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.327412" elapsed="0.000268"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>Hallo123!</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.327775" elapsed="0.000231"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Confirm Password"]</arg>
|
||||
<arg>Different123!</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.328100" elapsed="0.000248"/>
|
||||
</kw>
|
||||
<kw name="Click" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Simulates mouse click on the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.328459" elapsed="0.000240"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Confirm Password"]</arg>
|
||||
<arg>attached</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.328786" elapsed="0.000260"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<var>${msg}</var>
|
||||
<arg>css=[aria-label="Confirm Password"]/ancestor::*[contains(@class,"field")]//*[contains(@class,"validationMessage")]</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.329139" elapsed="0.000224"/>
|
||||
</kw>
|
||||
<kw name="Should Be Equal As Strings" owner="BuiltIn">
|
||||
<arg>${msg}</arg>
|
||||
<arg>Passwords do not match.</arg>
|
||||
<doc>Fails if objects are unequal after converting them to strings.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.329449" elapsed="0.000162"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.329689" elapsed="0.000183"/>
|
||||
</kw>
|
||||
<doc>Submitting with non-matching passwords surfaces an error on Confirm Password.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.324720" elapsed="0.005238"/>
|
||||
</test>
|
||||
<test id="s1-t4" name="Empty Required Fields Show Validation Errors" line="78">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.337764" elapsed="0.000617"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.339155" elapsed="0.000380"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.339630" elapsed="0.000295"/>
|
||||
</kw>
|
||||
<kw name="Click" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Simulates mouse click on the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.340021" elapsed="0.000220"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Master Password"]</arg>
|
||||
<arg>attached</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.340332" elapsed="0.000283"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<var>${msg}</var>
|
||||
<arg>css=[aria-label="Master Password"]/ancestor::*[contains(@class,"field")]//*[contains(@class,"validationMessage")]</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.340716" elapsed="0.000225"/>
|
||||
</kw>
|
||||
<kw name="Should Be Equal As Strings" owner="BuiltIn">
|
||||
<arg>${msg}</arg>
|
||||
<arg>Password is required.</arg>
|
||||
<doc>Fails if objects are unequal after converting them to strings.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.341034" elapsed="0.000150"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Database Path"]</arg>
|
||||
<arg>attached</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.341263" elapsed="0.000230"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<var>${msg}</var>
|
||||
<arg>css=[aria-label="Database Path"]/ancestor::*[contains(@class,"field")]//*[contains(@class,"validationMessage")]</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.341583" elapsed="0.000230"/>
|
||||
</kw>
|
||||
<kw name="Should Be Equal As Strings" owner="BuiltIn">
|
||||
<arg>${msg}</arg>
|
||||
<arg>Database path is required.</arg>
|
||||
<doc>Fails if objects are unequal after converting them to strings.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.341894" elapsed="0.000174"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="fail2ban Socket Path"]</arg>
|
||||
<arg>attached</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.342145" elapsed="0.000233"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<var>${msg}</var>
|
||||
<arg>css=[aria-label="fail2ban Socket Path"]/ancestor::*[contains(@class,"field")]//*[contains(@class,"validationMessage")]</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.342462" elapsed="0.000205"/>
|
||||
</kw>
|
||||
<kw name="Should Be Equal As Strings" owner="BuiltIn">
|
||||
<arg>${msg}</arg>
|
||||
<arg>Socket path is required.</arg>
|
||||
<doc>Fails if objects are unequal after converting them to strings.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.342743" elapsed="0.000137"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.342953" elapsed="0.000209"/>
|
||||
</kw>
|
||||
<doc>Submitting with blank required fields shows field-level error messages.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.333829" elapsed="0.009421"/>
|
||||
</test>
|
||||
<test id="s1-t5" name="Invalid Session Duration Shows Validation Error" line="100">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.348383" elapsed="0.000370"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.348871" elapsed="0.000241"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.349206" elapsed="0.000282"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>Hallo123!</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.349584" elapsed="0.000216"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Confirm Password"]</arg>
|
||||
<arg>Hallo123!</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.349885" elapsed="0.000210"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Database Path"]</arg>
|
||||
<arg>bangui.db</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.350176" elapsed="0.000203"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="fail2ban Socket Path"]</arg>
|
||||
<arg>/var/run/fail2ban/fail2ban.sock</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.350456" elapsed="0.000188"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Session Duration (minutes)"]</arg>
|
||||
<arg>0</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.350721" elapsed="0.000220"/>
|
||||
</kw>
|
||||
<kw name="Click" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Simulates mouse click on the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.351058" elapsed="0.000285"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Session Duration (minutes)"]</arg>
|
||||
<arg>attached</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.351500" elapsed="0.000444"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<var>${msg}</var>
|
||||
<arg>css=[aria-label="Session Duration (minutes)"]/ancestor::*[contains(@class,"field")]//*[contains(@class,"validationMessage")]</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.352094" elapsed="0.000361"/>
|
||||
</kw>
|
||||
<kw name="Should Be Equal As Strings" owner="BuiltIn">
|
||||
<arg>${msg}</arg>
|
||||
<arg>Session duration must be at least 1 minute.</arg>
|
||||
<doc>Fails if objects are unequal after converting them to strings.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.352673" elapsed="0.000368"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.353712" elapsed="0.000212"/>
|
||||
</kw>
|
||||
<doc>Session duration below 1 minute triggers a validation error.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.346640" elapsed="0.007391"/>
|
||||
</test>
|
||||
<test id="s1-t6" name="Incomplete Password Shows Complexity Error" line="120">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.360793" elapsed="0.000405"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.361312" elapsed="0.000247"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.361647" elapsed="0.000293"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>short</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.362037" elapsed="0.000214"/>
|
||||
</kw>
|
||||
<kw name="Click" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Simulates mouse click on the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.362335" elapsed="0.000206"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=[aria-label="Master Password"]</arg>
|
||||
<arg>attached</arg>
|
||||
<arg>timeout=5s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.362621" elapsed="0.000231"/>
|
||||
</kw>
|
||||
<kw name="Get Text" owner="Browser">
|
||||
<var>${msg}</var>
|
||||
<arg>css=[aria-label="Master Password"]/ancestor::*[contains(@class,"field")]//*[contains(@class,"validationMessage")]</arg>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns text attribute of the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.362936" elapsed="0.000208"/>
|
||||
</kw>
|
||||
<kw name="Should Contain" owner="BuiltIn">
|
||||
<arg>${msg}</arg>
|
||||
<arg>Password must meet all complexity requirements.</arg>
|
||||
<doc>Fails if ``container`` does not contain ``item`` one or more times.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.363225" elapsed="0.000152"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.363456" elapsed="0.000181"/>
|
||||
</kw>
|
||||
<doc>Submitting a password that meets length but not all rules shows complexity error.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.359200" elapsed="0.004521"/>
|
||||
</test>
|
||||
<test id="s1-t7" name="Setup Completes Successfully And Redirects To Login" line="135">
|
||||
<kw name="New Browser" owner="Browser">
|
||||
<arg>chromium</arg>
|
||||
<arg>headless=${TRUE}</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Create a new playwright Browser with specified options.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.369227" elapsed="0.001419"/>
|
||||
</kw>
|
||||
<kw name="GET" owner="RequestsLibrary">
|
||||
<var>${status_resp}</var>
|
||||
<arg>${BACKEND_URL}/api/setup/status</arg>
|
||||
<doc>Sends a GET request.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.370784" elapsed="0.000122"/>
|
||||
</kw>
|
||||
<kw name="Set Variable" owner="BuiltIn">
|
||||
<var>${status_body}</var>
|
||||
<arg>${status_resp.json()}</arg>
|
||||
<doc>Returns the given values which can then be assigned to a variables.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.370993" elapsed="0.000163"/>
|
||||
</kw>
|
||||
<kw name="Log" owner="BuiltIn">
|
||||
<arg>Setup complete: ${status_body}[setup_complete]</arg>
|
||||
<doc>Logs the given message with the given level.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.371232" elapsed="0.000136"/>
|
||||
</kw>
|
||||
<kw name="Go To" owner="Browser">
|
||||
<arg>${FRONTEND_URL}/setup</arg>
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Navigates to the given ``url``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.371442" elapsed="0.000212"/>
|
||||
</kw>
|
||||
<kw name="Wait For Elements State" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>visible</arg>
|
||||
<arg>timeout=15s</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Wait</tag>
|
||||
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.371742" elapsed="0.000370"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Master Password"]</arg>
|
||||
<arg>Hallo123!</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.372275" elapsed="0.000292"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Confirm Password"]</arg>
|
||||
<arg>Hallo123!</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.372675" elapsed="0.000251"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Database Path"]</arg>
|
||||
<arg>bangui.db</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.373035" elapsed="0.000310"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="fail2ban Socket Path"]</arg>
|
||||
<arg>/var/run/fail2ban/fail2ban.sock</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.373452" elapsed="0.000267"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Timezone"]</arg>
|
||||
<arg>UTC</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.373819" elapsed="0.000256"/>
|
||||
</kw>
|
||||
<kw name="Fill Text" owner="Browser">
|
||||
<arg>css=input[aria-label="Session Duration (minutes)"]</arg>
|
||||
<arg>60</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.374156" elapsed="0.000240"/>
|
||||
</kw>
|
||||
<kw name="Click" owner="Browser">
|
||||
<arg>css=button[type="submit"]</arg>
|
||||
<tag>PageContent</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Simulates mouse click on the element found by ``selector``.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.374478" elapsed="0.000261"/>
|
||||
</kw>
|
||||
<kw name="Get Url" owner="Browser">
|
||||
<var>${current_url}</var>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns the current URL.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.374846" elapsed="0.000234"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition=""login" not in """${current_url}"""">
|
||||
<kw name="Evaluate" owner="BuiltIn">
|
||||
<var>${deadline}</var>
|
||||
<arg>time.time() + 15</arg>
|
||||
<doc>Evaluates the given expression in Python and returns the result.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.375390" elapsed="0.000221"/>
|
||||
</kw>
|
||||
<while condition="True">
|
||||
<iter>
|
||||
<kw name="Evaluate" owner="BuiltIn">
|
||||
<var>${now}</var>
|
||||
<arg>time.time()</arg>
|
||||
<doc>Evaluates the given expression in Python and returns the result.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.376079" elapsed="0.000214"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition="${now} >= ${deadline}">
|
||||
<break>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.376629" elapsed="0.000061"/>
|
||||
</break>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.376533" elapsed="0.000200"/>
|
||||
</branch>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.376510" elapsed="0.000263"/>
|
||||
</if>
|
||||
<kw name="Get Url" owner="Browser">
|
||||
<var>${url}</var>
|
||||
<tag>Assertion</tag>
|
||||
<tag>Getter</tag>
|
||||
<tag>PageContent</tag>
|
||||
<doc>Returns the current URL.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.376870" elapsed="0.000303"/>
|
||||
</kw>
|
||||
<if>
|
||||
<branch type="IF" condition=""login" in """${url}"""">
|
||||
<break>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.377395" elapsed="0.000052"/>
|
||||
</break>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.377278" elapsed="0.000200"/>
|
||||
</branch>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.377259" elapsed="0.000245"/>
|
||||
</if>
|
||||
<kw name="Sleep" owner="BuiltIn">
|
||||
<arg>0.5</arg>
|
||||
<doc>Pauses the test executed for the given time.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.377566" elapsed="0.000152"/>
|
||||
</kw>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.375690" elapsed="0.002063"/>
|
||||
</iter>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.375688" elapsed="0.002094"/>
|
||||
</while>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.375221" elapsed="0.002591"/>
|
||||
</branch>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.375197" elapsed="0.002640"/>
|
||||
</if>
|
||||
<kw name="GET" owner="RequestsLibrary">
|
||||
<var>${new_status_resp}</var>
|
||||
<arg>${BACKEND_URL}/api/setup/status</arg>
|
||||
<doc>Sends a GET request.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.377900" elapsed="0.000088"/>
|
||||
</kw>
|
||||
<kw name="Set Variable" owner="BuiltIn">
|
||||
<var>${new_status_body}</var>
|
||||
<arg>${new_status_resp.json()}</arg>
|
||||
<doc>Returns the given values which can then be assigned to a variables.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.378068" elapsed="0.000134"/>
|
||||
</kw>
|
||||
<kw name="Should Be True" owner="BuiltIn">
|
||||
<arg>${new_status_body}[setup_complete]</arg>
|
||||
<doc>Fails if the given condition is not true.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.378279" elapsed="0.000129"/>
|
||||
</kw>
|
||||
<kw name="Close Browser" owner="Browser">
|
||||
<tag>BrowserControl</tag>
|
||||
<tag>Setter</tag>
|
||||
<doc>Closes the current browser.</doc>
|
||||
<status status="NOT RUN" start="2026-05-05T19:08:16.378480" elapsed="0.000189"/>
|
||||
</kw>
|
||||
<doc>Filling all fields and submitting completes setup and navigates to /login.</doc>
|
||||
<status status="PASS" start="2026-05-05T19:08:16.366735" elapsed="0.012022"/>
|
||||
</test>
|
||||
<status status="PASS" start="2026-05-05T19:08:15.508608" elapsed="0.873487"/>
|
||||
</suite>
|
||||
<statistics>
|
||||
<total>
|
||||
<stat pass="7" fail="0" skip="0">All Tests</stat>
|
||||
</total>
|
||||
<tag>
|
||||
</tag>
|
||||
<suite>
|
||||
<stat name="05 Setup" id="s1" pass="7" fail="0" skip="0">05 Setup</stat>
|
||||
</suite>
|
||||
</statistics>
|
||||
<errors>
|
||||
<msg time="2026-05-05T19:08:15.732927" level="ERROR">Error in file '/home/lukas/Volume/repo/BanGUI/e2e/resources/common.resource' on line 5: Processing variable file '/home/lukas/Volume/repo/BanGUI/e2e/resources/../../.env' failed: Importing variable file '/home/lukas/Volume/repo/BanGUI/e2e/resources/../../.env' failed: Module name cannot contain dots when importing by path.</msg>
|
||||
</errors>
|
||||
</robot>
|
||||
Reference in New Issue
Block a user