Files
Business-Management/tests/ALL_TESTS.md
T
curo1305 50d2348b36 refactor: rename MERGE_CHECKLIST to ALL_TESTS + add per-service test files
- tests/MERGE_CHECKLIST.md → tests/ALL_TESTS.md (git rename, updated header + index of sub-files)
- tests/backend_tests.md — §1–9, §18 (auth, users, admin, groups, appearance, service health, plugins, AI/doc settings, infra/security)
- tests/frontend_tests.md — §19 (UI & routing)
- tests/doc-service_tests.md — §10–16 (upload/processing, list/filtering, slide-over, sharing, categories, bulk actions, watch directory)
- tests/ai-service_tests.md — §17 (AI queue & providers)
- CLAUDE.md: updated merge checklist section, file tree, and self-update checkpoint with mandatory test-file update rule
- settings.local.json: added docker inspect/ps, curl, lsof, git merge/branch/log/diff/status/config/mv permissions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 02:19:51 +02:00

26 KiB
Raw Blame History

ALL_TESTS — Full Test Suite

Complete test suite covering all 19 feature areas. Run tests relevant to the changed area before merging any feature branch into main. Service-specific subsets live in separate files:

  • tests/backend_tests.md — §19, §18 (auth, users, admin, groups, appearance, service health, plugins, AI/doc settings, infra/security)
  • tests/frontend_tests.md — §19 (UI & routing)
  • tests/doc-service_tests.md — §1016 (upload/processing, list/filtering, slide-over, sharing, categories, bulk actions, watch directory)
  • tests/ai-service_tests.md — §17 (AI queue & providers)

Every test describes the exact UI action or API call to perform and the expected outcome.

Test environment: Feature stack at http://localhost:$PORT (see CLAUDE.md §Feature branch workflow). Admin credentials: any superuser account created during stack setup. Regular user credentials: a second non-admin account for permission boundary tests.


Legend

Symbol Meaning
Pass
Fail
N/A for this change

Mark each row before opening the PR.


1. Authentication

# Test Steps Expected
1.1 Register new account POST /api/auth/register with valid email + strong password 201; user row created; login works immediately
1.2 Password policy — too short Register with 7-char password 422 with validation error
1.3 Password policy — no uppercase Register with all-lowercase password 422 with validation error
1.4 Password policy — no special char Register without special character 422 with validation error
1.5 Password policy — common word Register with password containing "password" 422 with validation error
1.6 Duplicate email Register with an already-used email 400
1.7 Login — valid credentials POST /api/auth/login with correct email + password 200; access_token returned
1.8 Login — wrong password POST /api/auth/login with wrong password 401
1.9 Login — inactive account Admin deactivates user; attempt login 401
1.10 JWT expiry respected Manually craft token with exp in the past; call any protected route 401
1.11 Logout clears session Click Logout in UI; try navigating to / Redirected to /login
1.12 Unauthenticated redirect Open / without a token in localStorage Redirected to /login

2. User — Profile & Preferences

# Test Steps Expected
2.1 Fetch own profile GET /api/profile/me 200; profile auto-created if first request
2.2 Update profile fields PUT /api/profile/me with full_name, phone, position, address, date_of_birth 200; fields persisted; visible on /profile page
2.3 Invalid phone format PUT /api/profile/me with letters in phone field 422
2.4 Future date of birth PUT /api/profile/me with DOB = tomorrow 422
2.5 DOB before 1900 PUT /api/profile/me with DOB = 1899-12-31 422
2.6 Fetch dashboard preferences GET /api/users/me/preferences 200; app_ids list
2.7 Pin an app Dashboard → pencil button → press + on a card → save Card appears in pinned grid on next load
2.8 Unpin an app Dashboard → pencil button → press on a pinned card → save Card removed from pinned grid
2.9 Pin limit (50) PATCH /api/users/me/preferences with 51 app IDs 422
2.10 Color mode — user pref User sets mode to "dark"; reload page Dark theme applied; preference persists across sessions
2.11 Color mode — system fallback User has NULL color_mode; admin default_mode = "light" Light theme applied

3. Admin — Users

# Test Steps Expected
3.1 List all users Admin → /admin/users All registered users shown in table
3.2 Create user Admin clicks "Create user"; fills form 201; new user appears in list; can log in
3.3 Toggle user active Admin clicks toggle on active user User deactivated; login returns 401
3.4 Delete user Admin deletes a user 204; user no longer in list; their documents remain (orphaned)
3.5 Non-admin access Regular user navigates to /admin/users Redirected to /login
3.6 Admin 404 semantics Regular user calls GET /api/admin/users via curl 404 (not 403)

