docs: update test plan format and structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-30 21:01:32 -05:00
parent 0ccd26444e
commit 56d393e127

View File

@@ -1,467 +1,408 @@
# TrakQR Test Plan
> Manual test plan for validating all features before release.
## Test Plan Overview
| Item | Details |
|------|---------|
| **Application** | TrakQR - QR-First URL Shortener SaaS |
| **Version** | MVP |
| **Test Type** | Functional / End-to-End |
| **Environment** | Development (`localhost:5173` + `localhost:42001`) |
## How to Use This Document
1. Work through each section sequentially
2. Check the box `[x]` when a test passes
3. Mark `[F]` for failures and add notes
4. Mark `[S]` for skipped tests with reason
---
## 1. Authentication
### 1.1 Registration
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.1.1 | Register with valid email | 1. Go to `/register`<br>2. Enter valid email and password (8+ chars)<br>3. Click Register | Account created, redirected to dashboard, default workspace created | [ ] |
| 1.1.2 | Register with invalid email | 1. Go to `/register`<br>2. Enter invalid email format<br>3. Click Register | Error message shown, no account created | [ ] |
| 1.1.3 | Register with short password | 1. Go to `/register`<br>2. Enter valid email, password < 8 chars<br>3. Click Register | Error message about password length | [ ] |
| 1.1.4 | Register with existing email | 1. Register a new account<br>2. Try to register again with same email | Error message about email already in use | [ ] |
| 1.1.5 | Registration rate limiting | 1. Attempt to register 15+ times in 1 minute | Rate limit error after ~10 attempts | [ ] |
### 1.2 Login
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.2.1 | Login with valid credentials | 1. Go to `/login`<br>2. Enter registered email/password<br>3. Click Login | Logged in, redirected to dashboard | [ ] |
| 1.2.2 | Login with wrong password | 1. Go to `/login`<br>2. Enter valid email, wrong password<br>3. Click Login | Error message, not logged in | [ ] |
| 1.2.3 | Login with non-existent email | 1. Go to `/login`<br>2. Enter unregistered email<br>3. Click Login | Error message (generic, no email enumeration) | [ ] |
| 1.2.4 | Login rate limiting | 1. Attempt failed logins 15+ times | Rate limit error after ~10 attempts | [ ] |
| 1.2.5 | Redirect after login | 1. Try to access `/links` while logged out<br>2. Get redirected to login<br>3. Login successfully | Redirected back to `/links` | [ ] |
### 1.3 Password Reset
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.3.1 | Request password reset | 1. Go to `/forgot-password`<br>2. Enter registered email<br>3. Click Submit | Success message shown (check console for email in dev) | [ ] |
| 1.3.2 | Reset with valid token | 1. Get reset token from email/console<br>2. Go to `/reset-password?token=xxx`<br>3. Enter new password | Password changed, can login with new password | [ ] |
| 1.3.3 | Reset with invalid token | 1. Go to `/reset-password?token=invalid`<br>2. Enter new password | Error message about invalid/expired token | [ ] |
| 1.3.4 | Reset with expired token | 1. Wait for token to expire (or modify DB)<br>2. Try to use token | Error message about expired token | [ ] |
### 1.4 Email Verification
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.4.1 | Verify with valid token | 1. Register new account<br>2. Get verification token from console<br>3. Go to `/verify-email?token=xxx` | Email verified, success message | [ ] |
| 1.4.2 | Verify with invalid token | 1. Go to `/verify-email?token=invalid` | Error message about invalid token | [ ] |
| 1.4.3 | Resend verification | 1. Login with unverified account<br>2. Go to Settings<br>3. Click "Resend verification" | New email sent (check console) | [ ] |
### 1.5 Logout
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.5.1 | Logout | 1. Login<br>2. Click Logout in sidebar | Logged out, redirected to login, protected routes inaccessible | [ ] |
| 1.5.2 | Session persistence | 1. Login<br>2. Close browser<br>3. Reopen and go to app | Still logged in (token in localStorage) | [ ] |
---
## 2. Workspaces
### 2.1 Workspace Management
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 2.1.1 | Default workspace exists | 1. Register new account<br>2. Check workspace selector | Default workspace present | [ ] |
| 2.1.2 | Create workspace | 1. Click + button in workspace selector<br>2. Enter name<br>3. Click Create | New workspace created, switched to it | [ ] |
| 2.1.3 | Switch workspace | 1. Have 2+ workspaces<br>2. Select different workspace from dropdown | Workspace switched, data refreshed | [ ] |
| 2.1.4 | Update workspace name | 1. Click settings icon in workspace selector<br>2. Change name<br>3. Save | Name updated | [ ] |
| 2.1.5 | Delete workspace | 1. Have 2+ workspaces<br>2. Open workspace settings<br>3. Click Delete | Workspace deleted, switched to another | [ ] |
| 2.1.6 | Cannot delete only workspace | 1. Have only 1 workspace<br>2. Try to delete it | Delete button disabled or error shown | [ ] |
| 2.1.7 | Workspace persistence | 1. Switch to workspace B<br>2. Refresh page | Still on workspace B (localStorage) | [ ] |
---
## 3. Projects
### 3.1 Project CRUD
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 3.1.1 | View projects page | 1. Go to `/projects` | Projects list shown (or empty state) | [ ] |
| 3.1.2 | Create project | 1. Click "New Project"<br>2. Enter name and description<br>3. Save | Project created, appears in list | [ ] |
| 3.1.3 | Edit project | 1. Click edit on a project<br>2. Change name/description<br>3. Save | Project updated | [ ] |
| 3.1.4 | Delete project | 1. Click delete on a project<br>2. Confirm deletion | Project removed from list | [ ] |
| 3.1.5 | Project shows link count | 1. Create project<br>2. Create links assigned to project<br>3. View projects | Link count displayed correctly | [ ] |
---
## 4. Short Links
### 4.1 Link Creation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.1.1 | Create link with auto slug | 1. Click "Create Link"<br>2. Enter destination URL only<br>3. Save | Link created with auto-generated slug | [ ] |
| 4.1.2 | Create link with custom slug | 1. Click "Create Link"<br>2. Enter URL and custom slug<br>3. Save | Link created with custom slug | [ ] |
| 4.1.3 | Create link with title | 1. Create link with title filled in | Title shown in list | [ ] |
| 4.1.4 | Create link with expiration | 1. Create link with expiration date set | Link shows expiration, stops working after date | [ ] |
| 4.1.5 | Create link with password | 1. Create link with password set | Link requires password to access | [ ] |
| 4.1.6 | Invalid destination URL | 1. Try to create link with invalid URL | Error message shown | [ ] |
| 4.1.7 | Duplicate slug | 1. Create link with slug "test"<br>2. Try to create another with same slug | Error message about duplicate | [ ] |
### 4.2 Link Management
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.2.1 | View links list | 1. Go to `/links` | Links listed with short URL, destination, clicks | [ ] |
| 4.2.2 | Copy short URL | 1. Click copy icon on a link | URL copied to clipboard | [ ] |
| 4.2.3 | Edit link | 1. Click edit on a link<br>2. Change destination URL<br>3. Save | Link updated, redirect goes to new URL | [ ] |
| 4.2.4 | Delete link (soft) | 1. Click delete on a link<br>2. Confirm | Link moved to trash | [ ] |
| 4.2.5 | View trash | 1. Click "Trash" toggle | Deleted links shown | [ ] |
| 4.2.6 | Restore link | 1. View trash<br>2. Click restore on a link | Link restored, works again | [ ] |
| 4.2.7 | Disable link | 1. Edit link<br>2. Set status to Disabled<br>3. Save | Link returns 404/disabled message | [ ] |
### 4.3 Bulk Import
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.3.1 | Bulk import URLs | 1. Click "Bulk Import"<br>2. Paste multiple URLs (one per line)<br>3. Import | All links created | [ ] |
| 4.3.2 | Bulk import with titles | 1. Paste URLs with titles: `https://example.com, My Title`<br>2. Import | Links created with titles | [ ] |
| 4.3.3 | Bulk import with invalid URLs | 1. Include some invalid URLs in list<br>2. Import | Valid URLs imported, errors shown for invalid | [ ] |
### 4.4 UTM Builder
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.4.1 | Add UTM parameters | 1. Create link<br>2. Expand UTM builder<br>3. Fill in source, medium, campaign | UTM params appended to destination | [ ] |
| 4.4.2 | UTM presets | 1. Click "Google Ads" preset | Fields populated with Google preset values | [ ] |
| 4.4.3 | UTM preview | 1. Fill in UTM fields | Preview shows full URL with params | [ ] |
---
## 5. Redirect
### 5.1 Public Redirect
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 5.1.1 | Basic redirect | 1. Create link to `https://example.com`<br>2. Visit short URL | Redirected to example.com | [ ] |
| 5.1.2 | Non-existent slug | 1. Visit `/{random-slug}` | 404 error page | [ ] |
| 5.1.3 | Disabled link | 1. Disable a link<br>2. Visit its short URL | Error message (link disabled) | [ ] |
| 5.1.4 | Expired link | 1. Create link with past expiration<br>2. Visit short URL | Error message (link expired) | [ ] |
| 5.1.5 | Password-protected link | 1. Create password-protected link<br>2. Visit short URL | Password prompt shown | [ ] |
| 5.1.6 | Password entry | 1. Visit password-protected link<br>2. Enter correct password | Redirected to destination | [ ] |
| 5.1.7 | Wrong password | 1. Visit password-protected link<br>2. Enter wrong password | Error, stays on password page | [ ] |
| 5.1.8 | Redirect rate limiting | 1. Hit redirect endpoint 100+ times rapidly | Rate limited after threshold | [ ] |
---
## 6. QR Codes
### 6.1 QR Creation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.1.1 | Create basic QR | 1. Go to `/qrcodes/new`<br>2. Select a link<br>3. Save | QR code created with default style | [ ] |
| 6.1.2 | QR requires link | 1. Go to `/qrcodes/new`<br>2. Try to save without link | Error message | [ ] |
| 6.1.3 | QR name | 1. Create QR with custom name | Name shown in list | [ ] |
### 6.2 QR Designer
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.2.1 | Change foreground color | 1. Edit QR<br>2. Change foreground color<br>3. View preview | QR updates with new color | [ ] |
| 6.2.2 | Change background color | 1. Change background color | QR updates with new background | [ ] |
| 6.2.3 | Module shapes | 1. Try Square, Rounded, Dots shapes | Each shape renders correctly | [ ] |
| 6.2.4 | Eye shapes | 1. Try Square, Rounded, Circle eye shapes | Each eye shape renders correctly | [ ] |
| 6.2.5 | Error correction levels | 1. Try L, M, Q, H levels | QR generates with different densities | [ ] |
| 6.2.6 | Quiet zone | 1. Adjust quiet zone size | Padding around QR changes | [ ] |
| 6.2.7 | Style presets | 1. Click each of 6 presets | Styles applied correctly | [ ] |
| 6.2.8 | Upload logo | 1. Click logo upload<br>2. Select image file | Logo appears in center of QR | [ ] |
| 6.2.9 | Select existing logo | 1. Have uploaded assets<br>2. Select from asset gallery | Logo applied from gallery | [ ] |
| 6.2.10 | Remove logo | 1. Have QR with logo<br>2. Remove logo | QR renders without logo | [ ] |
### 6.3 QR Export
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.3.1 | Export PNG | 1. View QR<br>2. Click "Download PNG" | PNG file downloaded | [ ] |
| 6.3.2 | Export SVG | 1. Click "Download SVG" | SVG file downloaded | [ ] |
| 6.3.3 | PNG has correct size | 1. Export PNG<br>2. Check dimensions | Matches selected size (256/512/1024) | [ ] |
| 6.3.4 | QR is scannable | 1. Export QR<br>2. Scan with phone | Opens correct short URL | [ ] |
| 6.3.5 | QR with logo is scannable | 1. Add logo to QR<br>2. Export and scan | Still scans correctly | [ ] |
### 6.4 QR List
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.4.1 | View QR list | 1. Go to `/qrcodes` | List shows QR previews | [ ] |
| 6.4.2 | QR preview thumbnails | 1. View list | Each QR shows thumbnail preview | [ ] |
| 6.4.3 | Delete QR | 1. Click delete on QR<br>2. Confirm | QR removed from list | [ ] |
| 6.4.4 | Edit QR | 1. Click edit on QR | Opens designer with saved settings | [ ] |
---
## 7. Analytics
### 7.1 Event Tracking
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.1.1 | Click event recorded | 1. Create link<br>2. Visit short URL<br>3. Check analytics | Click count increased | [ ] |
| 7.1.2 | Scan event recorded | 1. Create QR<br>2. Export and scan QR<br>3. Check QR analytics | Scan count increased | [ ] |
| 7.1.3 | Unique visitor tracking | 1. Visit same link multiple times quickly<br>2. Check analytics | Only 1 unique visitor (dedupe) | [ ] |
| 7.1.4 | Device detection | 1. Visit from mobile device<br>2. Check device breakdown | Mobile device recorded | [ ] |
| 7.1.5 | Referrer tracking | 1. Visit link from a webpage<br>2. Check referrer breakdown | Referrer domain recorded | [ ] |
| 7.1.6 | Country detection | 1. Visit link<br>2. Check geo breakdown | Country detected (if GeoIP configured) | [ ] |
### 7.2 Dashboard Analytics
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.2.1 | View dashboard | 1. Go to `/dashboard` | Stats cards, chart, breakdowns shown | [ ] |
| 7.2.2 | Total clicks | 1. Check total clicks card | Matches sum of all link clicks | [ ] |
| 7.2.3 | Time series chart | 1. View activity chart | Shows clicks/scans over time | [ ] |
| 7.2.4 | Top links | 1. View top links section | Most clicked links shown | [ ] |
| 7.2.5 | Device breakdown | 1. View device breakdown | Desktop/Mobile/Tablet shown | [ ] |
| 7.2.6 | Referrer breakdown | 1. View referrer breakdown | Top referrers listed | [ ] |
| 7.2.7 | Country breakdown | 1. View geo breakdown | Countries with flags shown | [ ] |
### 7.3 Period Filters
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.3.1 | 24h filter | 1. Click "24h" period | Data filtered to last 24 hours | [ ] |
| 7.3.2 | 7d filter | 1. Click "7d" period | Data filtered to last 7 days | [ ] |
| 7.3.3 | 30d filter | 1. Click "30d" period | Data filtered to last 30 days | [ ] |
### 7.4 Per-Link Analytics
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.4.1 | View link detail | 1. Go to `/links/{id}` | Link analytics shown | [ ] |
| 7.4.2 | Link-specific stats | 1. View link detail | Stats match only that link's data | [ ] |
### 7.5 Per-QR Analytics
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.5.1 | View QR analytics | 1. Go to `/qrcodes/{id}/analytics` | QR scan stats shown | [ ] |
| 7.5.2 | QR-specific stats | 1. View QR detail | Stats match only that QR's scans | [ ] |
---
## 8. Domains
### 8.1 Domain Management
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 8.1.1 | View domains page | 1. Go to `/domains` | Domains list or upgrade prompt (Free plan) | [ ] |
| 8.1.2 | Add domain (Pro+) | 1. Click "Add Domain"<br>2. Enter hostname<br>3. Submit | Domain added with Pending status | [ ] |
| 8.1.3 | Verification instructions | 1. Add new domain | TXT record and CNAME instructions shown | [ ] |
| 8.1.4 | Copy verification token | 1. Click copy on verification token | Token copied to clipboard | [ ] |
| 8.1.5 | Verify domain | 1. Add DNS records<br>2. Click "Verify" | Domain status changes to Verified | [ ] |
| 8.1.6 | Delete domain | 1. Click delete on domain<br>2. Confirm | Domain removed | [ ] |
| 8.1.7 | Free plan restriction | 1. Be on Free plan<br>2. Try to add domain | Upgrade prompt shown | [ ] |
---
## 9. Settings
### 9.1 Profile
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.1.1 | View profile | 1. Go to `/settings` | Current email shown | [ ] |
| 9.1.2 | Update email | 1. Change email<br>2. Save | Email updated | [ ] |
| 9.1.3 | Verification warning | 1. Have unverified email | Warning shown with resend link | [ ] |
### 9.2 Password Change
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.2.1 | Change password | 1. Enter current password<br>2. Enter new password twice<br>3. Submit | Password changed | [ ] |
| 9.2.2 | Wrong current password | 1. Enter wrong current password<br>2. Submit | Error message | [ ] |
| 9.2.3 | Passwords don't match | 1. Enter different passwords<br>2. Submit | Error message | [ ] |
### 9.3 API Keys
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.3.1 | View API keys | 1. Scroll to API Keys section | List of keys (or empty state) | [ ] |
| 9.3.2 | Create API key | 1. Click "Create Key"<br>2. Enter name<br>3. Create | Key created, full key shown once | [ ] |
| 9.3.3 | Copy API key | 1. Create key<br>2. Click copy | Key copied to clipboard | [ ] |
| 9.3.4 | Key with expiry | 1. Create key with 30-day expiry | Expiry date shown | [ ] |
| 9.3.5 | Delete API key | 1. Click delete on a key<br>2. Confirm | Key removed | [ ] |
| 9.3.6 | Key prefix shown | 1. View existing keys | Only prefix visible (e.g., `tq_abc...`) | [ ] |
### 9.4 Danger Zone
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.4.1 | Delete account prompt | 1. Click "Delete Account" | Confirmation modal with password | [ ] |
| 9.4.2 | Delete account | 1. Enter password<br>2. Confirm delete | Account deleted, logged out | [ ] |
| 9.4.3 | Wrong password on delete | 1. Enter wrong password | Error, account not deleted | [ ] |
---
## 10. Billing
### 10.1 Plan Display
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 10.1.1 | View billing page | 1. Go to `/billing` | Current plan and features shown | [ ] |
| 10.1.2 | Plan comparison | 1. View billing page | Free/Pro/Business plans compared | [ ] |
| 10.1.3 | Current plan highlighted | 1. View billing page | Current plan marked as "Current" | [ ] |
### 10.2 Stripe Integration
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 10.2.1 | Upgrade to Pro | 1. Click "Upgrade" on Pro<br>2. Complete Stripe checkout | Plan upgraded | [ ] |
| 10.2.2 | Manage subscription | 1. Click "Manage Subscription"<br>2. Stripe portal opens | Can update payment, cancel | [ ] |
| 10.2.3 | Cancel subscription | 1. Cancel in Stripe portal | Plan downgrades at period end | [ ] |
---
## 11. Plan Limits
### 11.1 Free Plan Limits
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 11.1.1 | Workspace limit | 1. Be on Free plan<br>2. Try to create 2nd workspace | Error: limit reached | [ ] |
| 11.1.2 | Link limit | 1. Create 50 links<br>2. Try to create 51st | Error: limit reached | [ ] |
| 11.1.3 | QR code limit | 1. Create 25 QR codes<br>2. Try to create 26th | Error: limit reached | [ ] |
| 11.1.4 | No custom domains | 1. Try to add domain on Free | Upgrade prompt | [ ] |
### 11.2 Usage Display
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 11.2.1 | View usage | 1. Check billing or dashboard | Usage stats shown (links, QRs, events) | [ ] |
---
## 12. UI/UX
### 12.1 Navigation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.1.1 | Sidebar navigation | 1. Click each nav item | Correct page loads | [ ] |
| 12.1.2 | Active nav highlight | 1. Navigate to different pages | Current page highlighted in sidebar | [ ] |
| 12.1.3 | Mobile responsive | 1. Resize to mobile width | Layout adapts correctly | [ ] |
### 12.2 Loading States
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.2.1 | Loading indicators | 1. Navigate to data-heavy page | Loading indicator shown while fetching | [ ] |
| 12.2.2 | Button loading states | 1. Submit a form | Button shows loading state | [ ] |
### 12.3 Error Handling
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.3.1 | API errors shown | 1. Trigger an API error | User-friendly error message | [ ] |
| 12.3.2 | Network error | 1. Disable network<br>2. Try an action | Appropriate error message | [ ] |
| 12.3.3 | 401 redirect | 1. Clear token from localStorage<br>2. Try protected action | Redirected to login | [ ] |
### 12.4 Empty States
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.4.1 | No links | 1. View links with none created | Empty state with CTA | [ ] |
| 12.4.2 | No QR codes | 1. View QR codes with none created | Empty state with CTA | [ ] |
| 12.4.3 | No projects | 1. View projects with none created | Empty state with CTA | [ ] |
| 12.4.4 | No analytics data | 1. View analytics with no events | Empty state message | [ ] |
---
## 13. Security
### 13.1 Authentication
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 13.1.1 | Protected routes | 1. Log out<br>2. Try to access `/dashboard` | Redirected to login | [ ] |
| 13.1.2 | JWT expiry | 1. Wait for token to expire<br>2. Try an action | Redirected to login | [ ] |
| 13.1.3 | Cross-workspace access | 1. Try to access another user's workspace ID | 404 or 403 error | [ ] |
### 13.2 Input Validation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 13.2.1 | XSS in link title | 1. Create link with `<script>` in title | Script not executed, text escaped | [ ] |
| 13.2.2 | SQL injection attempt | 1. Enter SQL in form fields | No SQL executed, handled safely | [ ] |
---
## Test Summary
| Section | Total Tests | Passed | Failed | Skipped |
|---------|-------------|--------|--------|---------|
| 1. Authentication | 16 | | | |
| 2. Workspaces | 7 | | | |
| 3. Projects | 5 | | | |
| 4. Short Links | 17 | | | |
| 5. Redirect | 8 | | | |
| 6. QR Codes | 17 | | | |
| 7. Analytics | 17 | | | |
| 8. Domains | 7 | | | |
| 9. Settings | 12 | | | |
| 10. Billing | 5 | | | |
| 11. Plan Limits | 5 | | | |
| 12. UI/UX | 11 | | | |
| 13. Security | 4 | | | |
| **TOTAL** | **131** | | | |
---
## Test Environment Setup
### Prerequisites
1. **Backend running**: `cd src/api && dotnet run`
2. **Frontend running**: `cd src/frontend && npm run dev`
3. **Database**: PostgreSQL with migrations applied
4. **Email**: Console output in development (check terminal)
5. **Stripe**: Test mode with test API keys (optional for billing tests)
6. **GeoIP**: MaxMind database configured (optional for geo tests)
### Test Accounts
Create these accounts before testing:
| Email | Password | Purpose |
|-------|----------|---------|
| `test@example.com` | `password123` | General testing |
| `pro@example.com` | `password123` | Pro plan testing |
| `free@example.com` | `password123` | Free limits testing |
---
## Notes
- ## Test Plan Overview
| Item | Details |
|------|---------|
| **Application** | TrakQR - QR-First URL Shortener SaaS |
| **Version** | MVP |
| **Test Type** | Functional / End-to-End |
| **Environment** | Development (`localhost:5173` + `localhost:42001`) |
- ## How to Use This Document
1. Work through each section sequentially
2. Check the box `[x]` when a test passes
3. Mark `[F]` for failures and add notes
4. Mark `[S]` for skipped tests with reason
---
- ## 1. Authentication
- ### 1.1 Registration
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.1.1 | Register with valid email | 1. Go to `/register`<br>2. Enter valid email and password (8+ chars)<br>3. Click Register | Account created, redirected to dashboard, default workspace created | [ ] |
| 1.1.2 | Register with invalid email | 1. Go to `/register`<br>2. Enter invalid email format<br>3. Click Register | Error message shown, no account created | [ ] |
| 1.1.3 | Register with short password | 1. Go to `/register`<br>2. Enter valid email, password < 8 chars<br>3. Click Register | Error message about password length | [ ] |
| 1.1.4 | Register with existing email | 1. Register a new account<br>2. Try to register again with same email | Error message about email already in use | [ ] |
| 1.1.5 | Registration rate limiting | 1. Attempt to register 15+ times in 1 minute | Rate limit error after ~10 attempts | [ ] |
- ### 1.2 Login
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.2.1 | Login with valid credentials | 1. Go to `/login`<br>2. Enter registered email/password<br>3. Click Login | Logged in, redirected to dashboard | [ ] |
| 1.2.2 | Login with wrong password | 1. Go to `/login`<br>2. Enter valid email, wrong password<br>3. Click Login | Error message, not logged in | [ ] |
| 1.2.3 | Login with non-existent email | 1. Go to `/login`<br>2. Enter unregistered email<br>3. Click Login | Error message (generic, no email enumeration) | [ ] |
| 1.2.4 | Login rate limiting | 1. Attempt failed logins 15+ times | Rate limit error after ~10 attempts | [ ] |
| 1.2.5 | Redirect after login | 1. Try to access `/links` while logged out<br>2. Get redirected to login<br>3. Login successfully | Redirected back to `/links` | [ ] |
- ### 1.3 Password Reset
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.3.1 | Request password reset | 1. Go to `/forgot-password`<br>2. Enter registered email<br>3. Click Submit | Success message shown (check console for email in dev) | [ ] |
| 1.3.2 | Reset with valid token | 1. Get reset token from email/console<br>2. Go to `/reset-password?token=xxx`<br>3. Enter new password | Password changed, can login with new password | [ ] |
| 1.3.3 | Reset with invalid token | 1. Go to `/reset-password?token=invalid`<br>2. Enter new password | Error message about invalid/expired token | [ ] |
| 1.3.4 | Reset with expired token | 1. Wait for token to expire (or modify DB)<br>2. Try to use token | Error message about expired token | [ ] |
- ### 1.4 Email Verification
| # | Test Case | Steps | Expected Result | Status |
|----------------|-------|-----------------|--------|
| 1.4.1 | Verify with valid token | 1. Register new account<br>2. Get verification token from console<br>3. Go to `/verify-email?token=xxx` | Email verified, success message | [ ] |
| 1.4.2 | Verify with invalid token | 1. Go to `/verify-email?token=invalid` | Error message about invalid token | [ ] |
| 1.4.3 | Resend verification | 1. Login with unverified account<br>2. Go to Settings<br>3. Click "Resend verification" | New email sent (check console) | [ ] |
- ### 1.5 Logout
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 1.5.1 | Logout | 1. Login<br>2. Click Logout in sidebar | Logged out, redirected to login, protected routes inaccessible | [ ] |
| 1.5.2 | Session persistence | 1. Login<br>2. Close browser<br>3. Reopen and go to app | Still logged in (token in localStorage) | [ ] |
---
- ## 2. Workspaces
- ### 2.1 Workspace Management
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 2.1.1 | Default workspace exists | 1. Register new account<br>2. Check workspace selector | Default workspace present | [ ] |
| 2.1.2 | Create workspace | 1. Click + button in workspace selector<br>2. Enter name<br>3. Click Create | New workspace created, switched to it | [ ] |
| 2.1.3 | Switch workspace | 1. Have 2+ workspaces<br>2. Select different workspace from dropdown | Workspace switched, data refreshed | [ ] |
| 2.1.4 | Update workspace name | 1. Click settings icon in workspace selector<br>2. Change name<br>3. Save | Name updated | [ ] |
| 2.1.5 | Delete workspace | 1. Have 2+ workspaces<br>2. Open workspace settings<br>3. Click Delete | Workspace deleted, switched to another | [ ] |
| 2.1.6 | Cannot delete only workspace | 1. Have only 1 workspace<br>2. Try to delete it | Delete button disabled or error shown | [ ] |
| 2.1.7 | Workspace persistence | 1. Switch to workspace B<br>2. Refresh page | Still on workspace B (localStorage) | [ ] |
---
- ## 3. Projects
- ### 3.1 Project CRUD
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 3.1.1 | View projects page | 1. Go to `/projects` | Projects list shown (or empty state) | [ ] |
| 3.1.2 | Create project | 1. Click "New Project"<br>2. Enter name and description<br>3. Save | Project created, appears in list | [ ] |
| 3.1.3 | Edit project | 1. Click edit on a project<br>2. Change name/description<br>3. Save | Project updated | [ ] |
| 3.1.4 | Delete project | 1. Click delete on a project<br>2. Confirm deletion | Project removed from list | [ ] |
| 3.1.5 | Project shows link count | 1. Create project<br>2. Create links assigned to project<br>3. View projects | Link count displayed correctly | [ ] |
---
- ## 4. Short Links
- ### 4.1 Link Creation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.1.1 | Create link with auto slug | 1. Click "Create Link"<br>2. Enter destination URL only<br>3. Save | Link created with auto-generated slug | [ ] |
| 4.1.2 | Create link with custom slug | 1. Click "Create Link"<br>2. Enter URL and custom slug<br>3. Save | Link created with custom slug | [ ] |
| 4.1.3 | Create link with title | 1. Create link with title filled in | Title shown in list | [ ] |
| 4.1.4 | Create link with expiration | 1. Create link with expiration date set | Link shows expiration, stops working after date | [ ] |
| 4.1.5 | Create link with password | 1. Create link with password set | Link requires password to access | [ ] |
| 4.1.6 | Invalid destination URL | 1. Try to create link with invalid URL | Error message shown | [ ] |
| 4.1.7 | Duplicate slug | 1. Create link with slug "test"<br>2. Try to create another with same slug | Error message about duplicate | [ ] |
- ### 4.2 Link Management
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.2.1 | View links list | 1. Go to `/links` | Links listed with short URL, destination, clicks | [ ] |
| 4.2.2 | Copy short URL | 1. Click copy icon on a link | URL copied to clipboard | [ ] |
| 4.2.3 | Edit link | 1. Click edit on a link<br>2. Change destination URL<br>3. Save | Link updated, redirect goes to new URL | [ ] |
| 4.2.4 | Delete link (soft) | 1. Click delete on a link<br>2. Confirm | Link moved to trash | [ ] |
| 4.2.5 | View trash | 1. Click "Trash" toggle | Deleted links shown | [ ] |
| 4.2.6 | Restore link | 1. View trash<br>2. Click restore on a link | Link restored, works again | [ ] |
| 4.2.7 | Disable link | 1. Edit link<br>2. Set status to Disabled<br>3. Save | Link returns 404/disabled message | [ ] |
- ### 4.3 Bulk Import
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.3.1 | Bulk import URLs | 1. Click "Bulk Import"<br>2. Paste multiple URLs (one per line)<br>3. Import | All links created | [ ] |
| 4.3.2 | Bulk import with titles | 1. Paste URLs with titles: `https://example.com, My Title`<br>2. Import | Links created with titles | [ ] |
| 4.3.3 | Bulk import with invalid URLs | 1. Include some invalid URLs in list<br>2. Import | Valid URLs imported, errors shown for invalid | [ ] |
- ### 4.4 UTM Builder
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 4.4.1 | Add UTM parameters | 1. Create link<br>2. Expand UTM builder<br>3. Fill in source, medium, campaign | UTM params appended to destination | [ ] |
| 4.4.2 | UTM presets | 1. Click "Google Ads" preset | Fields populated with Google preset values | [ ] |
| 4.4.3 | UTM preview | 1. Fill in UTM fields | Preview shows full URL with params | [ ] |
---
- ## 5. Redirect
- ### 5.1 Public Redirect
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 5.1.1 | Basic redirect | 1. Create link to `https://example.com`<br>2. Visit short URL | Redirected to example.com | [ ] |
| 5.1.2 | Non-existent slug | 1. Visit `/{random-slug}` | 404 error page | [ ] |
| 5.1.3 | Disabled link | 1. Disable a link<br>2. Visit its short URL | Error message (link disabled) | [ ] |
| 5.1.4 | Expired link | 1. Create link with past expiration<br>2. Visit short URL | Error message (link expired) | [ ] |
| 5.1.5 | Password-protected link | 1. Create password-protected link<br>2. Visit short URL | Password prompt shown | [ ] |
| 5.1.6 | Password entry | 1. Visit password-protected link<br>2. Enter correct password | Redirected to destination | [ ] |
| 5.1.7 | Wrong password | 1. Visit password-protected link<br>2. Enter wrong password | Error, stays on password page | [ ] |
| 5.1.8 | Redirect rate limiting | 1. Hit redirect endpoint 100+ times rapidly | Rate limited after threshold | [ ] |
---
- ## 6. QR Codes
- ### 6.1 QR Creation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.1.1 | Create basic QR | 1. Go to `/qrcodes/new`<br>2. Select a link<br>3. Save | QR code created with default style | [ ] |
| 6.1.2 | QR requires link | 1. Go to `/qrcodes/new`<br>2. Try to save without link | Error message | [ ] |
| 6.1.3 | QR name | 1. Create QR with custom name | Name shown in list | [ ] |
- ### 6.2 QR Designer
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.2.1 | Change foreground color | 1. Edit QR<br>2. Change foreground color<br>3. View preview | QR updates with new color | [ ] |
| 6.2.2 | Change background color | 1. Change background color | QR updates with new background | [ ] |
| 6.2.3 | Module shapes | 1. Try Square, Rounded, Dots shapes | Each shape renders correctly | [ ] |
| 6.2.4 | Eye shapes | 1. Try Square, Rounded, Circle eye shapes | Each eye shape renders correctly | [ ] |
| 6.2.5 | Error correction levels | 1. Try L, M, Q, H levels | QR generates with different densities | [ ] |
| 6.2.6 | Quiet zone | 1. Adjust quiet zone size | Padding around QR changes | [ ] |
| 6.2.7 | Style presets | 1. Click each of 6 presets | Styles applied correctly | [ ] |
| 6.2.8 | Upload logo | 1. Click logo upload<br>2. Select image file | Logo appears in center of QR | [ ] |
| 6.2.9 | Select existing logo | 1. Have uploaded assets<br>2. Select from asset gallery | Logo applied from gallery | [ ] |
| 6.2.10 | Remove logo | 1. Have QR with logo<br>2. Remove logo | QR renders without logo | [ ] |
- ### 6.3 QR Export
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.3.1 | Export PNG | 1. View QR<br>2. Click "Download PNG" | PNG file downloaded | [ ] |
| 6.3.2 | Export SVG | 1. Click "Download SVG" | SVG file downloaded | [ ] |
| 6.3.3 | PNG has correct size | 1. Export PNG<br>2. Check dimensions | Matches selected size (256/512/1024) | [ ] |
| 6.3.4 | QR is scannable | 1. Export QR<br>2. Scan with phone | Opens correct short URL | [ ] |
| 6.3.5 | QR with logo is scannable | 1. Add logo to QR<br>2. Export and scan | Still scans correctly | [ ] |
- ### 6.4 QR List
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 6.4.1 | View QR list | 1. Go to `/qrcodes` | List shows QR previews | [ ] |
| 6.4.2 | QR preview thumbnails | 1. View list | Each QR shows thumbnail preview | [ ] |
| 6.4.3 | Delete QR | 1. Click delete on QR<br>2. Confirm | QR removed from list | [ ] |
| 6.4.4 | Edit QR | 1. Click edit on QR | Opens designer with saved settings | [ ] |
---
- ## 7. Analytics
- ### 7.1 Event Tracking
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.1.1 | Click event recorded | 1. Create link<br>2. Visit short URL<br>3. Check analytics | Click count increased | [ ] |
| 7.1.2 | Scan event recorded | 1. Create QR<br>2. Export and scan QR<br>3. Check QR analytics | Scan count increased | [ ] |
| 7.1.3 | Unique visitor tracking | 1. Visit same link multiple times quickly<br>2. Check analytics | Only 1 unique visitor (dedupe) | [ ] |
| 7.1.4 | Device detection | 1. Visit from mobile device<br>2. Check device breakdown | Mobile device recorded | [ ] |
| 7.1.5 | Referrer tracking | 1. Visit link from a webpage<br>2. Check referrer breakdown | Referrer domain recorded | [ ] |
| 7.1.6 | Country detection | 1. Visit link<br>2. Check geo breakdown | Country detected (if GeoIP configured) | [ ] |
- ### 7.2 Dashboard Analytics
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.2.1 | View dashboard | 1. Go to `/dashboard` | Stats cards, chart, breakdowns shown | [ ] |
| 7.2.2 | Total clicks | 1. Check total clicks card | Matches sum of all link clicks | [ ] |
| 7.2.3 | Time series chart | 1. View activity chart | Shows clicks/scans over time | [ ] |
| 7.2.4 | Top links | 1. View top links section | Most clicked links shown | [ ] |
| 7.2.5 | Device breakdown | 1. View device breakdown | Desktop/Mobile/Tablet shown | [ ] |
| 7.2.6 | Referrer breakdown | 1. View referrer breakdown | Top referrers listed | [ ] |
| 7.2.7 | Country breakdown | 1. View geo breakdown | Countries with flags shown | [ ] |
- ### 7.3 Period Filters
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.3.1 | 24h filter | 1. Click "24h" period | Data filtered to last 24 hours | [ ] |
| 7.3.2 | 7d filter | 1. Click "7d" period | Data filtered to last 7 days | [ ] |
| 7.3.3 | 30d filter | 1. Click "30d" period | Data filtered to last 30 days | [ ] |
- ### 7.4 Per-Link Analytics
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.4.1 | View link detail | 1. Go to `/links/{id}` | Link analytics shown | [ ] |
| 7.4.2 | Link-specific stats | 1. View link detail | Stats match only that link's data | [ ] |
- ### 7.5 Per-QR Analytics
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 7.5.1 | View QR analytics | 1. Go to `/qrcodes/{id}/analytics` | QR scan stats shown | [ ] |
| 7.5.2 | QR-specific stats | 1. View QR detail | Stats match only that QR's scans | [ ] |
---
- ## 8. Domains
- ### 8.1 Domain Management
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 8.1.1 | View domains page | 1. Go to `/domains` | Domains list or upgrade prompt (Free plan) | [ ] |
| 8.1.2 | Add domain (Pro+) | 1. Click "Add Domain"<br>2. Enter hostname<br>3. Submit | Domain added with Pending status | [ ] |
| 8.1.3 | Verification instructions | 1. Add new domain | TXT record and CNAME instructions shown | [ ] |
| 8.1.4 | Copy verification token | 1. Click copy on verification token | Token copied to clipboard | [ ] |
| 8.1.5 | Verify domain | 1. Add DNS records<br>2. Click "Verify" | Domain status changes to Verified | [ ] |
| 8.1.6 | Delete domain | 1. Click delete on domain<br>2. Confirm | Domain removed | [ ] |
| 8.1.7 | Free plan restriction | 1. Be on Free plan<br>2. Try to add domain | Upgrade prompt shown | [ ] |
---
- ## 9. Settings
- ### 9.1 Profile
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.1.1 | View profile | 1. Go to `/settings` | Current email shown | [ ] |
| 9.1.2 | Update email | 1. Change email<br>2. Save | Email updated | [ ] |
| 9.1.3 | Verification warning | 1. Have unverified email | Warning shown with resend link | [ ] |
- ### 9.2 Password Change
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.2.1 | Change password | 1. Enter current password<br>2. Enter new password twice<br>3. Submit | Password changed | [ ] |
| 9.2.2 | Wrong current password | 1. Enter wrong current password<br>2. Submit | Error message | [ ] |
| 9.2.3 | Passwords don't match | 1. Enter different passwords<br>2. Submit | Error message | [ ] |
- ### 9.3 API Keys
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.3.1 | View API keys | 1. Scroll to API Keys section | List of keys (or empty state) | [ ] |
| 9.3.2 | Create API key | 1. Click "Create Key"<br>2. Enter name<br>3. Create | Key created, full key shown once | [ ] |
| 9.3.3 | Copy API key | 1. Create key<br>2. Click copy | Key copied to clipboard | [ ] |
| 9.3.4 | Key with expiry | 1. Create key with 30-day expiry | Expiry date shown | [ ] |
| 9.3.5 | Delete API key | 1. Click delete on a key<br>2. Confirm | Key removed | [ ] |
| 9.3.6 | Key prefix shown | 1. View existing keys | Only prefix visible (e.g., `tq_abc...`) | [ ] |
- ### 9.4 Danger Zone
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 9.4.1 | Delete account prompt | 1. Click "Delete Account" | Confirmation modal with password | [ ] |
| 9.4.2 | Delete account | 1. Enter password<br>2. Confirm delete | Account deleted, logged out | [ ] |
| 9.4.3 | Wrong password on delete | 1. Enter wrong password | Error, account not deleted | [ ] |
---
- ## 10. Billing
- ### 10.1 Plan Display
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 10.1.1 | View billing page | 1. Go to `/billing` | Current plan and features shown | [ ] |
| 10.1.2 | Plan comparison | 1. View billing page | Free/Pro/Business plans compared | [ ] |
| 10.1.3 | Current plan highlighted | 1. View billing page | Current plan marked as "Current" | [ ] |
- ### 10.2 Stripe Integration
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 10.2.1 | Upgrade to Pro | 1. Click "Upgrade" on Pro<br>2. Complete Stripe checkout | Plan upgraded | [ ] |
| 10.2.2 | Manage subscription | 1. Click "Manage Subscription"<br>2. Stripe portal opens | Can update payment, cancel | [ ] |
| 10.2.3 | Cancel subscription | 1. Cancel in Stripe portal | Plan downgrades at period end | [ ] |
---
- ## 11. Plan Limits
- ### 11.1 Free Plan Limits
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 11.1.1 | Workspace limit | 1. Be on Free plan<br>2. Try to create 2nd workspace | Error: limit reached | [ ] |
| 11.1.2 | Link limit | 1. Create 50 links<br>2. Try to create 51st | Error: limit reached | [ ] |
| 11.1.3 | QR code limit | 1. Create 25 QR codes<br>2. Try to create 26th | Error: limit reached | [ ] |
| 11.1.4 | No custom domains | 1. Try to add domain on Free | Upgrade prompt | [ ] |
- ### 11.2 Usage Display
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 11.2.1 | View usage | 1. Check billing or dashboard | Usage stats shown (links, QRs, events) | [ ] |
---
- ## 12. UI/UX
- ### 12.1 Navigation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.1.1 | Sidebar navigation | 1. Click each nav item | Correct page loads | [ ] |
| 12.1.2 | Active nav highlight | 1. Navigate to different pages | Current page highlighted in sidebar | [ ] |
| 12.1.3 | Mobile responsive | 1. Resize to mobile width | Layout adapts correctly | [ ] |
- ### 12.2 Loading States
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.2.1 | Loading indicators | 1. Navigate to data-heavy page | Loading indicator shown while fetching | [ ] |
| 12.2.2 | Button loading states | 1. Submit a form | Button shows loading state | [ ] |
- ### 12.3 Error Handling
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.3.1 | API errors shown | 1. Trigger an API error | User-friendly error message | [ ] |
| 12.3.2 | Network error | 1. Disable network<br>2. Try an action | Appropriate error message | [ ] |
| 12.3.3 | 401 redirect | 1. Clear token from localStorage<br>2. Try protected action | Redirected to login | [ ] |
- ### 12.4 Empty States
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 12.4.1 | No links | 1. View links with none created | Empty state with CTA | [ ] |
| 12.4.2 | No QR codes | 1. View QR codes with none created | Empty state with CTA | [ ] |
| 12.4.3 | No projects | 1. View projects with none created | Empty state with CTA | [ ] |
| 12.4.4 | No analytics data | 1. View analytics with no events | Empty state message | [ ] |
---
- ## 13. Security
- ### 13.1 Authentication
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 13.1.1 | Protected routes | 1. Log out<br>2. Try to access `/dashboard` | Redirected to login | [ ] |
| 13.1.2 | JWT expiry | 1. Wait for token to expire<br>2. Try an action | Redirected to login | [ ] |
| 13.1.3 | Cross-workspace access | 1. Try to access another user's workspace ID | 404 or 403 error | [ ] |
- ### 13.2 Input Validation
| # | Test Case | Steps | Expected Result | Status |
|---|-----------|-------|-----------------|--------|
| 13.2.1 | XSS in link title | 1. Create link with `<script>` in title | Script not executed, text escaped | [ ] |
| 13.2.2 | SQL injection attempt | 1. Enter SQL in form fields | No SQL executed, handled safely | [ ] |
---
- ## Test Summary
| Section | Total Tests | Passed | Failed | Skipped |
|---------|-------------|--------|--------|---------|
| 1. Authentication | 16 | | | |
| 2. Workspaces | 7 | | | |
| 3. Projects | 5 | | | |
| 4. Short Links | 17 | | | |
| 5. Redirect | 8 | | | |
| 6. QR Codes | 17 | | | |
| 7. Analytics | 17 | | | |
| 8. Domains | 7 | | | |
| 9. Settings | 12 | | | |
| 10. Billing | 5 | | | |
| 11. Plan Limits | 5 | | | |
| 12. UI/UX | 11 | | | |
| 13. Security | 4 | | | |
| **TOTAL** | **131** | | | |
---
- ## Test Environment Setup
- ### Prerequisites
1. **Backend running**: `cd src/api && dotnet run`
2. **Frontend running**: `cd src/frontend && npm run dev`
3. **Database**: PostgreSQL with migrations applied
4. **Email**: Console output in development (check terminal)
5. **Stripe**: Test mode with test API keys (optional for billing tests)
6. **GeoIP**: MaxMind database configured (optional for geo tests)
- ### Test Accounts
Create these accounts before testing:
| Email | Password | Purpose |
|-------|----------|---------|
| `test@example.com` | `password123` | General testing |
| `pro@example.com` | `password123` | Pro plan testing |
| `free@example.com` | `password123` | Free limits testing |
---
- ## Notes
- Mark tests as `[F]` if they fail and add details below
- Mark tests as `[S]` if skipped with reason
- Re-run failed tests after fixes
- Update this document as features change
- ### Failed Tests Log
### Failed Tests Log
| Test # | Issue | Date | Fixed |
|--------|-------|------|-------|
| | | | |
- ### Skipped Tests Log
| Test # | Issue | Date | Fixed |
|--------|-------|------|-------|
| | | | |
### Skipped Tests Log
| Test # | Reason | Date |
|--------|--------|------|
| | | |
| Test # | Reason | Date |
|--------|--------|------|
| | | |