Testing Scenarios
Comprehensive test cases and edge cases for the Trial Experience feature.
Functional Test Cases
Trial Start
| Test Case | Steps | Expected Result |
|---|---|---|
| Start new trial | Visit /trial, click “Start Trial” | Anonymous session created, timer starts at 30:00 |
| Resume existing trial | Return to /trial with active session | Session resumes with remaining time |
| Permanent user redirect | Logged-in user visits /trial | Redirected to /dashboard |
| Multiple browser tabs | Open /trial in two tabs | Same session ID in both tabs |
Timer Behavior
| Test Case | Steps | Expected Result |
|---|---|---|
| Timer countdown | Wait and observe | Timer decrements every second |
| 15-minute warning | Let timer reach 15:00 | Timer bar shows subtle pulse |
| 5-minute warning | Let timer reach 5:00 | Timer bar turns amber |
| 1-minute warning | Let timer reach 1:00 | Timer bar turns red with pulse |
| Timer expires | Let timer reach 0:00 | Modal appears: “Time’s up! Save your progress” |
| Page refresh | Refresh during active trial | Timer shows correct remaining time from server |
AI Conversation Trial
| Test Case | Steps | Expected Result |
|---|---|---|
| Start conversation | Choose AI mode, send message | Elena responds, message saved with trial_session_id |
| Multiple messages | Send 10+ messages | Conversation count increments, quality score improves |
| Long message | Send 500+ word message | Processes successfully, quality score reflects detail |
| Empty message | Try to send empty message | Button disabled or error message |
| Conversation save | Check database after conversation | All messages have is_trial=true |
Voice Recording Trial
| Test Case | Steps | Expected Result |
|---|---|---|
| Start recording | Choose Voice mode, click record | Recording starts, timer visible |
| 10-minute recording | Record for 10+ minutes | Quality indicator shows “story ready” |
| Stop and resume | Stop recording, start new one | Both recordings saved with trial_session_id |
| Audio quality | Record with background noise | System handles gracefully (no crash) |
| Browser permissions | Deny mic access | Helpful error message with retry option |
Content Validation
| Test Case | Steps | Expected Result |
|---|---|---|
| Valid voice content | 10+ min recording, click “I’m Done” | Validation passes, signup modal appears |
| Valid AI content | 10+ detailed exchanges, click “I’m Done” | Validation passes, signup modal appears |
| Insufficient voice | 2 min recording, click “I’m Done” | Validation fails with suggestions |
| Insufficient AI | 3 short messages, click “I’m Done” | Validation fails with suggestions |
| Empty trial | No content, click “I’m Done" | "Add some content first” message |
Account Upgrade
| Test Case | Steps | Expected Result |
|---|---|---|
| Email signup | Enter email/password in modal | Account created, trial data linked |
| Google OAuth | Click “Continue with Google” | OAuth flow, account linked, trial data preserved |
| Apple OAuth | Click “Continue with Apple” | OAuth flow, account linked, trial data preserved |
| Existing account login | Choose “Already have account?” | Login modal, trial data merged |
Story Generation
| Test Case | Steps | Expected Result |
|---|---|---|
| Async generation | Complete signup after trial | Story generation starts in background |
| Status polling | Observe during onboarding | Status updates from “processing” to “complete” |
| Generation success | Wait for completion | Story record created with correct content |
| Post-payment redirect | Complete payment after story ready | Redirected to /stories/[id]/edit |
| Payment before ready | Complete payment while processing | Loading screen until story ready, then redirect |
Edge Cases
Session Management
| Edge Case | Steps | Expected Result |
|---|---|---|
| Expired session retry | Try to interact after expiry | ”Session expired” message, option to start new |
| Browser cleared | Clear cookies mid-trial | Session lost, must start new trial |
| Multiple devices | Start trial on phone, continue on desktop | Separate sessions (expected behavior) |
| Long inactive period | Leave page for 25 min, return | Timer reflects elapsed time (may be expired) |
Content Edge Cases
| Edge Case | Steps | Expected Result |
|---|---|---|
| Very long recording | Record for 30 minutes (full session) | Handles large file, content saved |
| Very short recording | Record 10 seconds only | Saved but validation will fail |
| Non-English content | Speak in Spanish/French | Transcription attempts language detection |
| Mixed content | Do both AI and voice in same session | Both saved, validation uses higher quality content |
| Audio upload (if allowed) | Upload existing audio file | Process like recording |
Error Handling
| Edge Case | Steps | Expected Result |
|---|---|---|
| Network loss during recording | Disconnect wifi while recording | Recording continues locally, saves when reconnected |
| Network loss during save | Disconnect during “Save” | Retry logic, error message if persistent |
| AI API failure | OpenAI returns error | Friendly error, retry option |
| Database error | Supabase unavailable | ”Technical difficulties” message |
| Transcription failure | Audio too noisy for transcription | Fallback message, manual review option |
Concurrency
| Edge Case | Steps | Expected Result |
|---|---|---|
| Rapid message sending | Send 10 messages in 2 seconds | All processed in order, no duplicates |
| Multiple save attempts | Click “Save” button multiple times | Debounced, only one validation triggered |
| Simultaneous signup | Complete signup form twice | First succeeds, second handles gracefully |
Performance Tests
Load Testing
| Test | Target | Measurement |
|---|---|---|
| Concurrent trials | 100 simultaneous sessions | Response time < 500ms |
| Trial start latency | Cold start | < 2 seconds |
| Status check latency | Active session | < 200ms |
| Validation latency | Content validation API | < 5 seconds |
| Story generation time | Full story generation | < 30 seconds |
Resource Usage
| Test | Metric | Acceptable Range |
|---|---|---|
| Database connections | Per 100 users | < 50 connections |
| Memory usage | Per trial session | < 10MB |
| Storage per trial | Audio + conversation | < 50MB |
| AI token usage | Per validation | < 3,000 tokens |
| AI token usage | Per story generation | < 10,000 tokens |
Security Tests
Authentication
| Test | Steps | Expected Result |
|---|---|---|
| Anonymous user isolation | Two users start trials | Cannot see each other’s data |
| Session hijacking attempt | Copy session ID to different browser | Auth required, blocked |
| Token refresh | Session active beyond token expiry | Token refreshes automatically |
Data Access
| Test | Steps | Expected Result |
|---|---|---|
| RLS enforcement | Query trial_sessions as different user | Only own session returned |
| API authorization | Call /api/trial/status without auth | 401 Unauthorized |
| Trial data after conversion | Check is_trial flag post-conversion | Set to false |
Input Validation
| Test | Steps | Expected Result |
|---|---|---|
| XSS in conversation | Send message with script tag | Sanitized before storage and display |
| SQL injection attempt | Malicious session ID | Rejected at validation |
| Large payload | Send 10MB of text | Rejected with size limit error |
Integration Tests
End-to-End Flows
describe('Trial to Conversion Flow', () => {
it('completes full trial to story journey', async () => {
// 1. Start trial
const { sessionId } = await startTrial()
expect(sessionId).toBeDefined()
// 2. Create conversation content
await sendMessages(sessionId, 10)
// 3. Validate content
const validation = await validateContent(sessionId)
expect(validation.isValid).toBe(true)
// 4. Sign up
const user = await signUp({ email: 'test@example.com', password: 'test123' })
expect(user.is_anonymous).toBe(false)
// 5. Check trial conversion
const session = await getTrialSession(sessionId)
expect(session.status).toBe('converted')
// 6. Wait for story generation
await waitForStoryGeneration(sessionId)
// 7. Verify story created
const story = await getStoryForSession(sessionId)
expect(story).toBeDefined()
expect(story.content).toContain('story content')
})
})Component Integration
describe('TrialTimerBar Integration', () => {
it('updates when context changes', async () => {
render(
<TrialProvider>
<TrialTimerBar />
</TrialProvider>
)
// Start trial
await userEvent.click(screen.getByText('Start Trial'))
// Verify timer appears
expect(screen.getByText('30:00')).toBeInTheDocument()
// Wait and verify countdown
await waitFor(() => {
expect(screen.getByText('29:59')).toBeInTheDocument()
})
})
})Monitoring Checklist
After deployment, monitor:
- Trial start success rate
- Average trial duration before conversion
- Content validation pass/fail ratio
- Story generation success rate
- AI API error rates
- Time to story generation completion
- Conversion rate (trial → signup → payment)
Rollback Plan
If issues arise:
- Feature flag: Disable trial routes in middleware
- Marketing CTA: Remove trial links from marketing site
- Database: Trial data remains, no cleanup needed
- Monitoring: Alert on conversion rate drop
Test Environment Setup
# Set up test environment
cp .env.example .env.test
# Required test env vars
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
SUPABASE_SERVICE_ROLE_KEY=test-key
OPENAI_API_KEY=test-key
# Run tests
npm run test:e2e -- --grep "trial"