4. Admin — Groups

# Test Steps Expected
4.1 List groups Admin → /admin/groups All groups shown with member count
4.2 Create group Fill name + description → submit Group appears in list; {group_name}-admin bootstrap group also exists (auto-created on service start)
4.3 Edit group Click edit on group → change name → save Name updated
4.4 Delete group Delete group 204; group gone; memberships cascade-deleted
4.5 Add member Open group → search user → add 204; user appears in member list
4.6 Remove member Click remove on a member User removed from group
4.7 Duplicate group name Create group with name that already exists 400 / validation error shown
4.8 Non-admin access Regular user calls GET /api/admin/groups 404
4.9 Set group admin role Admin → group detail → tick "Group admin" checkbox on a member → save PATCH /api/admin/groups/{id}/members/{user_id}/admin with {"is_group_admin": true} returns 200; badge shown in member list
4.10 Unset group admin role Admin unticks "Group admin" on an existing group admin member Returns 200; badge removed; user loses group-admin privileges

5. Admin — Appearance

# Test Steps Expected
5.1 List themes Admin → /admin/appearance Built-in themes + any custom themes shown
5.2 Switch active theme Select a different theme → save All users see the new theme on next load
5.3 Create custom theme Admin → create theme. Required fields: id (slug), label, light (CSS vars object), dark (CSS vars object) 201; theme appears in selector; can be activated
5.4 Edit custom theme Admin edits colour values on a custom theme Colours update live after activation
5.5 Delete custom theme Admin deletes a custom theme 204; theme gone from selector; active theme reverts to default
5.6 Set default mode PATCH /api/settings/appearance with {"theme": "<id>", "default_mode": "dark"} (both fields required) 200; new users without a personal preference see dark mode

6. Service Health & Dashboard

# Test Steps Expected
6.1 Services endpoint GET /api/services (authenticated) Returns health status for doc-service and ai-service
6.2 Healthy service card Both services running → /apps page. API response uses healthy: true (boolean), not status: "healthy" Cards show "Available" badge; clicking navigates to the app
6.3 Unhealthy service card Stop doc-service container → wait 30s → /apps Doc-service card dimmed, "Unavailable", not clickable
6.4 Service recovery Restart stopped container → wait 30s Card returns to "Available"
6.5 Dashboard pinned cards Pin a service → go to / Pinned card appears in home grid
6.6 Customize mode Click pencil on dashboard → toggle cards Pinned list updates after save

7. Plugin System

# Test Steps Expected
7.1 List plugins GET /api/plugins (authenticated) Returns accessible plugins for current user
7.2 Superuser sees all plugins Log in as admin → GET /api/plugins All registered service plugins returned
7.3 Group member sees plugin Add user to doc-service-admin group → GET /api/plugins doc-service plugin returned
7.4 Unpermitted user hidden Regular user not in any admin group → GET /api/plugins Empty list (plugins hidden, not 403)
7.5 Manifest fetch GET /api/plugins/doc-service/manifest as permitted user JSON Schema + access rules returned
7.6 Settings read GET /api/plugins/doc-service/settings Current doc-service plugin settings returned
7.7 Settings write PATCH /api/plugins/doc-service/settings with valid payload 200; setting persisted to volume
7.8 Unpermitted settings access Regular user GET /api/plugins/doc-service/settings 404

8. AI Service Settings

# Test Steps Expected
8.1 Read AI config Admin (or ai-service-admin member) → GET /api/settings/ai Config returned; API keys masked
8.2 Update provider PATCH /api/settings/ai with provider = "anthropic" + valid key 200; config persisted
8.3 Test connection POST /api/settings/ai/test with valid config 200; success response from provider
8.4 Test connection — bad key POST /api/settings/ai/test with wrong API key 502 or error detail
8.5 Read system prompts GET /api/settings/system-prompts All registered service prompts returned
8.6 Update system prompt PATCH /api/settings/system-prompts/doc-service with new prompt text 200; doc-service picks up new prompt within 30s
8.7 Non-admin access Regular user calls any /api/settings/ai endpoint 404
8.8 ai-service-admin delegation Non-superuser added to ai-service-admin group → accesses AI settings page Page loads; can read and write settings

9. Document Service Settings

