42ff3e8f33
Build & Deploy / Test & Lint (push) Has been cancelled
Build & Deploy / Security Scan (push) Has been cancelled
Code Quality / Code Quality Checks (push) Has been cancelled
Code Quality / Dependency Vulnerabilities (push) Has been cancelled
Code Quality / Performance Testing (push) Has been cancelled
Build & Deploy / Build Docker Images (push) Has been cancelled
Build & Deploy / Deploy to Kubernetes (push) Has been cancelled
656 lines
15 KiB
Markdown
656 lines
15 KiB
Markdown
# Testing Guide - Job Info Application
|
|
|
|
## Phase 8: End-to-End Testing
|
|
|
|
This guide covers comprehensive testing of the Job Info application including OAuth2 flow, token management, error handling, and offline capabilities.
|
|
|
|
---
|
|
|
|
## 1. Environment Setup
|
|
|
|
### Prerequisites
|
|
- Bun runtime installed
|
|
- Node.js 18+ (for development)
|
|
- Two terminals ready (one for backend, one for frontend)
|
|
- Microsoft OAuth app registered (credentials in `.env`)
|
|
|
|
### Configuration Files
|
|
```
|
|
Mode3Test/.env - Backend OAuth credentials
|
|
frontend/.env.local - Frontend environment variables
|
|
```
|
|
|
|
### Start Services
|
|
|
|
**Terminal 1 - Backend (Hono + OAuth)**
|
|
```bash
|
|
cd /home/admin/Job-Info-Test/Mode3Test
|
|
bun install # if needed
|
|
bun run dev # Starts on http://localhost:3005
|
|
```
|
|
|
|
**Terminal 2 - Frontend (Vite + Svelte)**
|
|
```bash
|
|
cd /home/admin/Job-Info-Test/frontend
|
|
bun install # if needed
|
|
bun run dev # Starts on http://localhost:5173
|
|
```
|
|
|
|
---
|
|
|
|
## 2. OAuth2 Flow Testing
|
|
|
|
### Test 2.1: Sign In Flow
|
|
|
|
**Objective**: Verify complete OAuth2 PKCE flow with Microsoft
|
|
|
|
**Steps**:
|
|
1. Navigate to http://localhost:5173/#/signin
|
|
2. Click "Sign In with Microsoft"
|
|
3. Verify redirect to Microsoft login
|
|
4. Enter Microsoft credentials
|
|
5. Grant permissions on consent screen
|
|
6. Verify redirect back to http://localhost:5173/#/callback
|
|
7. Verify redirect to http://localhost:5173/#/ (home)
|
|
|
|
**Expected Results**:
|
|
- ✅ User profile displayed in navigation (name, avatar)
|
|
- ✅ Jobs list loaded and displayed
|
|
- ✅ No console errors
|
|
- ✅ Access token stored in sessionStorage
|
|
- ✅ User profile stored in IndexedDB
|
|
|
|
**Validation Commands** (in browser console):
|
|
```javascript
|
|
// Check sessionStorage
|
|
sessionStorage.getItem('access_token'); // Should return token string
|
|
|
|
// Check IndexedDB
|
|
const db = await window.openDatabase();
|
|
const user = await db.getFromStore('userProfile');
|
|
console.log(user); // Should show user data
|
|
|
|
// Check store values
|
|
window.store?.subscribe(v => console.log('Auth:', v));
|
|
```
|
|
|
|
---
|
|
|
|
### Test 2.2: PKCE Code Verification
|
|
|
|
**Objective**: Verify PKCE security flow
|
|
|
|
**Tools**: Browser DevTools Network tab
|
|
|
|
**Steps**:
|
|
1. Open DevTools → Network tab
|
|
2. Click "Sign In with Microsoft"
|
|
3. Check the request to `/api/auth/authorize`
|
|
4. Verify request body contains:
|
|
- `code` - Authorization code from Microsoft
|
|
- `code_verifier` - PKCE code verifier
|
|
- `state` - CSRF token (should match state from redirect)
|
|
|
|
**Expected Results**:
|
|
- ✅ Request uses POST method
|
|
- ✅ Request includes CORS headers
|
|
- ✅ Response contains `access_token`, `expires_in`, `user`
|
|
- ✅ Status code 200 OK
|
|
|
|
---
|
|
|
|
## 3. Token Management Testing
|
|
|
|
### Test 3.1: Token Storage Security
|
|
|
|
**Objective**: Verify tokens stored securely
|
|
|
|
**Steps**:
|
|
1. After sign in, check browser storage:
|
|
- Open DevTools → Application → Cookies
|
|
- Open DevTools → Application → Local Storage
|
|
- Open DevTools → Application → Session Storage
|
|
|
|
**Expected Results**:
|
|
- ✅ `access_token` in sessionStorage (NOT localStorage)
|
|
- ✅ No tokens in cookies
|
|
- ✅ No tokens in localStorage
|
|
- ✅ Token expires in ~1 hour (check `token_expiry`)
|
|
|
|
**Why This Matters**:
|
|
- SessionStorage lost on browser close (prevents token theft)
|
|
- Can't be accessed by XSS attacks in other tabs
|
|
- Service Worker has separate access for refresh
|
|
|
|
---
|
|
|
|
### Test 3.2: Token Refresh
|
|
|
|
**Objective**: Verify Service Worker automatically refreshes token
|
|
|
|
**Steps**:
|
|
1. Sign in successfully
|
|
2. Wait 55+ seconds (Service Worker polls every 60 seconds)
|
|
3. Check DevTools → Application → Service Workers
|
|
4. Verify Service Worker status shows "activated"
|
|
5. Monitor Console for refresh logs
|
|
|
|
**Expected Results**:
|
|
- ✅ Service Worker shows "activated and running"
|
|
- ✅ No manual action needed
|
|
- ✅ Can continue using app without re-login
|
|
- ✅ Token refreshes 5 minutes before expiry
|
|
|
|
**Debug Commands**:
|
|
```javascript
|
|
// Check Service Worker registration
|
|
navigator.serviceWorker.getRegistrations().then(regs => {
|
|
regs.forEach(reg => console.log('SW:', reg.scope, reg.active?.state));
|
|
});
|
|
|
|
// Send refresh command to Service Worker
|
|
if (navigator.serviceWorker.controller) {
|
|
navigator.serviceWorker.controller.postMessage({
|
|
type: 'REFRESH_TOKEN'
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. API Error Handling Testing
|
|
|
|
### Test 4.1: Network Error Handling
|
|
|
|
**Objective**: Verify graceful handling of network failures
|
|
|
|
**Steps**:
|
|
1. Sign in successfully
|
|
2. Open DevTools → Network tab
|
|
3. Check "Offline" checkbox (simulates no network)
|
|
4. Try to perform action (search, load jobs)
|
|
5. Verify error message displayed
|
|
6. Uncheck "Offline"
|
|
7. Verify app recovers automatically
|
|
|
|
**Expected Results**:
|
|
- ✅ Error message shown: "Network error - please check your connection"
|
|
- ✅ Retry button appears
|
|
- ✅ App recovers when network restored
|
|
- ✅ No unhandled exceptions in console
|
|
- ✅ Error logged to structured logger
|
|
|
|
---
|
|
|
|
### Test 4.2: API Error Responses
|
|
|
|
**Objective**: Verify handling of HTTP error responses
|
|
|
|
**Steps**:
|
|
1. Use DevTools → Network → Throttle to simulate slow network
|
|
2. Open DevTools → Network → Response headers
|
|
3. Modify response (requires proxy like Charles/Fiddler):
|
|
- Change 200 to 401 (Unauthorized)
|
|
- Change 200 to 403 (Forbidden)
|
|
- Change 200 to 500 (Server Error)
|
|
|
|
**Expected Results** (per error type):
|
|
|
|
**401 Unauthorized**:
|
|
- ✅ "Session expired" message shown
|
|
- ✅ Redirect to sign in page
|
|
- ✅ Error logged with context
|
|
|
|
**403 Forbidden**:
|
|
- ✅ "You don't have permission" message shown
|
|
- ✅ Retry option disabled
|
|
- ✅ Contact admin message shown
|
|
|
|
**500 Server Error**:
|
|
- ✅ "Server error" message shown
|
|
- ✅ Retry button enabled
|
|
- ✅ Auto-retry happens 2-3 times
|
|
|
|
---
|
|
|
|
### Test 4.3: Request Timeout
|
|
|
|
**Objective**: Verify timeout handling
|
|
|
|
**Steps**:
|
|
1. Use DevTools → Network → Throttle to "Slow 3G"
|
|
2. Trigger API call (load jobs)
|
|
3. Wait for 30+ seconds
|
|
|
|
**Expected Results**:
|
|
- ✅ Request times out after 30 seconds
|
|
- ✅ Error message: "Request timeout - please try again"
|
|
- ✅ Retry automatically attempted
|
|
- ✅ No hung requests in Network tab
|
|
|
|
---
|
|
|
|
## 5. Data Storage Testing
|
|
|
|
### Test 5.1: IndexedDB Jobs Cache
|
|
|
|
**Objective**: Verify jobs cached locally
|
|
|
|
**Steps**:
|
|
1. Sign in and load jobs
|
|
2. Open DevTools → Application → IndexedDB → job-info-db
|
|
3. Check `jobs` object store
|
|
4. Sign out
|
|
5. Go back to sign in page
|
|
6. Turn off network ("Offline" in DevTools)
|
|
7. Sign in again (offline)
|
|
8. Check if previous jobs available
|
|
|
|
**Expected Results**:
|
|
- ✅ Jobs loaded from IndexedDB when offline
|
|
- ✅ Jobs display without network
|
|
- ✅ Database shows ~50-100 jobs
|
|
- ✅ Each job has: id, title, description, location, salary
|
|
|
|
---
|
|
|
|
### Test 5.2: Cache Invalidation
|
|
|
|
**Objective**: Verify old data cleaned up
|
|
|
|
**Steps**:
|
|
1. Sign in and load jobs
|
|
2. Note timestamp in IndexedDB
|
|
3. Wait 1 hour (or modify cache expiry in constants)
|
|
4. Refresh page
|
|
5. Check if cache refreshed from API
|
|
|
|
**Expected Results**:
|
|
- ✅ Fresh jobs fetched from API
|
|
- ✅ Cache timestamp updated
|
|
- ✅ Stale data not used
|
|
- ✅ No cache inconsistencies
|
|
|
|
---
|
|
|
|
## 6. UI Component Testing
|
|
|
|
### Test 6.1: Responsive Design
|
|
|
|
**Objectives**: Verify layout works on all screen sizes
|
|
|
|
**Steps**:
|
|
1. Open DevTools → Responsive Design Mode
|
|
2. Test on:
|
|
- Mobile (375px - iPhone SE)
|
|
- Tablet (768px - iPad)
|
|
- Desktop (1920px - 4K)
|
|
3. Verify:
|
|
- Navigation stays accessible
|
|
- Job list responsive
|
|
- Search bar functional
|
|
- No horizontal scroll
|
|
|
|
**Expected Results**:
|
|
- ✅ All sizes readable and usable
|
|
- ✅ TailwindCSS classes applied correctly
|
|
- ✅ Touch targets ≥ 44x44 pixels on mobile
|
|
- ✅ No overflow or layout shifts
|
|
|
|
---
|
|
|
|
### Test 6.2: Error Boundary Display
|
|
|
|
**Objective**: Verify error UI works
|
|
|
|
**Steps**:
|
|
1. Sign in
|
|
2. Open DevTools → Console
|
|
3. Manually throw error in component:
|
|
```javascript
|
|
throw new Error('Test error for ErrorBoundary');
|
|
```
|
|
4. Verify error displayed gracefully
|
|
|
|
**Expected Results**:
|
|
- ✅ Error Boundary component displays
|
|
- ✅ User-friendly message shown
|
|
- ✅ Development details (stack) available
|
|
- ✅ Recovery suggestions shown
|
|
- ✅ Retry button works
|
|
|
|
---
|
|
|
|
## 7. Logging & Debugging
|
|
|
|
### Test 7.1: Structured Logging
|
|
|
|
**Objective**: Verify comprehensive logging
|
|
|
|
**Steps**:
|
|
1. Sign in
|
|
2. Load jobs
|
|
3. Perform search
|
|
4. Open DevTools → Console
|
|
5. Check for log messages with format:
|
|
```
|
|
[module] message {context}
|
|
```
|
|
|
|
**Expected Log Entries**:
|
|
- `[OAuth] Token refreshed successfully`
|
|
- `[API] GET /api/graph/me - 200`
|
|
- `[Jobs] Loaded X jobs from cache`
|
|
- `[Search] Searching for: term`
|
|
|
|
---
|
|
|
|
### Test 7.2: Log Export
|
|
|
|
**Objective**: Verify log export for debugging
|
|
|
|
**Steps**:
|
|
1. Sign in and perform actions
|
|
2. In Console, run:
|
|
```javascript
|
|
window.logger.exportLogs();
|
|
```
|
|
3. Check Downloads folder
|
|
4. Verify JSON file contains:
|
|
- Timestamps
|
|
- Log levels
|
|
- Module names
|
|
- Context data
|
|
|
|
**Expected Results**:
|
|
- ✅ JSON file downloads
|
|
- ✅ Contains 100+ log entries
|
|
- ✅ Properly formatted
|
|
- ✅ Includes error context
|
|
|
|
---
|
|
|
|
## 8. Performance Testing
|
|
|
|
### Test 8.1: Build Size
|
|
|
|
**Objective**: Verify production build is optimized
|
|
|
|
**Command**:
|
|
```bash
|
|
cd /home/admin/Job-Info-Test/frontend
|
|
bun run build
|
|
```
|
|
|
|
**Expected Results**:
|
|
- ✅ Total JS: < 50 kB (gzip)
|
|
- ✅ CSS: < 5 kB (gzip)
|
|
- ✅ HTML: < 1 kB
|
|
- ✅ Build time: < 5 seconds
|
|
|
|
**Current Metrics**:
|
|
```
|
|
JS: 42.56 kB (gzip)
|
|
CSS: 3.96 kB (gzip)
|
|
HTML: 0.32 kB
|
|
Build: 2.68s
|
|
Modules: 51
|
|
```
|
|
|
|
---
|
|
|
|
### Test 8.2: Load Time
|
|
|
|
**Objective**: Verify fast initial load
|
|
|
|
**Steps**:
|
|
1. Clear browser cache
|
|
2. Open DevTools → Network tab
|
|
3. Navigate to http://localhost:5173
|
|
4. Check timing breakdown:
|
|
- Time to First Byte (TTFB)
|
|
- First Contentful Paint (FCP)
|
|
- Largest Contentful Paint (LCP)
|
|
|
|
**Expected Results**:
|
|
- ✅ TTFB: < 100ms
|
|
- ✅ FCP: < 1s
|
|
- ✅ LCP: < 2.5s (Core Web Vitals target)
|
|
- ✅ Total load: < 3s
|
|
|
|
---
|
|
|
|
## 9. Security Testing
|
|
|
|
### Test 9.1: XSS Protection
|
|
|
|
**Objective**: Verify no XSS vulnerabilities
|
|
|
|
**Steps**:
|
|
1. Try to inject script in search:
|
|
```
|
|
<script>alert('XSS')</script>
|
|
```
|
|
2. Check if alert fires (it shouldn't)
|
|
3. Check rendered HTML
|
|
4. Verify script treated as text
|
|
|
|
**Expected Results**:
|
|
- ✅ No alert shown
|
|
- ✅ Input rendered as plain text
|
|
- ✅ Script tags escaped
|
|
- ✅ Content Security Policy working
|
|
|
|
---
|
|
|
|
### Test 9.2: CSRF Protection
|
|
|
|
**Objective**: Verify CSRF token handling
|
|
|
|
**Steps**:
|
|
1. In Network tab, check requests to backend
|
|
2. Verify state parameter in OAuth flow
|
|
3. Check CORS headers are set correctly
|
|
4. Try to call API from different origin (if possible)
|
|
|
|
**Expected Results**:
|
|
- ✅ State token matches request/response
|
|
- ✅ CORS prevents cross-origin requests
|
|
- ✅ SameSite cookie policy enforced
|
|
- ✅ No state token reuse
|
|
|
|
---
|
|
|
|
## 10. Accessibility Testing
|
|
|
|
### Test 10.1: Keyboard Navigation
|
|
|
|
**Steps**:
|
|
1. Sign in to app
|
|
2. Press Tab repeatedly
|
|
3. Navigate through:
|
|
- Navigation menu
|
|
- Search input
|
|
- Job list items
|
|
- Buttons
|
|
4. Verify focus visible on all elements
|
|
5. Press Enter on buttons to activate
|
|
6. Verify Esc closes modals
|
|
|
|
**Expected Results**:
|
|
- ✅ All interactive elements reachable via keyboard
|
|
- ✅ Focus indicator clearly visible
|
|
- ✅ Tab order logical
|
|
- ✅ Enter activates buttons
|
|
- ✅ Esc closes overlays
|
|
|
|
---
|
|
|
|
### Test 10.2: Screen Reader
|
|
|
|
**Steps**:
|
|
1. Enable screen reader:
|
|
- macOS: Cmd+F5 (VoiceOver)
|
|
- Windows: Windows+Enter (Narrator)
|
|
- Linux: NVDA (free)
|
|
2. Navigate through app
|
|
3. Check that:
|
|
- Page title announced
|
|
- Headings identified
|
|
- Links have labels
|
|
- Form inputs have labels
|
|
- Errors announced
|
|
|
|
**Expected Results**:
|
|
- ✅ Navigation menu announced correctly
|
|
- ✅ Page sections identified
|
|
- ✅ Buttons have accessible labels
|
|
- ✅ Form inputs labeled
|
|
- ✅ Errors announced to screen reader
|
|
|
|
---
|
|
|
|
## 11. Regression Testing Checklist
|
|
|
|
Use this checklist before each release:
|
|
|
|
### Authentication
|
|
- [ ] Sign in flow completes successfully
|
|
- [ ] Token stored securely in sessionStorage
|
|
- [ ] User profile displayed in navigation
|
|
- [ ] Sign out clears auth state
|
|
- [ ] Protected pages redirect to sign in when logged out
|
|
|
|
### Data Loading
|
|
- [ ] Jobs list loads on home page
|
|
- [ ] Search filters jobs correctly
|
|
- [ ] Pagination works (if implemented)
|
|
- [ ] Job details display when clicked
|
|
- [ ] Loading state shows spinner
|
|
|
|
### Error Handling
|
|
- [ ] Network errors show user message
|
|
- [ ] API errors handled gracefully
|
|
- [ ] No unhandled exceptions in console
|
|
- [ ] Error recovery buttons work
|
|
- [ ] Errors logged with context
|
|
|
|
### Token Refresh
|
|
- [ ] Service Worker registers successfully
|
|
- [ ] Token refreshes before expiry
|
|
- [ ] App continues working after refresh
|
|
- [ ] No authentication prompts during normal use
|
|
|
|
### UI/UX
|
|
- [ ] Navigation responsive on all sizes
|
|
- [ ] Colors have sufficient contrast
|
|
- [ ] Font sizes readable on mobile
|
|
- [ ] Buttons easily tappable (44x44px min)
|
|
- [ ] Forms accessible via keyboard
|
|
|
|
### Performance
|
|
- [ ] Build size within limits
|
|
- [ ] No console errors or warnings
|
|
- [ ] Page loads in < 3 seconds
|
|
- [ ] Interactions respond immediately
|
|
- [ ] No memory leaks (check DevTools)
|
|
|
|
---
|
|
|
|
## 12. Known Limitations & Workarounds
|
|
|
|
### Issue 1: Token Expiry During Long Session
|
|
**Symptom**: Suddenly get 401 errors after 1 hour
|
|
**Cause**: Token expires, Service Worker refresh fails
|
|
**Workaround**: Service Worker auto-refreshes at 55 min mark (before 1hr expiry)
|
|
**Fix**: Already implemented in Service Worker
|
|
|
|
### Issue 2: IndexedDB Not Available
|
|
**Symptom**: Jobs don't persist offline
|
|
**Cause**: Incognito/Private mode disables IndexedDB
|
|
**Workaround**: Use normal browser mode
|
|
**Fix**: Graceful fallback to in-memory cache (already implemented)
|
|
|
|
### Issue 3: CORS Errors
|
|
**Symptom**: "CORS policy: No 'Access-Control-Allow-Origin'"
|
|
**Cause**: API doesn't allow requests from localhost:5173
|
|
**Fix**: Ensure vite.config.ts has correct proxy:
|
|
```typescript
|
|
proxy: {
|
|
'/api': 'http://localhost:3005'
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Testing Automation
|
|
|
|
### Unit Test Example (Optional - Future)
|
|
```typescript
|
|
import { describe, it, expect } from 'bun:test';
|
|
import { classifyError } from '../services/errorHandler';
|
|
|
|
describe('errorHandler', () => {
|
|
it('should classify network error', () => {
|
|
const error = new Error('Network error');
|
|
const classified = classifyError(error);
|
|
expect(classified.type).toBe('network');
|
|
});
|
|
|
|
it('should classify auth error', () => {
|
|
const error = new Error('401 Unauthorized');
|
|
const classified = classifyError(error);
|
|
expect(classified.type).toBe('auth');
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 14. Test Results Template
|
|
|
|
**Date**: ___________
|
|
**Tester**: ___________
|
|
**Environment**:
|
|
- Browser: ___________
|
|
- OS: ___________
|
|
- Build: ___________
|
|
|
|
**Test Results**:
|
|
- [ ] OAuth2 Flow: PASS / FAIL
|
|
- [ ] Token Management: PASS / FAIL
|
|
- [ ] Error Handling: PASS / FAIL
|
|
- [ ] Data Storage: PASS / FAIL
|
|
- [ ] UI Components: PASS / FAIL
|
|
- [ ] Performance: PASS / FAIL
|
|
- [ ] Accessibility: PASS / FAIL
|
|
|
|
**Issues Found**:
|
|
1. ___________
|
|
2. ___________
|
|
3. ___________
|
|
|
|
**Notes**:
|
|
___________________________________________
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
This testing guide ensures comprehensive validation of:
|
|
✅ OAuth2 security flow
|
|
✅ Token management and refresh
|
|
✅ Error handling and recovery
|
|
✅ Data persistence
|
|
✅ UI/UX across devices
|
|
✅ Performance benchmarks
|
|
✅ Accessibility compliance
|
|
✅ Security best practices
|
|
|
|
**Next Steps**:
|
|
1. Execute tests in order (sections 2-7)
|
|
2. Document any failures
|
|
3. Fix issues using logger insights
|
|
4. Re-run failed tests
|
|
5. Move to deployment when all pass
|