Testing Guide
This guide covers testing OneLibro locally before deployment, including Plaid sandbox testing, email testing, subdomain routing, and end-to-end user workflows.
Overview
OneLibro testing includes:
- Local Development Testing - Running and testing the app locally
- Subdomain Testing - Testing finance and admin subdomains on localhost
- Plaid Sandbox Testing - Testing bank connections without real accounts
- Email Testing - Testing email templates and delivery
- End-to-End Testing - Complete user workflow validation
- Database Testing - Verifying data integrity and RLS policies
Local Development Setup
Step 1: Install Dependencies
# Clone repository
git clone https://github.com/yourusername/yatheesh-portfolio.git
cd yatheesh-portfolio
# Install dependencies
npm install
# Or with clean install
npm ci
Step 2: Configure Environment Variables
Create .env.local file in project root:
# Supabase (use your development project)
NEXT_PUBLIC_SUPABASE_URL=https://[your-project].supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...
# Plaid (IMPORTANT: Use sandbox for local testing)
PLAID_CLIENT_ID=your_client_id
PLAID_SECRET=your_sandbox_secret
PLAID_ENV=sandbox
# Encryption (generate with: openssl rand -hex 32)
ENCRYPTION_KEY=your_64_char_hex_string
# Email (Resend - use test mode)
RESEND_API_KEY=re_...
RESEND_FROM_EMAIL=onboarding@resend.dev
RESEND_FROM_NAME=OneLibro
# Cron (for local testing)
CRON_SECRET=local_test_secret
# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
NODE_ENV=development
CRITICAL: Always use PLAID_ENV=sandbox for local development!
Step 3: Start Development Server
# Start Next.js development server with Turbopack
npm run dev
Output:
▲ Next.js 15.0.0 (turbo)
- Local: http://localhost:3000
- Environments: .env.local
✓ Ready in 2.1s
Access Applications:
- Portfolio: http://localhost:3000
- Finance App: http://finance.localhost:3000
- Admin Dashboard: http://admin.localhost:3000
Testing Subdomain Routing Locally
OneLibro uses subdomain routing to serve different apps from one codebase.
How Subdomain Routing Works Locally
Middleware (middleware.ts) rewrites subdomain requests:
// finance.localhost:3000 → /finance route
if (hostname.startsWith('finance.')) {
url.pathname = `/finance${url.pathname}`;
return NextResponse.rewrite(url);
}
// admin.localhost:3000 → /admin route
if (hostname.startsWith('admin.')) {
url.pathname = `/admin${url.pathname}`;
return NextResponse.rewrite(url);
}
Testing Subdomains
Test Finance Subdomain:
- Navigate to:
http://finance.localhost:3000 - Should show finance app login page
- URL should remain
finance.localhost:3000(not redirect to/finance) - Clicking links should stay on
finance.localhost:3000
Test Admin Subdomain:
- Navigate to:
http://admin.localhost:3000 - Should show admin login page
- URL should remain
admin.localhost:3000 - Test admin TOTP 2FA flow
Test Main Portfolio:
- Navigate to:
http://localhost:3000 - Should show portfolio homepage
- Should NOT redirect to finance or admin
Troubleshooting Subdomain Routing
Issue: finance.localhost:3000 shows 404 or portfolio instead of finance app
Solution 1: Check Browser Compatibility
- Chrome/Edge: Works by default
- Firefox: May need
network.dns.localDomainsconfiguration - Safari: Works by default
Solution 2: Use Hosts File (if subdomain.localhost doesn't work):
Windows (C:\Windows\System32\drivers\etc\hosts):
127.0.0.1 finance.local
127.0.0.1 admin.local
Mac/Linux (/etc/hosts):
127.0.0.1 finance.local
127.0.0.1 admin.local
Then access:
http://finance.local:3000http://admin.local:3000
Solution 3: Test with URL Rewrites:
If subdomains don't work, test routes directly:
- Finance: http://localhost:3000/finance
- Admin: http://localhost:3000/admin
Plaid Sandbox Testing
The Plaid sandbox environment allows testing without real bank accounts.
Sandbox vs Real Environments
| Feature | Sandbox | Development | Production |
|---|---|---|---|
| Cost | Free | Free (100 items) | Paid |
| Real Banks | No (test mode) | Yes | Yes |
| Real Credentials | No | Yes | Yes |
| Transaction Data | Fake | Real | Real |
| Rate Limits | None | Limited | Limited |
| Use Case | Local testing | Pre-launch testing | Live app |
Always use sandbox for local development.
Sandbox Test Credentials
Plaid provides test credentials for different scenarios:
Successful Connection (most common):
Username: user_good
Password: pass_good
Failed Connection (invalid credentials):
Username: user_bad
Password: pass_bad
MFA Required (multi-factor auth flow):
Username: user_good
Password: pass_good
MFA Code: 1234 (any 4 digits works)
Locked Account (account temporarily locked):
Username: user_account_locked
Password: pass_good
Additional Verification (requires extra step):
Username: user_custom
Password: pass_good
Testing Bank Connection Flow
Step-by-Step:
-
Start Plaid Link:
- Navigate to
http://finance.localhost:3000 - Click "Connect Bank Account"
- Plaid Link modal opens
- Navigate to
-
Search for Test Bank:
- In search bar, type:
"Platypus" - Select "First Platypus Bank" (Plaid's test institution)
- Or search "Chase" for real bank simulation
- In search bar, type:
-
Enter Test Credentials:
- Username:
user_good - Password:
pass_good - Click "Submit"
- Username:
-
Select Accounts:
- Sandbox returns fake accounts (checking, savings, credit)
- Select accounts to connect
- Click "Continue"
-
Grant Permissions:
- Review requested permissions
- Click "Allow" or "Continue"
-
Verify Success:
- Plaid Link closes
- Accounts appear in OneLibro dashboard
- Check browser console for any errors
Testing Transaction Sync
After connecting a sandbox account:
Initial Sync:
// Plaid sandbox returns fake transactions automatically
// Check database: transactions table should populate
Manual Sync:
- Go to Accounts page:
http://finance.localhost:3000/accounts - Find connected account
- Click "Sync" button
- Wait for spinner
- Check for success toast: "Synced! Added: X, Modified: Y"
Verify in Database:
-- Check transactions table in Supabase
SELECT * FROM transactions
WHERE account_id = 'your_account_id'
ORDER BY transaction_date DESC
LIMIT 10;
Sandbox Helper Functions
OneLibro includes sandbox testing helpers in lib/plaid.ts:
Reset Login Flow (simulate expired credentials):
import { sandboxResetLogin } from '@/lib/plaid';
// In a test script or API route
await sandboxResetLogin(accessToken);
// Next time user tries to sync, they'll be prompted to re-authenticate
Fire Webhook Manually (test webhook handling):
import { sandboxFireWebhook } from '@/lib/plaid';
// Trigger a transaction update webhook
await sandboxFireWebhook(accessToken, 'DEFAULT_UPDATE');
// Webhook endpoint receives event
// Check /api/plaid/webhook for processing
Webhook Test Codes:
DEFAULT_UPDATE- Standard transaction updateHISTORICAL_UPDATE- Historical data availableINITIAL_UPDATE- Initial transaction fetch completeITEM_LOGIN_REQUIRED- User needs to relink
Testing Error Scenarios
Invalid Access Token:
// Use expired or wrong access token
// Should trigger error handling and prompt re-authentication
Rate Limiting:
// Make multiple sync requests rapidly
// Should handle gracefully with error message
Network Failure:
// Turn off network mid-request
// Should show error state and retry option
Email Testing
Local Email Testing with Resend
Test Mode: Resend allows testing without sending real emails.
Option 1: Use Resend Test Domain:
RESEND_FROM_EMAIL=onboarding@resend.dev
- Emails appear in Resend dashboard logs
- Not delivered to inbox (safe for testing)
Option 2: Use Personal Email:
RESEND_FROM_EMAIL=your-email@gmail.com
- Emails sent to your inbox
- Verify templates render correctly
- Check spam folder if not received
Testing Email Templates
OneLibro has 7+ email templates. Test each:
1. Welcome Email (on signup):
# Sign up new user
# Check email for welcome message
# Verify branding and formatting
2. Invite Request Confirmation:
# Request invite code
# Check email confirming request received
3. Invite Code Email:
# Admin creates invite code
# User receives invite code email
# Verify code is readable and copy-pasteable
4. Budget Alert Email:
# Create budget with threshold
# Manually trigger alert or wait for cron
# Verify alert shows budget name, amount, percentage
5. Password Reset (if implemented):
# Click "Forgot Password"
# Check email for reset link
# Verify link works
Manual Email Testing
Test Send via API Route:
Create temporary API route for testing:
// app/api/test-email/route.ts
import { sendEmail } from '@/lib/email';
export async function GET() {
const result = await sendEmail({
to: 'your-email@example.com',
subject: 'Test Email from OneLibro',
template: 'welcome',
data: {
name: 'Test User',
email: 'test@example.com',
},
});
return Response.json(result);
}
Test:
curl http://localhost:3000/api/test-email
Verify:
- Check Resend dashboard for delivery status
- Check inbox for email
- Inspect template rendering
- Test on different email clients (Gmail, Outlook, Apple Mail)
Checking Resend Logs
- Go to Resend Dashboard
- Click "Logs"
- View recent emails:
- Sent: Successfully delivered
- Delivered: Confirmed receipt
- Opened: Recipient opened email
- Clicked: Recipient clicked link
- Bounced: Failed delivery
- Complained: Marked as spam
End-to-End Testing
Test complete user workflows from start to finish.
Test 1: New User Signup Flow
Scenario: New user signs up with invite code
Steps:
- Navigate to
http://finance.localhost:3000 - Click "Don't have an invite code? Request one"
- Enter email:
test@example.com - Submit request
- Verify in database:
invite_code_requeststable has entry - Go to admin dashboard:
http://admin.localhost:3000 - Login as admin (requires TOTP 2FA setup)
- Navigate to Invite Requests
- Approve the request
- Verify email sent with invite code
- Copy invite code from email
- Return to finance app signup
- Enter email, password, name, and invite code
- Submit signup form
- Verify:
- User created in
userstable - Welcome email sent
- Redirected to dashboard
- Can access finance app
- User created in
Test 2: Bank Connection Flow
Scenario: User connects bank account via Plaid
Steps:
- Login to finance app
- Navigate to dashboard
- Click "Connect Bank Account"
- Plaid Link opens
- Search for "First Platypus Bank"
- Select institution
- Enter credentials:
user_good/pass_good - Select accounts (checking + savings)
- Grant permissions
- Plaid Link closes
- Verify:
- Accounts appear in dashboard
- Balances displayed correctly
- Account cards show institution name
- Can click "Sync" to refresh transactions
Test 3: Transaction Management
Scenario: View, filter, and export transactions
Steps:
- Connect bank account (if not already)
- Navigate to Transactions page
- Verify transactions displayed
- Test date filter:
- Select "Last 7 days"
- Verify only recent transactions shown
- Test category filter:
- Select "Food & Drink"
- Verify filtered results
- Test search:
- Type merchant name (e.g., "Starbucks")
- Verify search results
- Test export:
- Click "Export to CSV"
- Verify CSV downloads
- Open CSV and check data format
- Test manual transaction:
- Click "Add Transaction"
- Fill form with test data
- Submit
- Verify appears in list
Test 4: Budget Creation and Alerts
Scenario: Create budget and trigger alert
Steps:
- Navigate to Budgets page
- Click "Create Budget"
- Fill form:
- Name: "Groceries Test"
- Category: "Food & Drink"
- Amount: $50
- Period: Monthly
- Submit form
- Verify budget appears in list
- Create transactions exceeding 90% of budget:
- Add manual transactions totaling $46+ (> 90% of $50)
- Trigger budget alert cron manually:
curl http://localhost:3000/api/cron/budget-alerts \
-H "Authorization: Bearer local_test_secret" - Verify:
- Alert email sent
budget_alert_historytable has entry- Duplicate alert prevented (run cron again, no new email)
Test 5: Admin Workflows
Scenario: Admin manages users and invites
Steps:
Setup Admin Account:
- Create user in Supabase
userstable - Set
is_admin = true - Generate TOTP secret and save
- Setup 2FA in authenticator app
Test Admin Login:
- Navigate to
http://admin.localhost:3000 - Enter admin email and password
- Enter TOTP code from authenticator
- Verify access to admin dashboard
Test User Management:
- Navigate to Users section
- View list of users
- Check user details (name, email, signup date)
- Verify admin flag displayed correctly
Test Invite Code Creation:
- Navigate to Invite Codes
- Click "Create Invite Code"
- Fill form:
- Code:
TESTCODE123 - Max Uses: 5
- Expiration: 7 days from now
- Code:
- Submit
- Verify code appears in list
- Test code usage:
- Signup with code
- Check
invite_codestable:used_countincremented
Test Invite Request Approval:
- User requests invite code (from finance app)
- Admin sees request in Invite Requests
- Admin clicks "Approve"
- Verify:
- Invite code generated
- Email sent to requester
- Request status updated
Database Testing
Testing RLS Policies
Row-Level Security (RLS) ensures users can only access their own data.
Test User Data Isolation:
-- Login as User A
-- Try to query User B's transactions
SELECT * FROM transactions WHERE user_id = 'user_b_id';
-- Should return 0 rows (blocked by RLS)
Test Admin Access:
-- Login as admin user (is_admin = true)
-- Should be able to query all users' data
SELECT * FROM transactions;
-- Should return all transactions
Test Public Access:
-- Without authentication
SELECT * FROM invite_codes WHERE code = 'TESTCODE123';
-- Should succeed (invite codes are publicly readable for validation)
Testing Data Integrity
Foreign Key Constraints:
-- Try to create transaction with non-existent account
INSERT INTO transactions (account_id, amount, ...)
VALUES ('invalid_account_id', 1000, ...);
-- Should fail with foreign key violation
Unique Constraints:
-- Try to create duplicate invite code
INSERT INTO invite_codes (code, ...)
VALUES ('TESTCODE123', ...);
-- Should fail if code already exists
Check Constraints:
-- Try to create budget with negative amount
INSERT INTO budgets (amount_cents, ...)
VALUES (-1000, ...);
-- Should fail (amount must be positive)
Performance Testing
Load Testing Dashboard
Test with Multiple Accounts and Transactions:
- Connect 5+ sandbox accounts
- Generate 100+ transactions
- Navigate to dashboard
- Measure load time (should be < 2 seconds)
- Check browser console for performance warnings
Tools:
- Chrome DevTools Performance tab
- Lighthouse audit
- React DevTools Profiler
API Response Times
Test API Endpoints:
# Test transaction fetch
time curl http://localhost:3000/api/transactions?userId=test_user_id
# Should respond in < 500ms
Optimize Slow Queries:
- Add database indexes
- Use pagination
- Implement caching (SWR on client)
Automated Testing (Future)
While OneLibro currently uses manual testing, consider adding:
Unit Tests (Jest + React Testing Library):
// Example: Test budget calculation
import { calculateBudgetProgress } from '@/lib/budgets';
test('calculates budget progress correctly', () => {
const budget = { amount_cents: 50000 }; // $500
const spent = 45000; // $450
const progress = calculateBudgetProgress(budget, spent);
expect(progress).toBe(90); // 90%
});
Integration Tests (Playwright or Cypress):
// Example: Test signup flow
test('user can sign up with invite code', async ({ page }) => {
await page.goto('http://finance.localhost:3000');
await page.click('text=Sign Up');
await page.fill('#email', 'test@example.com');
await page.fill('#password', 'SecurePass123');
await page.fill('#inviteCode', 'TESTCODE123');
await page.click('button[type=submit]');
await expect(page).toHaveURL(/dashboard/);
});
API Tests (Supertest):
import request from 'supertest';
test('GET /api/accounts requires authentication', async () => {
const response = await request(app).get('/api/accounts');
expect(response.status).toBe(401);
});
Testing Checklist
Before deploying to production, verify:
Local Testing
- Development server starts without errors
- All environment variables loaded correctly
- Finance subdomain works:
finance.localhost:3000 - Admin subdomain works:
admin.localhost:3000 - Main portfolio works:
localhost:3000
Plaid Testing
- Can connect sandbox bank account
- Accounts appear after connection
- Transactions sync successfully
- Manual sync button works
- Sandbox credentials work:
user_good/pass_good - Error handling works for bad credentials
- Access tokens encrypted before storing
Email Testing
- Welcome email sent on signup
- Invite code email sent when created
- Budget alert emails sent
- Email templates render correctly
- No emails go to spam
- Resend logs show successful delivery
User Flows
- Invite request flow works end-to-end
- Signup with invite code works
- Login and session persistence works
- Bank connection flow completes successfully
- Transaction filtering and search works
- CSV export downloads correctly
- Budget creation and tracking works
- Budget alerts trigger correctly
Admin Testing
- Admin login with TOTP 2FA works
- User management displays correctly
- Invite code creation works
- Invite request approval works
- Admin can view all users' data
Database Testing
- RLS policies prevent unauthorized access
- Foreign key constraints enforced
- Data validation works (no negative amounts, etc.)
- Transactions isolated per user
- Admin flag grants full access
Performance
- Dashboard loads in < 2 seconds
- API responses < 500ms
- No console errors or warnings
- No memory leaks (check with long sessions)
Troubleshooting Common Issues
Issue: "Failed to fetch" errors in console
Cause: API routes not accessible or CORS issue
Solution:
- Verify development server running
- Check API route exists in
app/api/ - Check network tab for actual error
- Verify environment variables loaded
Issue: Plaid Link won't open
Cause: Link token creation failing
Solution:
- Check
PLAID_CLIENT_IDandPLAID_SECRETin.env.local - Verify
PLAID_ENV=sandbox - Check browser console for errors
- Test link token endpoint manually:
curl -X POST http://localhost:3000/api/plaid/create-link-token \
-H "Content-Type: application/json" \
-d '{"userId": "test_user_id"}'
Issue: Emails not sending
Cause: Resend API key invalid or rate limit
Solution:
- Verify
RESEND_API_KEYin.env.local - Check Resend dashboard for errors
- Try test domain:
onboarding@resend.dev - Check Resend logs for delivery status
Issue: Subdomain routing not working
Cause: Browser doesn't resolve .localhost subdomains
Solution:
- Use Chrome or Edge (best support)
- Or edit hosts file (see Subdomain Testing section)
- Or test direct routes:
/finance,/admin
Summary
Testing checklist:
- ✅ Local development environment set up
- ✅ Subdomain routing tested on all subdomains
- ✅ Plaid sandbox connection flow verified
- ✅ Transaction syncing works with test data
- ✅ Email templates tested and delivered correctly
- ✅ All end-to-end user flows completed successfully
- ✅ Admin workflows function correctly
- ✅ Database RLS policies enforced
- ✅ Performance benchmarks met
OneLibro is ready for production deployment!
For deployment instructions, see the Deployment Guide.