# Test Steps Expected
9.1 Read upload limits GET /api/settings/documents/limits (admin or doc-service-admin) max_pdf_bytes returned
9.2 Update upload limit PATCH /api/settings/documents/limits with new value 200; upload of oversized PDF now rejected with 413
9.3 Non-admin access Regular user calls GET /api/settings/documents/limits 404
9.4 Settings page loads Admin navigates to /apps/documents/settings Upload limits section + watch directory config visible
9.5 doc-service-admin delegation Non-superuser added to doc-service-admin → navigates to settings page Page loads; settings editable

10. Document Upload & Processing

# Test Steps Expected
10.1 Upload valid PDF Drag-and-drop or file picker → select a PDF under the size limit 202; document row appears with status=pending; transitions to done
10.2 Upload oversized PDF Upload a PDF exceeding max_pdf_bytes 413; error shown; no row created
10.3 Upload non-PDF Upload a .docx or .jpg 415; error shown
10.4 Multi-file upload Select 3 PDFs at once All 3 appear in upload queue panel; each processes independently
10.5 Upload queue panel During upload → check bottom-right panel Per-file status indicator; "Review →" link after each completes
10.6 Drag-and-drop overlay Drag file over the documents page Full-page overlay appears; drop uploads file
10.7 Processing status poll Upload a large PDF Table row auto-updates every 3s until status = done or failed
10.8 AI extraction result Open slide-over for a done document title, document_type, tags, extracted_data fields populated
10.9 Failed extraction AI service down → upload PDF Status = failed; error_message shown in slide-over
10.10 Re-analyse Click "Re-analyse" in slide-over 202; status resets to pending; re-processes through AI

11. Document List & Filtering

# Test Steps Expected
11.1 Default list Navigate to /apps/documents Own documents shown, newest first, 20 per page
11.2 Search Type in search box (debounced 400ms) Results filtered by title / filename / tags / type
11.3 Filter by status Add filter chip → Status → "done" Only completed docs shown
11.4 Filter by type Add filter chip → Document type → "invoice" Only invoices shown
11.5 Filter by category Add filter chip → Category → pick one Only docs in that category shown
11.6 Remove filter chip Click × on a chip Filter removed; full list restored
11.7 Sort by column Click "Date" column header List re-ordered; chevron indicates direction; click again reverses
11.8 Pagination Upload > 20 docs → scroll to bottom Page controls appear; page 2 loads next 20
11.9 "Mine" view Click "Mine" in SourcePanel Only own (uploaded) documents shown
11.10 "Shared with me" view Click "Shared with me" Docs shared by others via groups; own docs excluded
11.11 Category filter via SourcePanel Click a category in the left tree Table filtered to that category's documents
11.12 URL state preserved Apply filters → copy URL → open in new tab Same filters applied

12. Document Detail — Slide-over

# Test Steps Expected
12.1 Open slide-over Click any document row 480px right panel slides in; metadata loaded
12.2 Inline title edit Click pencil icon next to title → type new title → confirm Title saved; updated in table row
12.3 Change document type Click a type chip (Invoice, Receipt, etc.) Type updated immediately
12.4 Edit tags Click into tag area → type a tag → press Enter → remove a tag with × Tags saved correctly
12.5 Assign category Categories combobox → search → select Category badge appears on document; table row updates
12.6 Remove category Click × on an assigned category badge Category removed from document
12.7 AI category suggestions Slide-over shows "Suggested categories" "Assign" and "Create & Assign" buttons present; clicking assigns
12.8 Confirm folder suggestion "Confirm" button next to suggested_folder Category created (if needed) and assigned; suggested_folder cleared
12.9 Reject folder suggestion "Reject" button next to suggested_folder suggested_folder cleared; no category created
12.10 Confirm filename suggestion "Confirm" button next to suggested_filename title updated to suggested value; suggested_filename cleared
12.11 Reject filename suggestion "Reject" button next to suggested_filename suggested_filename cleared; title unchanged
12.12 Extracted data section Open slide-over on done doc Key-value table of AI-extracted fields (vendor, amounts, dates, etc.)
12.13 Raw text section Expand raw text collapse First ~500k chars of extracted PDF text shown
12.14 Download Click "Download" Browser downloads the original PDF file
12.15 View in new tab Click "View" PDF opens in new browser tab; URL auto-revokes after 60s
12.16 Delete — owner Click "Delete" → confirm dialog Document and file removed; table row gone
12.16b Delete — admin Admin opens any doc (not their own) → Delete → confirm Document deleted; 204 returned
12.16c Delete — can_delete share Group member whose share has can_delete=true → Delete 204; document removed; viewer_can_delete was true in DocumentOut
12.16d Delete — group admin User is group admin for a group the doc is shared with; no explicit can_delete flag → Delete 204; group admin always has delete rights for docs shared with their group
12.16e Delete — watch document, admin only Watch-ingested doc (source=watch); regular user → Delete 403 (not owner); admin can delete it
12.17 Non-owner cannot edit Recipient of shared doc opens slide-over (no can_delete, not group admin) Edit controls (type, tags, title, delete) absent; download available

13. Document Sharing

# Test Steps Expected
13.1 Share from slide-over Owner opens sharing section → selects a group from combobox → shares Group appears in shares list; share_count in table row increments
13.2 Only user's own groups shown Open group picker in share section Only groups the current user belongs to are listed
13.3 Recipient sees shared doc Log in as group member → "Shared with me" view Shared document appears with primary accent border
13.4 Recipient download Recipient clicks Download on shared doc PDF downloaded successfully
13.4b Non-owner calls GET /documents/{id}/shares Regular user on a doc they don't own 404 (doc-service hides existence, consistent with admin 404 semantics — not 403)
13.5 Recipient cannot delete Recipient opens slide-over Delete button absent
13.6 Recipient cannot re-share Recipient opens sharing section Share controls absent
13.7 Remove share Owner clicks remove on a group share Group removed; share_count decrements; recipient no longer sees doc
13.8 Bulk share Select multiple rows → bulk share → pick group All selected docs shared with that group
13.9 Share count indicator Document shared with 2 groups Users icon in table row shows "2"
13.10 Share with non-member group POST /api/documents/{id}/shares with group not in X-User-Groups 403 / validation error
13.11 Share with can_delete enabled Owner opens sharing section → tick "Allow group members to delete" → share can_delete=true stored; trash icon badge appears next to group name in shares list
13.12 Share without can_delete (default) Owner shares without ticking delete checkbox can_delete=false; recipient sees the doc but Delete button absent in slide-over
13.13 can_delete shown in shares list Share with can_delete=true → inspect shares list in slide-over Trash2 icon rendered beside the group name; tooltip "Group members can delete this document"
13.14 viewer_can_delete in document list Share with can_delete=true; log in as group member → GET /api/documents viewer_can_delete=true in the recipient's list response for that doc

14. Categories

# Test Steps Expected
14.1 Create category SourcePanel → "New category" form → submit Category appears in tree
14.2 Rename category Manage categories dialog → edit → save New name reflected everywhere
14.3 Delete category Delete category with documents assigned 204; documents remain; category assignment removed
14.4 Category search More than 4 categories → type in search field Tree filtered in real time
14.5 Manage categories dialog Click "Manage categories" Modal shows categories grouped by scope (Personal / Group / System) with lock icons on group and system categories
14.6 New category triggers re-analysis Create category with name similar to AI suggestion Background re-analysis triggered (check backend logs)
14.7 Create personal category SourcePanel → "New category" → no group selected → submit valid PascalCase name Created with scope=personal; visible only to owner
14.8 Create group-scoped category SourcePanel → "New category" → select a group → submit Created with scope=group; visible to all members of that group
14.9 Group category visible to group members Log in as another group member Group category appears in their category list and SourcePanel
14.10 Non-member cannot see group category Log in as user not in the group Group category absent from list
14.11 Only group admin can rename group category Regular group member → rename group category 403; group admin can rename it successfully
14.12 Only group admin can delete group category Regular group member → delete group category 403; group admin can delete it
14.13 System categories read-only for non-admin Regular user → Manage categories → rename/delete a system category 403; lock icon shown; action blocked in UI
14.14 Admin can manage system categories Superuser → rename or delete a system category Succeeds; ManageCategoriesDialog shows edit/delete controls for system rows
14.15 PascalCase naming enforced — invalid Create category named my-invoices or Invoice Reports 422 with message explaining PascalCase-with-dashes format
14.16 PascalCase naming enforced — valid Create category named Vendor-Invoices 201; category created successfully
14.17 SourcePanel scope sections Categories exist for all three scopes SourcePanel tree shows "Mine", per-group, and "System" sections separately

15. Bulk Actions

# Test Steps Expected
15.1 Select rows Tick checkboxes on multiple rows Floating bulk actions bar appears at bottom
15.2 Bulk share Select docs → Share with group → confirm All selected docs shared; confirmation
15.3 Bulk delete Select docs → Delete → confirm dialog All selected docs deleted; bar disappears
15.4 Clear selection Click "Clear" in bulk bar All checkboxes deselected; bar hides
15.5 Bulk bar — "Mine" view only Switch to "Shared with me" view Bulk actions bar not shown (no edit rights for shared docs)

16. Watch Directory

# Test Steps Expected
16.1 Enable watch Doc settings page → toggle watch_enabled on → save File watcher starts; backend logs confirm
16.2 Ingest new file Drop a PDF into the bind-mounted watch directory Document appears in "All Documents" view with source=watch
16.3 Sub-folder to category Place PDF in watch/invoices/ Document auto-assigned to "invoices" category
16.4 Startup scan Restart doc-service with PDFs already in watch dir Pre-existing PDFs ingested (idempotent — no duplicates)
16.5 AI folder suggestion ai_folder_suggestion enabled → ingest file suggested_folder populated; confirm/reject buttons visible in slide-over
16.6 AI rename suggestion ai_rename_suggestion enabled → ingest file suggested_filename populated; confirm/reject buttons visible
16.7 No-remove policy Delete PDF from watch dir Document record remains in DB
16.8 Disable watch Toggle watch_enabled off → save Watcher stops; new files dropped are not ingested
16.9 Watch docs visible to all users Log in as any authenticated user Watch-ingested docs (user_id = "watch") appear in "All Documents"

17. AI Service — Queue & Providers

# Test Steps Expected
17.1 Health check GET /health on ai-service (via backend services endpoint) {"status": "ok"}
17.2 Provider health GET /health/provider Active provider name, model, configured=true
17.3 Unconfigured provider Set provider to "anthropic" with empty API key → test connection 503 or 502 with clear error
17.4 Sync chat POST /chat with valid messages array Response returned synchronously
17.5 Queue — async job POST /queue/jobs job_id returned immediately
17.6 Queue — poll job GET /queue/jobs/{id} after enqueue Returns status (pendingdone) and result
17.7 Queue — cancel job DELETE /queue/jobs/{id} before processing Job removed; status = cancelled
17.8 Queue pause POST /queue/pause 204; current job finishes; no new jobs picked up
17.9 Queue resume POST /queue/resume after pause 204; worker resumes; pending jobs process
17.10 Priority ordering Enqueue LOW then HIGH job HIGH job processed first
17.11 Provider timeout POST /chat when provider is unreachable 504 returned after timeout

18. Infrastructure & Security

# Test Steps Expected
18.1 Non-root containers docker inspect <container> --format '{{.Config.User}}' for each service Returns 1001 (or 70 for db)
18.2 No host ports in prod docker compose up --build -ddocker ps Only port 80 (frontend) exposed; no 8000/8001/8010/5432
18.3 backend-net isolation curl http://localhost:8000 from host in prod Connection refused
18.4 Pre-commit hook runs Stage a file with eval("x")git commit Commit blocked; security_check.py output shown
18.5 Pre-commit hook — clean code Normal commit Hook passes; commit succeeds
18.6 JWT algorithm none rejected Craft token with "alg": "none" → call protected route 401
18.7 XSS — input sanitation Enter <script>alert(1)</script> in title/name fields Value stored as plain text; not executed in UI
18.8 SQL injection attempt Pass '; DROP TABLE documents; -- as search param 200 with empty results; no DB error
18.9 CORS curl -H "Origin: http://evil.com" http://localhost/api/users/me Request blocked or access-control-allow-origin not set for that origin
18.10 Config volume persistence Restart all containers AI provider config + doc limits survive restart
18.11 Migration auto-apply Start fresh stack Both alembic upgrade head chains run without error; all tables created

19. Frontend — UI & Routing

# Test Steps Expected
19.1 PrivateRoute redirect Open any protected route without token Redirected to /login
19.2 AdminRoute redirect Log in as non-admin → navigate to /admin Redirected to /login
19.3 ServiceAdminRoute Non-admin, non-group-member → navigate to /apps/documents/settings Redirected (access denied)
19.4 Sidebar collapse Click collapse button Sidebar shrinks to icon-only; expand restores labels
19.5 Apps accordion Click "Apps" in sidebar Expands to show "Documents" NavLink
19.6 SourcePanel visibility Navigate to /apps then /apps/documents SourcePanel only visible on /apps/documents route
19.7 Theme toggle Click sun/moon button Mode switches; persists on reload
19.8 Unknown route Navigate to /does-not-exist Redirected to /
19.9 TanStack Query cache Navigate away from docs → back List loads from cache instantly; background refetch runs
19.10 30s service poll Leave /apps open for 30s GET /api/services fires again in network tab
19.11 Three-dots menu not clipped Scroll document table → open three-dot actions on any row Dropdown renders above the table's overflow-hidden container; not cut off