remove: obsolete auth debug test infrastructure
- Remove auth-debug.spec.ts (functionality merged into auth.spec.ts) - Remove auth-debug-setup.ts and auth-debug-teardown.ts - Remove AUTH-DEBUG-GUIDE.md and AUTH-DEBUG-SETUP-GUIDE.md documentation - Remove specialized playwright.auth.config.ts configuration - Consolidates testing into main E2E test suite for better maintainability
This commit is contained in:
@@ -1,421 +0,0 @@
|
||||
# 🔐 Authentication Debug Testing Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The authentication debug test suite (`auth-debug.spec.ts`) provides comprehensive automated testing and debugging capabilities for all authentication flows in the Medication Reminder App. This replaces the previous manual browser console debugging scripts with fully automated, cross-browser tests.
|
||||
|
||||
## 🎯 What This Replaces
|
||||
|
||||
### Before (Manual Tests)
|
||||
|
||||
- `tests/manual/admin-login-debug.js` - Browser console script
|
||||
- `tests/manual/auth-db-debug.js` - Database debugging script
|
||||
- `tests/manual/debug-email-validation.js` - Email validation script
|
||||
|
||||
### After (Automated Tests)
|
||||
|
||||
- `tests/e2e/auth-debug.spec.ts` - Comprehensive E2E test suite
|
||||
- Cross-browser automated testing
|
||||
- CI/CD pipeline integration
|
||||
- Interactive debugging capabilities
|
||||
|
||||
## 🧪 Test Coverage
|
||||
|
||||
### 1. Admin User Validation
|
||||
|
||||
- Verifies admin@localhost account exists
|
||||
- Tests admin login flow
|
||||
- Validates admin permissions and UI access
|
||||
- Checks admin interface functionality
|
||||
|
||||
### 2. Email Format Validation
|
||||
|
||||
- Tests various email formats including localhost domains
|
||||
- Validates email input validation rules
|
||||
- Covers edge cases and invalid formats
|
||||
- Ensures proper error messaging
|
||||
|
||||
### 3. User Registration
|
||||
|
||||
- Tests user creation with password
|
||||
- Validates registration form fields
|
||||
- Checks verification flow
|
||||
- Ensures unique user handling
|
||||
|
||||
### 4. OAuth Integration
|
||||
|
||||
- Verifies OAuth buttons are present
|
||||
- Tests OAuth flow initiation
|
||||
- Handles OAuth redirects and errors
|
||||
- Validates OAuth user creation
|
||||
|
||||
### 5. Database Connection
|
||||
|
||||
- Checks system status indicators
|
||||
- Validates database connectivity
|
||||
- Ensures app loads properly
|
||||
- Tests service health
|
||||
|
||||
### 6. Password Security
|
||||
|
||||
- Tests password strength requirements
|
||||
- Validates weak password rejection
|
||||
- Ensures strong password acceptance
|
||||
- Checks security messaging
|
||||
|
||||
### 7. Session Management
|
||||
|
||||
- Tests session persistence across page reloads
|
||||
- Validates login state maintenance
|
||||
- Checks automatic logout scenarios
|
||||
- Ensures proper session handling
|
||||
|
||||
### 8. Error Handling
|
||||
|
||||
- Tests invalid login attempts
|
||||
- Validates error messaging
|
||||
- Checks form validation
|
||||
- Ensures proper feedback
|
||||
|
||||
### 9. User Management
|
||||
|
||||
- Tests admin user lookup functionality
|
||||
- Validates user search capabilities
|
||||
- Checks user list display
|
||||
- Ensures admin tools work
|
||||
|
||||
## 🚀 Running Auth Debug Tests
|
||||
|
||||
### Quick Commands
|
||||
|
||||
```bash
|
||||
# Run auth debug tests (headless)
|
||||
make test-auth-debug
|
||||
|
||||
# Run with interactive UI for debugging
|
||||
make test-auth-debug-ui
|
||||
|
||||
# Run specific test with debug mode
|
||||
bunx playwright test auth-debug.spec.ts --debug
|
||||
|
||||
# Run on specific browser
|
||||
bunx playwright test auth-debug.spec.ts --project=auth-debug-firefox
|
||||
```
|
||||
|
||||
### Full Command Options
|
||||
|
||||
```bash
|
||||
# All browsers with full reporting
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts
|
||||
|
||||
# Single browser with trace
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --project=auth-debug-chromium --trace=on
|
||||
|
||||
# Headed mode for visual debugging
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --headed
|
||||
|
||||
# Debug specific failing test
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --debug -g "should validate admin user"
|
||||
```
|
||||
|
||||
## 🔧 Test Configuration
|
||||
|
||||
The auth debug tests use a specialized Playwright configuration (`playwright.auth.config.ts`) with:
|
||||
|
||||
- **Extended timeouts** for auth operations (60s per test)
|
||||
- **Sequential execution** to avoid auth conflicts
|
||||
- **Enhanced reporting** with multiple output formats
|
||||
- **Service auto-start** for dependencies
|
||||
- **Cross-browser testing** on desktop and mobile
|
||||
- **Detailed tracing** on failures
|
||||
|
||||
### Browser Coverage
|
||||
|
||||
- **Desktop**: Chrome, Firefox, Safari
|
||||
- **Mobile**: Chrome on Android, Safari on iOS
|
||||
- **Special configs** for auth-specific browser settings
|
||||
|
||||
## 📊 Reports and Output
|
||||
|
||||
### Generated Reports
|
||||
|
||||
1. **HTML Report**: `playwright-report-auth/index.html`
|
||||
- Interactive test results
|
||||
- Screenshots and videos
|
||||
- Detailed failure analysis
|
||||
|
||||
2. **JSON Report**: `playwright-report-auth.json`
|
||||
- Machine-readable results
|
||||
- Integration with CI/CD
|
||||
- Detailed test metadata
|
||||
|
||||
3. **Summary Report**: `auth-debug-summary.json`
|
||||
- High-level test statistics
|
||||
- Environment information
|
||||
- Quick status overview
|
||||
|
||||
4. **JUnit Report**: `playwright-auth-results.xml`
|
||||
- CI/CD integration format
|
||||
- Test result parsing
|
||||
- Build system integration
|
||||
|
||||
### Viewing Reports
|
||||
|
||||
```bash
|
||||
# Open HTML report
|
||||
npx playwright show-report playwright-report-auth
|
||||
|
||||
# View summary
|
||||
cat auth-debug-summary.json | jq
|
||||
|
||||
# Check specific failures
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --reporter=list
|
||||
```
|
||||
|
||||
## 🐛 Debugging Workflows
|
||||
|
||||
### Interactive Debugging
|
||||
|
||||
```bash
|
||||
# Launch interactive debug mode
|
||||
make test-auth-debug-ui
|
||||
|
||||
# Debug specific test
|
||||
bunx playwright test auth-debug.spec.ts --debug -g "admin user"
|
||||
|
||||
# Step through test with browser open
|
||||
bunx playwright test auth-debug.spec.ts --headed --debug
|
||||
```
|
||||
|
||||
### Common Debugging Scenarios
|
||||
|
||||
#### 1. Admin Login Issues
|
||||
|
||||
```bash
|
||||
# Debug admin login specifically
|
||||
bunx playwright test --debug -g "should validate admin user exists"
|
||||
|
||||
# Check with different browser
|
||||
bunx playwright test --project=auth-debug-firefox --debug -g "admin user"
|
||||
```
|
||||
|
||||
#### 2. Email Validation Problems
|
||||
|
||||
```bash
|
||||
# Debug email validation
|
||||
bunx playwright test --debug -g "email format"
|
||||
|
||||
# Run with console output
|
||||
bunx playwright test -g "email format" --reporter=line
|
||||
```
|
||||
|
||||
#### 3. OAuth Flow Issues
|
||||
|
||||
```bash
|
||||
# Debug OAuth with network logs
|
||||
bunx playwright test --debug -g "OAuth" --trace=on
|
||||
|
||||
# Check OAuth buttons
|
||||
bunx playwright test --headed -g "OAuth user creation"
|
||||
```
|
||||
|
||||
#### 4. Database Connection Problems
|
||||
|
||||
```bash
|
||||
# Debug database connectivity
|
||||
bunx playwright test --debug -g "database connection"
|
||||
|
||||
# Check service status
|
||||
bunx playwright test -g "database" --reporter=line
|
||||
```
|
||||
|
||||
### Debug Output Interpretation
|
||||
|
||||
The tests include extensive console logging:
|
||||
|
||||
```
|
||||
Testing email validation for: admin@localhost
|
||||
✅ Admin user verified and functional
|
||||
⚠️ Search functionality not implemented - this is optional
|
||||
Testing weak password (too short): 123
|
||||
📊 Found 1 users in the system
|
||||
```
|
||||
|
||||
**Log Levels:**
|
||||
|
||||
- `✅` Success/verification messages
|
||||
- `⚠️` Warnings (expected issues)
|
||||
- `❌` Errors requiring attention
|
||||
- `📊` Information and statistics
|
||||
|
||||
## 🔄 CI/CD Integration
|
||||
|
||||
### Pipeline Configuration
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
name: Auth Debug Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
auth-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- run: bun install
|
||||
- run: bunx playwright install --with-deps
|
||||
- run: make test-auth-debug
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: auth-test-results
|
||||
path: |
|
||||
playwright-report-auth/
|
||||
auth-debug-summary.json
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Required for CI
|
||||
NODE_ENV=test
|
||||
CI=true
|
||||
VITE_COUCHDB_URL=http://localhost:5984
|
||||
VITE_COUCHDB_USERNAME=admin
|
||||
VITE_COUCHDB_PASSWORD=password
|
||||
```
|
||||
|
||||
## 🛠️ Maintenance and Updates
|
||||
|
||||
### Adding New Auth Tests
|
||||
|
||||
1. **Add test case** to `auth-debug.spec.ts`
|
||||
2. **Follow naming convention**: `should [action] [expected result]`
|
||||
3. **Include console logging** for debugging
|
||||
4. **Handle timeouts** appropriately
|
||||
5. **Clean up test data** if needed
|
||||
|
||||
### Example New Test
|
||||
|
||||
```typescript
|
||||
test('should validate two-factor authentication', async ({ page }) => {
|
||||
console.log('Testing 2FA validation...');
|
||||
|
||||
// Test implementation
|
||||
await page.fill('input[type="email"]', 'admin@localhost');
|
||||
await page.fill('input[type="password"]', 'admin123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Check for 2FA prompt
|
||||
await expect(page.locator('text=Enter verification code')).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
console.log('✅ 2FA prompt displayed correctly');
|
||||
});
|
||||
```
|
||||
|
||||
### Updating Test Credentials
|
||||
|
||||
If admin credentials change, update:
|
||||
|
||||
- Test files: `auth-debug.spec.ts`
|
||||
- Setup files: `auth-debug-setup.ts`
|
||||
- Documentation: This guide
|
||||
|
||||
## 🚨 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Tests Timeout
|
||||
|
||||
**Symptoms**: Tests hang or timeout
|
||||
**Solutions**:
|
||||
|
||||
- Check service availability (`http://localhost:8080`, `http://localhost:5984`)
|
||||
- Increase timeouts in config
|
||||
- Run with `--headed` to see what's happening
|
||||
|
||||
#### 2. Admin User Not Found
|
||||
|
||||
**Symptoms**: Admin login fails
|
||||
**Solutions**:
|
||||
|
||||
- Verify admin user exists in database
|
||||
- Check credentials in test file
|
||||
- Run database initialization
|
||||
|
||||
#### 3. Service Not Ready
|
||||
|
||||
**Symptoms**: Cannot connect to app/database
|
||||
**Solutions**:
|
||||
|
||||
- Start services manually: `make dev` and CouchDB
|
||||
- Check Docker containers
|
||||
- Verify ports are not blocked
|
||||
|
||||
#### 4. Browser Issues
|
||||
|
||||
**Symptoms**: Tests fail in specific browsers
|
||||
**Solutions**:
|
||||
|
||||
- Update Playwright: `bunx playwright install`
|
||||
- Check browser-specific configurations
|
||||
- Run single browser: `--project=auth-debug-chromium`
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Check service status
|
||||
curl http://localhost:8080
|
||||
curl http://localhost:5984
|
||||
|
||||
# Verify test setup
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --list
|
||||
|
||||
# Run with maximum verbosity
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --reporter=line --verbose
|
||||
|
||||
# Check configuration
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --reporter=json | jq '.config'
|
||||
```
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- **Main E2E Guide**: `tests/e2e/README.md`
|
||||
- **Test Cleanup Info**: `tests/README-CLEANUP.md`
|
||||
- **Migration Summary**: `CLEANUP-SUMMARY.md`
|
||||
- **Quick Reference**: `QUICK-REFERENCE.md`
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### Writing Auth Tests
|
||||
|
||||
1. **Use unique identifiers** (timestamps) for test data
|
||||
2. **Include descriptive console logging**
|
||||
3. **Handle both success and failure cases**
|
||||
4. **Clean up test artifacts**
|
||||
5. **Use appropriate timeouts**
|
||||
|
||||
### Debugging Process
|
||||
|
||||
1. **Start with interactive mode** (`--ui` or `--debug`)
|
||||
2. **Check service availability** first
|
||||
3. **Review console logs** for clues
|
||||
4. **Use browser dev tools** when needed
|
||||
5. **Isolate failing tests**
|
||||
|
||||
### Maintenance
|
||||
|
||||
1. **Run tests regularly** to catch regressions
|
||||
2. **Update credentials** when changed
|
||||
3. **Add tests for new auth features**
|
||||
4. **Monitor test performance**
|
||||
5. **Review failure patterns**
|
||||
|
||||
---
|
||||
|
||||
**Quick Start**: Run `make test-auth-debug-ui` to launch interactive debugging mode and explore the authentication flows visually.
|
||||
|
||||
**Need Help?**: Check the generated HTML report for detailed test results and failure analysis.
|
||||
@@ -1,316 +0,0 @@
|
||||
# Authentication Debug Setup Guide
|
||||
|
||||
This guide explains the `auth-debug-setup.ts` file and how to use it for debugging authentication flows in the Medication Reminder application.
|
||||
|
||||
## Overview
|
||||
|
||||
The `auth-debug-setup.ts` file is a Playwright global setup script specifically designed for debugging authentication-related issues. It ensures that all required services are running and properly configured before running authentication tests.
|
||||
|
||||
## What It Does
|
||||
|
||||
### 🔧 Service Initialization
|
||||
|
||||
- **Frontend Service**: Verifies the app is running on `http://localhost:8080`
|
||||
- **CouchDB Database**: Ensures CouchDB is accessible on `http://localhost:5984`
|
||||
- **Database Setup**: Creates necessary databases if they don't exist
|
||||
- **Admin User Verification**: Tests admin login functionality end-to-end
|
||||
|
||||
### 📊 Diagnostics
|
||||
|
||||
- **Service Health Checks**: Comprehensive connectivity testing
|
||||
- **Database Status**: Lists available databases and connection status
|
||||
- **Environment Information**: Logs Node.js version, platform, and environment variables
|
||||
- **Network Connectivity**: Tests various endpoints for accessibility
|
||||
|
||||
## File Structure
|
||||
|
||||
```typescript
|
||||
// Main setup functions
|
||||
globalSetup(); // Orchestrates all setup tasks
|
||||
waitForServices(); // Waits for services to be ready
|
||||
initializeTestData(); // Creates required databases
|
||||
verifyAdminUser(); // Tests admin login flow
|
||||
logEnvironmentInfo(); // Logs debugging information
|
||||
|
||||
// Diagnostic utilities
|
||||
runServiceDiagnostics(); // Comprehensive service testing
|
||||
testDatabaseConnectivity(); // Detailed database status
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Services
|
||||
|
||||
Before running auth debug tests, ensure these services are running:
|
||||
|
||||
1. **Frontend Application**
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
# Runs on http://localhost:8080
|
||||
```
|
||||
|
||||
2. **CouchDB Database**
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/docker-compose.yaml up -d
|
||||
# Runs on http://localhost:5984
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The setup respects these environment variables:
|
||||
|
||||
- `NODE_ENV`: Environment mode (development/test/production)
|
||||
- `CI`: CI/CD environment flag
|
||||
- `DEBUG_MODE`: Enables additional debugging features
|
||||
|
||||
### Database Configuration
|
||||
|
||||
The setup creates these databases automatically:
|
||||
|
||||
- `users` - User accounts and authentication data
|
||||
- `medications` - Medication information
|
||||
- `settings` - Application settings
|
||||
- `taken_doses` - Medication intake records
|
||||
- `reminders` - Reminder configurations
|
||||
|
||||
### Default Credentials
|
||||
|
||||
The setup uses these default credentials for testing:
|
||||
|
||||
- **CouchDB**: `admin:password`
|
||||
- **Test Admin User**: `admin@localhost:admin123!`
|
||||
|
||||
## Usage
|
||||
|
||||
### Running Auth Debug Tests
|
||||
|
||||
```bash
|
||||
# Run auth debug tests specifically
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts
|
||||
|
||||
# Run with UI for interactive debugging
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --ui
|
||||
|
||||
# Run in debug mode
|
||||
bunx playwright test --config=tests/e2e/playwright.auth.config.ts --debug
|
||||
```
|
||||
|
||||
### Manual Setup Verification
|
||||
|
||||
You can verify the setup manually:
|
||||
|
||||
```bash
|
||||
# Check frontend
|
||||
curl http://localhost:8080
|
||||
|
||||
# Check CouchDB
|
||||
curl -u admin:password http://localhost:5984
|
||||
|
||||
# List databases
|
||||
curl -u admin:password http://localhost:5984/_all_dbs
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Services Not Ready
|
||||
|
||||
**Symptoms**: Setup fails with service connection errors
|
||||
**Solutions**:
|
||||
|
||||
```bash
|
||||
# Check if services are running
|
||||
docker ps
|
||||
netstat -tlnp | grep 8080
|
||||
netstat -tlnp | grep 5984
|
||||
|
||||
# Restart services
|
||||
docker-compose -f docker/docker-compose.yaml restart
|
||||
bun run dev
|
||||
```
|
||||
|
||||
#### 2. Database Connection Failed
|
||||
|
||||
**Symptoms**: CouchDB authentication or connection errors
|
||||
**Solutions**:
|
||||
|
||||
```bash
|
||||
# Check CouchDB logs
|
||||
docker-compose -f docker/docker-compose.yaml logs couchdb
|
||||
|
||||
# Reset CouchDB data
|
||||
docker-compose -f docker/docker-compose.yaml down -v
|
||||
docker-compose -f docker/docker-compose.yaml up -d
|
||||
```
|
||||
|
||||
#### 3. Admin User Not Found
|
||||
|
||||
**Symptoms**: Admin login verification fails
|
||||
**Solutions**:
|
||||
|
||||
- Check if admin user exists in the users database
|
||||
- Verify credentials match the expected format
|
||||
- Create admin user manually if needed
|
||||
|
||||
#### 4. Timeout Issues
|
||||
|
||||
**Symptoms**: Setup times out waiting for services
|
||||
**Solutions**:
|
||||
|
||||
```bash
|
||||
# Increase timeout values in setup
|
||||
# Check system resources
|
||||
free -h
|
||||
docker stats
|
||||
|
||||
# Reduce parallel processes
|
||||
pkill -f "node.*vite"
|
||||
pkill -f "playwright"
|
||||
```
|
||||
|
||||
### Debug Logs
|
||||
|
||||
The setup provides detailed logging at different levels:
|
||||
|
||||
```typescript
|
||||
// Enable debug logging
|
||||
logger.setLevel(LogLevel.DEBUG);
|
||||
|
||||
// View specific context logs
|
||||
logger.getLogs('SETUP');
|
||||
logger.getLogs('AUTH');
|
||||
logger.getLogs('DATABASE');
|
||||
```
|
||||
|
||||
### Diagnostic Output
|
||||
|
||||
The setup generates comprehensive diagnostic information:
|
||||
|
||||
```
|
||||
🌍 Environment Information:
|
||||
Node.js: v18.17.0
|
||||
Platform: linux
|
||||
NODE_ENV: test
|
||||
CI: false
|
||||
Frontend URL: http://localhost:8080
|
||||
CouchDB URL: http://localhost:5984
|
||||
|
||||
🔍 Running comprehensive service diagnostics...
|
||||
Frontend status: 200 OK
|
||||
Database connected with 5 databases
|
||||
Health endpoint accessible
|
||||
|
||||
✅ Auth debug setup completed in 2847ms
|
||||
```
|
||||
|
||||
## Integration with Test Suite
|
||||
|
||||
### Playwright Configuration
|
||||
|
||||
The setup integrates with `playwright.auth.config.ts`:
|
||||
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
globalSetup: require.resolve('./auth-debug-setup.ts'),
|
||||
globalTeardown: require.resolve('./auth-debug-teardown.ts'),
|
||||
// ... other config
|
||||
});
|
||||
```
|
||||
|
||||
### Test Dependencies
|
||||
|
||||
Tests that depend on this setup:
|
||||
|
||||
- `auth-debug.spec.ts` - Main authentication validation tests
|
||||
- `admin.spec.ts` - Admin functionality tests
|
||||
- `auth.spec.ts` - General authentication tests
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Environment Isolation
|
||||
|
||||
- Use dedicated test databases
|
||||
- Clean up test data between runs
|
||||
- Avoid production credentials
|
||||
|
||||
### 2. Robust Error Handling
|
||||
|
||||
- Don't fail setup for non-critical issues
|
||||
- Log warnings for optional features
|
||||
- Provide helpful error messages
|
||||
|
||||
### 3. Service Dependencies
|
||||
|
||||
- Wait for all required services
|
||||
- Test actual connectivity, not just port availability
|
||||
- Verify service functionality, not just status
|
||||
|
||||
### 4. Debugging Support
|
||||
|
||||
- Comprehensive logging at appropriate levels
|
||||
- Detailed diagnostic information
|
||||
- Clear failure messages with next steps
|
||||
|
||||
## Development
|
||||
|
||||
### Modifying the Setup
|
||||
|
||||
When modifying the setup script:
|
||||
|
||||
1. **Test thoroughly** in different environments
|
||||
2. **Maintain backward compatibility** with existing tests
|
||||
3. **Update documentation** for any new features
|
||||
4. **Add appropriate logging** for debugging
|
||||
|
||||
### Adding New Services
|
||||
|
||||
To add new service checks:
|
||||
|
||||
```typescript
|
||||
// Add to waitForServices()
|
||||
await waitForService('http://localhost:9000', 'NewService');
|
||||
|
||||
// Add diagnostic check
|
||||
async function checkNewService() {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Environment-Specific Configuration
|
||||
|
||||
For different environments:
|
||||
|
||||
```typescript
|
||||
const config = {
|
||||
development: {
|
||||
timeout: 60000,
|
||||
retries: 3,
|
||||
},
|
||||
ci: {
|
||||
timeout: 120000,
|
||||
retries: 5,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Related Files
|
||||
|
||||
- `auth-debug-teardown.ts` - Cleanup and reporting
|
||||
- `auth-debug.spec.ts` - Main authentication tests
|
||||
- `playwright.auth.config.ts` - Playwright configuration
|
||||
- `AUTH-DEBUG-GUIDE.md` - Test execution guide
|
||||
|
||||
## Support
|
||||
|
||||
For issues with the auth debug setup:
|
||||
|
||||
1. Check the diagnostic output for specific error messages
|
||||
2. Verify all required services are running
|
||||
3. Review the troubleshooting section above
|
||||
4. Check related test files for configuration examples
|
||||
5. Enable debug logging for detailed information
|
||||
|
||||
The setup is designed to be self-diagnosing and should provide clear information about any issues encountered during initialization.
|
||||
@@ -1,354 +0,0 @@
|
||||
import { chromium } from 'playwright';
|
||||
import { logger } from '../../services/logging';
|
||||
|
||||
interface GlobalSetupConfig {
|
||||
projects?: Array<{
|
||||
name: string;
|
||||
use?: Record<string, unknown>;
|
||||
}>;
|
||||
webServer?: Array<{
|
||||
command: string;
|
||||
port: number;
|
||||
timeout: number;
|
||||
reuseExistingServer: boolean;
|
||||
}>;
|
||||
use?: {
|
||||
baseURL?: string;
|
||||
trace?: string;
|
||||
screenshot?: string;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global setup for authentication debug tests
|
||||
* Ensures services are running and database is properly initialized
|
||||
*/
|
||||
async function globalSetup(_config: GlobalSetupConfig) {
|
||||
logger.info(
|
||||
'🔧 Setting up authentication debug test environment...',
|
||||
'SETUP'
|
||||
);
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Wait for services to be ready
|
||||
await waitForServices();
|
||||
|
||||
// Initialize test data if needed
|
||||
await initializeTestData();
|
||||
|
||||
// Verify admin user exists
|
||||
await verifyAdminUser();
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
logger.info(`✅ Auth debug setup completed in ${duration}ms`, 'SETUP');
|
||||
} catch (error) {
|
||||
logger.error('❌ Auth debug setup failed:', 'SETUP', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for required services to be available
|
||||
*/
|
||||
async function waitForServices(): Promise<void> {
|
||||
logger.info('⏳ Waiting for services to be ready...', 'SETUP');
|
||||
|
||||
// Wait for frontend
|
||||
await waitForService('http://localhost:8080', 'Frontend');
|
||||
|
||||
// Wait for CouchDB
|
||||
await waitForService('http://localhost:5984', 'CouchDB');
|
||||
|
||||
logger.info('✅ All services are ready', 'SETUP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a specific service to be available
|
||||
*/
|
||||
async function waitForService(url: string, serviceName: string): Promise<void> {
|
||||
const maxAttempts = 30;
|
||||
const delay = 2000; // 2 seconds
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
signal: AbortSignal.timeout(5000), // 5 second timeout per request
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
logger.info(`✅ ${serviceName} is ready at ${url}`, 'SETUP');
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
// Log specific error types for better debugging
|
||||
if (error instanceof Error) {
|
||||
logger.debug(
|
||||
`⏳ ${serviceName} connection failed: ${error.message}`,
|
||||
'SETUP'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (attempt === maxAttempts) {
|
||||
throw new Error(
|
||||
`${serviceName} not available at ${url} after ${maxAttempts} attempts`
|
||||
);
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
`⏳ ${serviceName} not ready, attempt ${attempt}/${maxAttempts}...`,
|
||||
'SETUP'
|
||||
);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize test data and ensure databases exist
|
||||
*/
|
||||
async function initializeTestData(): Promise<void> {
|
||||
logger.info('🔧 Initializing test data...', 'SETUP');
|
||||
|
||||
try {
|
||||
// Check if databases exist, create if needed
|
||||
const databases = [
|
||||
'users',
|
||||
'medications',
|
||||
'settings',
|
||||
'taken_doses',
|
||||
'reminders',
|
||||
];
|
||||
|
||||
for (const dbName of databases) {
|
||||
await ensureDatabaseExists(dbName);
|
||||
}
|
||||
|
||||
logger.info('✅ Test data initialization completed', 'SETUP');
|
||||
} catch (error) {
|
||||
logger.warn('⚠️ Test data initialization had issues:', 'SETUP', error);
|
||||
// Don't fail setup for database issues as the app should handle missing DBs
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a database exists
|
||||
*/
|
||||
async function ensureDatabaseExists(dbName: string): Promise<void> {
|
||||
const url = `http://localhost:5984/${dbName}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'HEAD',
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
});
|
||||
|
||||
if (response.status === 404) {
|
||||
// Database doesn't exist, create it
|
||||
await fetch(url, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
logger.info(`📊 Created database: ${dbName}`, 'SETUP');
|
||||
} else if (response.ok) {
|
||||
logger.info(`✅ Database exists: ${dbName}`, 'SETUP');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`⚠️ Could not verify/create database ${dbName}:`,
|
||||
'SETUP',
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify admin user exists for testing
|
||||
*/
|
||||
async function verifyAdminUser(): Promise<void> {
|
||||
logger.info('🔧 Verifying admin user exists...', 'SETUP');
|
||||
|
||||
try {
|
||||
const browser = await chromium.launch();
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
|
||||
// Navigate to the app
|
||||
await page.goto('http://localhost:8080');
|
||||
|
||||
// Wait for login form
|
||||
await page.waitForSelector('input[type="email"]', { timeout: 10000 });
|
||||
|
||||
// Try to login with admin credentials
|
||||
await page.fill('input[type="email"]', 'admin@localhost');
|
||||
await page.fill('input[type="password"]', 'admin123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Check if login was successful
|
||||
try {
|
||||
await page.waitForSelector('h1:has-text("Medication Reminder")', {
|
||||
timeout: 15000,
|
||||
});
|
||||
logger.info('✅ Admin user verified and functional', 'SETUP');
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
'⚠️ Admin user may not exist or credentials may be incorrect',
|
||||
'SETUP'
|
||||
);
|
||||
logger.warn(
|
||||
' Tests will attempt to create/verify admin user during execution',
|
||||
'SETUP'
|
||||
);
|
||||
if (error instanceof Error) {
|
||||
logger.debug(`Login verification error: ${error.message}`, 'SETUP');
|
||||
}
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
} catch (error) {
|
||||
logger.warn('⚠️ Could not verify admin user', 'SETUP');
|
||||
if (error instanceof Error) {
|
||||
logger.debug(`Admin verification error: ${error.message}`, 'SETUP');
|
||||
}
|
||||
// Don't fail setup, let individual tests handle this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log environment information
|
||||
*/
|
||||
function logEnvironmentInfo(): void {
|
||||
logger.info('🌍 Environment Information:', 'SETUP');
|
||||
logger.info(` Node.js: ${process.version}`, 'SETUP');
|
||||
logger.info(` Platform: ${process.platform}`, 'SETUP');
|
||||
logger.info(` NODE_ENV: ${process.env.NODE_ENV || 'not set'}`, 'SETUP');
|
||||
logger.info(` CI: ${process.env.CI || 'false'}`, 'SETUP');
|
||||
logger.info(` Frontend URL: http://localhost:8080`, 'SETUP');
|
||||
logger.info(` CouchDB URL: http://localhost:5984`, 'SETUP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database connectivity and return detailed status
|
||||
*/
|
||||
async function testDatabaseConnectivity(): Promise<{
|
||||
connected: boolean;
|
||||
databases: string[];
|
||||
errors: string[];
|
||||
}> {
|
||||
const result = {
|
||||
connected: false,
|
||||
databases: [] as string[],
|
||||
errors: [] as string[],
|
||||
};
|
||||
|
||||
try {
|
||||
// Test basic connectivity
|
||||
const response = await fetch('http://localhost:5984/', {
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
result.connected = true;
|
||||
const info = await response.json();
|
||||
logger.debug(`CouchDB version: ${info.version}`, 'SETUP');
|
||||
|
||||
// Get list of databases
|
||||
const dbResponse = await fetch('http://localhost:5984/_all_dbs', {
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
});
|
||||
|
||||
if (dbResponse.ok) {
|
||||
result.databases = await dbResponse.json();
|
||||
logger.debug(
|
||||
`Found databases: ${result.databases.join(', ')}`,
|
||||
'SETUP'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
result.errors.push(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
result.errors.push(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform comprehensive service diagnostics
|
||||
*/
|
||||
async function runServiceDiagnostics(): Promise<void> {
|
||||
logger.info('🔍 Running comprehensive service diagnostics...', 'SETUP');
|
||||
|
||||
// Test frontend
|
||||
try {
|
||||
const frontendResponse = await fetch('http://localhost:8080', {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
logger.info(
|
||||
`Frontend status: ${frontendResponse.status} ${frontendResponse.statusText}`,
|
||||
'SETUP'
|
||||
);
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`Frontend not accessible: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
'SETUP'
|
||||
);
|
||||
}
|
||||
|
||||
// Test database with detailed info
|
||||
const dbStatus = await testDatabaseConnectivity();
|
||||
if (dbStatus.connected) {
|
||||
logger.info(
|
||||
`Database connected with ${dbStatus.databases.length} databases`,
|
||||
'SETUP'
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Database connection failed: ${dbStatus.errors.join(', ')}`,
|
||||
'SETUP'
|
||||
);
|
||||
}
|
||||
|
||||
// Test network connectivity
|
||||
try {
|
||||
const response = await fetch('http://localhost:8080/health', {
|
||||
signal: AbortSignal.timeout(3000),
|
||||
});
|
||||
if (response.ok) {
|
||||
logger.info('Health endpoint accessible', 'SETUP');
|
||||
}
|
||||
} catch {
|
||||
logger.debug('Health endpoint not available (this is optional)', 'SETUP');
|
||||
}
|
||||
}
|
||||
|
||||
// Execute setup
|
||||
export default async function (config: GlobalSetupConfig) {
|
||||
logEnvironmentInfo();
|
||||
await runServiceDiagnostics();
|
||||
await globalSetup(config);
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
interface GlobalTeardownConfig {
|
||||
projects?: Array<{
|
||||
name: string;
|
||||
use?: Record<string, unknown>;
|
||||
}>;
|
||||
webServer?: Array<{
|
||||
command: string;
|
||||
port: number;
|
||||
timeout: number;
|
||||
reuseExistingServer: boolean;
|
||||
}>;
|
||||
use?: {
|
||||
baseURL?: string;
|
||||
trace?: string;
|
||||
screenshot?: string;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global teardown for authentication debug tests
|
||||
* Cleans up test environment and generates summary report
|
||||
*/
|
||||
async function globalTeardown(_config: GlobalTeardownConfig) {
|
||||
console.log('🧹 Starting authentication debug test teardown...');
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Clean up test data
|
||||
await cleanupTestData();
|
||||
|
||||
// Generate test summary
|
||||
await generateTestSummary();
|
||||
|
||||
// Clean up test artifacts
|
||||
await cleanupTestArtifacts();
|
||||
|
||||
// Log final status
|
||||
await logFinalStatus();
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
console.log(`✅ Auth debug teardown completed in ${duration}ms`);
|
||||
} catch (error) {
|
||||
console.error('❌ Auth debug teardown failed:', error);
|
||||
// Don't throw error to avoid masking test failures
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up test data created during tests
|
||||
*/
|
||||
async function cleanupTestData(): Promise<void> {
|
||||
console.log('🗑️ Cleaning up test data...');
|
||||
|
||||
try {
|
||||
// Clean up test users created during the test run
|
||||
await cleanupTestUsers();
|
||||
|
||||
// Clean up any temporary files
|
||||
await cleanupTempFiles();
|
||||
|
||||
console.log('✅ Test data cleanup completed');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Test data cleanup had issues:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove test users created during testing
|
||||
*/
|
||||
async function cleanupTestUsers(): Promise<void> {
|
||||
console.log('👥 Cleaning up test users...');
|
||||
|
||||
try {
|
||||
// Get list of databases
|
||||
const response = await fetch('http://localhost:5984/_all_dbs', {
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.warn('⚠️ Could not access CouchDB for user cleanup');
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for users database
|
||||
const databases = await response.json();
|
||||
if (databases.includes('users')) {
|
||||
await cleanupUsersFromDatabase();
|
||||
}
|
||||
|
||||
console.log('✅ Test users cleanup completed');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Could not cleanup test users:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up test users from the users database
|
||||
*/
|
||||
async function cleanupUsersFromDatabase(): Promise<void> {
|
||||
try {
|
||||
// Get all users
|
||||
const response = await fetch(
|
||||
'http://localhost:5984/users/_all_docs?include_docs=true',
|
||||
{
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const testUserPattern =
|
||||
/debug-test.*@localhost|test.*@localhost|strong.*@localhost/;
|
||||
|
||||
// Find and delete test users
|
||||
for (const row of data.rows) {
|
||||
if (row.doc && row.doc.email && testUserPattern.test(row.doc.email)) {
|
||||
await deleteTestUser(row.doc._id, row.doc._rev);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Error cleaning users database:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a specific test user
|
||||
*/
|
||||
async function deleteTestUser(userId: string, rev: string): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`http://localhost:5984/users/${userId}?rev=${rev}`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
Authorization:
|
||||
'Basic ' + Buffer.from('admin:password').toString('base64'),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`🗑️ Deleted test user: ${userId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Could not delete test user ${userId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up temporary files created during tests
|
||||
*/
|
||||
async function cleanupTempFiles(): Promise<void> {
|
||||
console.log('📂 Cleaning up temporary files...');
|
||||
|
||||
try {
|
||||
const fs = await import('fs').then(m => m.promises);
|
||||
const path = await import('path');
|
||||
|
||||
// Clean up any temporary screenshots or videos from failed tests
|
||||
const tempDirs = [
|
||||
'test-results-auth',
|
||||
'playwright-report-auth',
|
||||
'screenshots-temp',
|
||||
'videos-temp',
|
||||
];
|
||||
|
||||
for (const dir of tempDirs) {
|
||||
try {
|
||||
const fullPath = path.join(process.cwd(), dir);
|
||||
await fs.access(fullPath);
|
||||
// Directory exists, but don't delete it as it may contain useful debug info
|
||||
console.log(`📁 Preserved test artifacts in: ${dir}`);
|
||||
} catch {
|
||||
// Directory doesn't exist, which is fine
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Temporary files cleanup completed');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Temporary files cleanup had issues:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate test summary report
|
||||
*/
|
||||
async function generateTestSummary(): Promise<void> {
|
||||
console.log('📊 Generating test summary...');
|
||||
|
||||
try {
|
||||
const fs = await import('fs').then(m => m.promises);
|
||||
const path = await import('path');
|
||||
|
||||
// Check if test results exist
|
||||
const reportPath = path.join(process.cwd(), 'playwright-report-auth.json');
|
||||
|
||||
try {
|
||||
await fs.access(reportPath);
|
||||
const reportData = await fs.readFile(reportPath, 'utf-8');
|
||||
const report = JSON.parse(reportData);
|
||||
|
||||
// Generate summary
|
||||
const summary = {
|
||||
timestamp: new Date().toISOString(),
|
||||
testType: 'Authentication Debug',
|
||||
totalTests:
|
||||
report.suites?.reduce(
|
||||
(total: number, suite: { specs?: unknown[] }) =>
|
||||
total + (suite.specs?.length || 0),
|
||||
0
|
||||
) || 0,
|
||||
passedTests: 0,
|
||||
failedTests: 0,
|
||||
skippedTests: 0,
|
||||
duration: report.stats?.duration || 0,
|
||||
environment: {
|
||||
nodeVersion: process.version,
|
||||
platform: process.platform,
|
||||
ci: !!process.env.CI,
|
||||
},
|
||||
};
|
||||
|
||||
// Count test results
|
||||
if (report.suites) {
|
||||
for (const suite of report.suites) {
|
||||
if (suite.specs) {
|
||||
for (const spec of suite.specs) {
|
||||
if (spec.tests) {
|
||||
for (const test of spec.tests) {
|
||||
switch (test.status) {
|
||||
case 'passed':
|
||||
summary.passedTests++;
|
||||
break;
|
||||
case 'failed':
|
||||
summary.failedTests++;
|
||||
break;
|
||||
case 'skipped':
|
||||
summary.skippedTests++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save summary
|
||||
const summaryPath = path.join(process.cwd(), 'auth-debug-summary.json');
|
||||
await fs.writeFile(summaryPath, JSON.stringify(summary, null, 2));
|
||||
|
||||
console.log('📈 Test Summary:');
|
||||
console.log(` Total Tests: ${summary.totalTests}`);
|
||||
console.log(` Passed: ${summary.passedTests}`);
|
||||
console.log(` Failed: ${summary.failedTests}`);
|
||||
console.log(` Skipped: ${summary.skippedTests}`);
|
||||
console.log(` Duration: ${summary.duration}ms`);
|
||||
console.log(` Summary saved to: auth-debug-summary.json`);
|
||||
} catch (_error) {
|
||||
console.warn('⚠️ Could not find test report for summary generation');
|
||||
}
|
||||
|
||||
console.log('✅ Test summary generation completed');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Test summary generation had issues:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up test artifacts but preserve important debug information
|
||||
*/
|
||||
async function cleanupTestArtifacts(): Promise<void> {
|
||||
console.log('🧹 Managing test artifacts...');
|
||||
|
||||
try {
|
||||
const fs = await import('fs').then(m => m.promises);
|
||||
const path = await import('path');
|
||||
|
||||
// Archive old test results if they exist
|
||||
const testResultsDir = 'test-results-auth';
|
||||
const archiveDir = 'test-results-archive';
|
||||
|
||||
try {
|
||||
await fs.access(testResultsDir);
|
||||
|
||||
// Create archive directory if it doesn't exist
|
||||
try {
|
||||
await fs.mkdir(archiveDir, { recursive: true });
|
||||
} catch {
|
||||
// Directory might already exist
|
||||
}
|
||||
|
||||
// Move current results to archive with timestamp
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
const archivePath = path.join(archiveDir, `auth-debug-${timestamp}`);
|
||||
|
||||
await fs.rename(testResultsDir, archivePath);
|
||||
console.log(`📦 Archived test results to: ${archivePath}`);
|
||||
} catch {
|
||||
// No test results to archive
|
||||
}
|
||||
|
||||
console.log('✅ Test artifacts management completed');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Test artifacts cleanup had issues:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log final status and cleanup recommendations
|
||||
*/
|
||||
async function logFinalStatus(): Promise<void> {
|
||||
console.log('📋 Auth Debug Test Session Complete');
|
||||
console.log('');
|
||||
console.log('📁 Available Reports:');
|
||||
console.log(' • HTML Report: playwright-report-auth/index.html');
|
||||
console.log(' • JSON Report: playwright-report-auth.json');
|
||||
console.log(' • Summary: auth-debug-summary.json');
|
||||
console.log('');
|
||||
console.log('🔧 Debug Commands:');
|
||||
console.log(
|
||||
' • View HTML report: npx playwright show-report playwright-report-auth'
|
||||
);
|
||||
console.log(
|
||||
' • Run specific test: bunx playwright test auth-debug.spec.ts --debug'
|
||||
);
|
||||
console.log(' • Interactive mode: make test-e2e-ui');
|
||||
console.log('');
|
||||
console.log('🧹 Cleanup Status:');
|
||||
console.log(' • Test users: Cleaned up');
|
||||
console.log(' • Temporary files: Preserved for debugging');
|
||||
console.log(' • Test artifacts: Archived');
|
||||
console.log('');
|
||||
|
||||
// Check for failed tests and provide guidance
|
||||
try {
|
||||
const fs = await import('fs').then(m => m.promises);
|
||||
const path = await import('path');
|
||||
const summaryPath = path.join(process.cwd(), 'auth-debug-summary.json');
|
||||
|
||||
const summaryData = await fs.readFile(summaryPath, 'utf-8');
|
||||
const summary = JSON.parse(summaryData);
|
||||
|
||||
if (summary.failedTests > 0) {
|
||||
console.log('⚠️ Test Failures Detected:');
|
||||
console.log(` ${summary.failedTests} test(s) failed`);
|
||||
console.log(' Check the HTML report for detailed failure information');
|
||||
console.log(' Use --debug flag to interactively debug failing tests');
|
||||
console.log('');
|
||||
} else if (summary.passedTests > 0) {
|
||||
console.log('✅ All Authentication Tests Passed!');
|
||||
console.log(' Authentication flows are working correctly');
|
||||
console.log('');
|
||||
}
|
||||
} catch {
|
||||
// Summary file might not exist
|
||||
}
|
||||
|
||||
console.log('🎯 Next Steps:');
|
||||
console.log(' • Review test reports for any issues');
|
||||
console.log(' • Update authentication tests as features evolve');
|
||||
console.log(' • Run tests regularly in CI/CD pipeline');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Emergency cleanup in case of critical errors
|
||||
*/
|
||||
async function emergencyCleanup(): Promise<void> {
|
||||
console.log('🚨 Running emergency cleanup...');
|
||||
|
||||
try {
|
||||
// Force cleanup of any hanging processes or connections
|
||||
// This is a safety net for test environments
|
||||
|
||||
console.log('✅ Emergency cleanup completed');
|
||||
} catch (error) {
|
||||
console.error('❌ Emergency cleanup failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute teardown
|
||||
export default async function (config: GlobalTeardownConfig) {
|
||||
try {
|
||||
await globalTeardown(config);
|
||||
} catch (_error) {
|
||||
console.error('❌ Teardown failed, running emergency cleanup...');
|
||||
await emergencyCleanup();
|
||||
}
|
||||
}
|
||||
@@ -1,390 +0,0 @@
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Authentication Debug and Validation', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
// Wait for login form to be ready
|
||||
await page.waitForSelector('input[type="email"]', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('should validate admin user exists in system', async ({ page }) => {
|
||||
// Check if admin user exists by attempting login
|
||||
await page.fill('input[type="email"]', 'admin@localhost');
|
||||
await page.fill('input[type="password"]', 'admin123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should successfully login and reach main app
|
||||
await expect(page.locator('h1')).toContainText('Medication Reminder', {
|
||||
timeout: 15000,
|
||||
});
|
||||
await expect(page.locator('text=Admin')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Verify admin role and permissions
|
||||
await page.click('button:has-text("Admin")');
|
||||
await expect(page.locator('text=Admin Interface')).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
await expect(page.locator('text=User Management')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should validate email format with localhost domain', async ({
|
||||
page,
|
||||
}) => {
|
||||
const testEmails = [
|
||||
{ email: 'admin@localhost', valid: true },
|
||||
{ email: 'user@localhost', valid: true },
|
||||
{ email: 'test@example.com', valid: true },
|
||||
{ email: 'invalid-email', valid: false },
|
||||
{ email: '@localhost', valid: false },
|
||||
{ email: 'user@', valid: false },
|
||||
{ email: '', valid: false },
|
||||
];
|
||||
|
||||
for (const { email, valid } of testEmails) {
|
||||
console.log(`Testing email validation for: ${email}`);
|
||||
|
||||
// Clear form
|
||||
await page.fill('input[type="email"]', '');
|
||||
await page.fill('input[type="password"]', '');
|
||||
|
||||
// Fill email
|
||||
await page.fill('input[type="email"]', email);
|
||||
await page.fill('input[type="password"]', 'testpass123');
|
||||
|
||||
// Try to submit
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
if (valid) {
|
||||
// Should not show validation error for valid emails
|
||||
await expect(page.locator('text=Invalid email format')).not.toBeVisible(
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
} else {
|
||||
// Should show validation error for invalid emails
|
||||
await expect(page.locator('text=Invalid')).toBeVisible({
|
||||
timeout: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
// Wait a bit between tests and reload to reset state
|
||||
await page.waitForTimeout(1000);
|
||||
await page.reload();
|
||||
await page.waitForSelector('input[type="email"]');
|
||||
}
|
||||
});
|
||||
|
||||
test('should validate user creation with password', async ({ page }) => {
|
||||
// Go to registration
|
||||
await page.click('text=Register');
|
||||
await page.waitForSelector('input[name="username"]', { timeout: 5000 });
|
||||
|
||||
// Test user data with timestamp to ensure uniqueness
|
||||
const timestamp = Date.now();
|
||||
const testUser = {
|
||||
email: `debug-test-${timestamp}@localhost`,
|
||||
username: `debugtest${timestamp}`,
|
||||
password: 'DebugTest123!',
|
||||
};
|
||||
|
||||
console.log(`Testing user creation for: ${testUser.email}`);
|
||||
|
||||
// Fill registration form
|
||||
await page.fill('input[type="email"]', testUser.email);
|
||||
await page.fill('input[name="username"]', testUser.username);
|
||||
await page.fill('input[type="password"]', testUser.password);
|
||||
|
||||
// Submit registration
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should show success or verification message
|
||||
await expect(
|
||||
page
|
||||
.locator('text=verification')
|
||||
.or(page.locator('text=registered'))
|
||||
.or(page.locator('text=success'))
|
||||
).toBeVisible({ timeout: 10000 });
|
||||
});
|
||||
|
||||
test('should handle OAuth user creation flow', async ({ page }) => {
|
||||
// Check OAuth buttons are present
|
||||
await expect(page.locator('button:has-text("Google")')).toBeVisible({
|
||||
timeout: 5000,
|
||||
});
|
||||
await expect(page.locator('button:has-text("GitHub")')).toBeVisible({
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
// Store current URL to verify navigation attempt
|
||||
const currentUrl = page.url();
|
||||
|
||||
// Click OAuth button (won't actually authenticate in test)
|
||||
await page.click('button:has-text("Google")');
|
||||
|
||||
// Should either redirect to OAuth provider or show error in test environment
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Verify some action was taken (URL change or error message)
|
||||
const newUrl = page.url();
|
||||
const hasError = await page.locator('text=error').isVisible();
|
||||
|
||||
// One of these should be true: URL changed (redirect) or error shown
|
||||
const actionTaken = newUrl !== currentUrl || hasError;
|
||||
expect(actionTaken).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should validate database connection status', async ({ page }) => {
|
||||
// Login as admin to access system status
|
||||
await page.fill('input[type="email"]', 'admin@localhost');
|
||||
await page.fill('input[type="password"]', 'admin123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await expect(page.locator('h1')).toContainText('Medication Reminder', {
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
// Check if there's a system status indicator
|
||||
const statusIndicator = page.locator('[data-testid="system-status"]');
|
||||
const statusVisible = await statusIndicator.isVisible();
|
||||
|
||||
if (statusVisible) {
|
||||
await expect(statusIndicator).toContainText('Connected');
|
||||
console.log('System status indicator found and shows: Connected');
|
||||
} else {
|
||||
console.log(
|
||||
'System status indicator not found - this is optional functionality'
|
||||
);
|
||||
}
|
||||
|
||||
// Alternative: Check if app loads successfully (indicates DB connection)
|
||||
await expect(page.locator('button:has-text("Add Medication")')).toBeVisible(
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
console.log(
|
||||
'App loaded successfully - database connection presumed working'
|
||||
);
|
||||
});
|
||||
|
||||
test('should validate password strength requirements', async ({ page }) => {
|
||||
await page.click('text=Register');
|
||||
await page.waitForSelector('input[name="username"]', { timeout: 5000 });
|
||||
|
||||
const weakPasswords = [
|
||||
{ password: '123', description: 'too short' },
|
||||
{ password: 'password', description: 'common word' },
|
||||
{ password: 'admin', description: 'common admin' },
|
||||
{ password: 'abc123', description: 'simple pattern' },
|
||||
{ password: 'PASSWORD', description: 'all caps, no numbers' },
|
||||
];
|
||||
|
||||
const strongPasswords = [
|
||||
{
|
||||
password: 'StrongPass123!',
|
||||
description: 'mixed case, numbers, symbols',
|
||||
},
|
||||
{
|
||||
password: 'MySecure@Password1',
|
||||
description: 'long with special chars',
|
||||
},
|
||||
{ password: 'Complex#Pass9', description: 'complex pattern' },
|
||||
];
|
||||
|
||||
// Test weak passwords
|
||||
for (const { password, description } of weakPasswords) {
|
||||
console.log(`Testing weak password (${description}): ${password}`);
|
||||
|
||||
const timestamp = Date.now();
|
||||
await page.fill('input[type="email"]', `test${timestamp}@localhost`);
|
||||
await page.fill('input[name="username"]', `testuser${timestamp}`);
|
||||
await page.fill('input[type="password"]', password);
|
||||
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should show password strength error
|
||||
const errorVisible = await page
|
||||
.locator('text=Password must')
|
||||
.or(page.locator('text=weak'))
|
||||
.or(page.locator('text=strength'))
|
||||
.isVisible();
|
||||
if (!errorVisible) {
|
||||
console.log(
|
||||
`Warning: Password strength validation may not be implemented for: ${password}`
|
||||
);
|
||||
}
|
||||
|
||||
// Clear form for next test
|
||||
await page.fill('input[type="password"]', '');
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
// Test strong passwords
|
||||
for (const { password, description } of strongPasswords) {
|
||||
console.log(`Testing strong password (${description}): ${password}`);
|
||||
|
||||
const timestamp = Date.now();
|
||||
await page.fill('input[type="email"]', `strong${timestamp}@localhost`);
|
||||
await page.fill('input[name="username"]', `stronguser${timestamp}`);
|
||||
await page.fill('input[type="password"]', password);
|
||||
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should not show password strength error, but might show other validation
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
const hasPasswordError = await page
|
||||
.locator('text=Password must')
|
||||
.or(page.locator('text=weak'))
|
||||
.isVisible();
|
||||
if (hasPasswordError) {
|
||||
console.log(`Unexpected: Strong password rejected: ${password}`);
|
||||
}
|
||||
|
||||
// Clear form for next test
|
||||
await page.fill('input[type="password"]', '');
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
});
|
||||
|
||||
test('should validate session persistence', async ({ page }) => {
|
||||
console.log('Testing session persistence...');
|
||||
|
||||
// Login
|
||||
await page.fill('input[type="email"]', 'admin@localhost');
|
||||
await page.fill('input[type="password"]', 'admin123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await expect(page.locator('h1')).toContainText('Medication Reminder', {
|
||||
timeout: 15000,
|
||||
});
|
||||
console.log('Initial login successful');
|
||||
|
||||
// Refresh page
|
||||
await page.reload();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Should still be logged in
|
||||
try {
|
||||
await expect(page.locator('h1')).toContainText('Medication Reminder', {
|
||||
timeout: 10000,
|
||||
});
|
||||
await expect(page.locator('text=Admin')).toBeVisible({ timeout: 5000 });
|
||||
console.log(
|
||||
'Session persistence verified - user remains logged in after refresh'
|
||||
);
|
||||
} catch (_error) {
|
||||
console.log(
|
||||
'Session persistence not implemented - user was logged out after refresh'
|
||||
);
|
||||
// This might be expected behavior depending on implementation
|
||||
await expect(page.locator('input[type="email"]')).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('should handle invalid login attempts', async ({ page }) => {
|
||||
const invalidCredentials = [
|
||||
{
|
||||
email: 'nonexistent@localhost',
|
||||
password: 'password123',
|
||||
type: 'nonexistent user',
|
||||
},
|
||||
{
|
||||
email: 'admin@localhost',
|
||||
password: 'wrongpassword',
|
||||
type: 'wrong password',
|
||||
},
|
||||
{
|
||||
email: 'invalid-email',
|
||||
password: 'password123',
|
||||
type: 'invalid email format',
|
||||
},
|
||||
{ email: '', password: 'password123', type: 'empty email' },
|
||||
{ email: 'admin@localhost', password: '', type: 'empty password' },
|
||||
];
|
||||
|
||||
for (const { email, password, type } of invalidCredentials) {
|
||||
console.log(`Testing invalid login: ${type}`);
|
||||
|
||||
await page.fill('input[type="email"]', email);
|
||||
await page.fill('input[type="password"]', password);
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Wait for response
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Should show error message or stay on login page
|
||||
const hasError = await page
|
||||
.locator('text=Invalid')
|
||||
.or(page.locator('text=error'))
|
||||
.or(page.locator('text=failed'))
|
||||
.isVisible();
|
||||
const staysOnLogin = await page
|
||||
.locator('input[type="email"]')
|
||||
.isVisible();
|
||||
|
||||
if (!hasError && !staysOnLogin) {
|
||||
console.log(`Warning: No clear error indication for ${type}`);
|
||||
}
|
||||
|
||||
// Should not redirect to main app
|
||||
const redirectedToApp = await page
|
||||
.locator('h1:has-text("Medication Reminder")')
|
||||
.isVisible();
|
||||
expect(redirectedToApp).toBeFalsy();
|
||||
|
||||
// Clear form for next test
|
||||
await page.fill('input[type="email"]', '');
|
||||
await page.fill('input[type="password"]', '');
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
});
|
||||
|
||||
test('should validate user lookup functionality', async ({ page }) => {
|
||||
console.log('Testing user lookup functionality...');
|
||||
|
||||
// Login as admin first
|
||||
await page.fill('input[type="email"]', 'admin@localhost');
|
||||
await page.fill('input[type="password"]', 'admin123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await expect(page.locator('h1')).toContainText('Medication Reminder', {
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
// Open admin interface
|
||||
await page.click('button:has-text("Admin")');
|
||||
await expect(page.locator('text=User Management')).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// Should show admin user in user list
|
||||
await expect(page.locator('text=admin@localhost')).toBeVisible({
|
||||
timeout: 5000,
|
||||
});
|
||||
console.log('Admin user found in user list');
|
||||
|
||||
// Test user search if available
|
||||
const searchBox = page
|
||||
.locator('input[placeholder*="search"]')
|
||||
.or(page.locator('input[type="search"]'));
|
||||
const searchVisible = await searchBox.isVisible();
|
||||
|
||||
if (searchVisible) {
|
||||
console.log('Search functionality found, testing...');
|
||||
await searchBox.fill('admin');
|
||||
await page.waitForTimeout(1000); // Allow for search debouncing
|
||||
await expect(page.locator('text=admin@localhost')).toBeVisible();
|
||||
console.log('Search functionality works correctly');
|
||||
} else {
|
||||
console.log('Search functionality not implemented - this is optional');
|
||||
}
|
||||
|
||||
// Test user count or list functionality
|
||||
const userRows = page.locator(
|
||||
'tr:has-text("@"), .user-item, [data-testid*="user"]'
|
||||
);
|
||||
const userCount = await userRows.count();
|
||||
console.log(`Found ${userCount} users in the system`);
|
||||
|
||||
expect(userCount).toBeGreaterThan(0); // At least admin should be present
|
||||
});
|
||||
});
|
||||
@@ -1,158 +0,0 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Specialized Playwright configuration for authentication debug tests
|
||||
* Optimized for debugging auth flows with extended timeouts and detailed reporting
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './',
|
||||
testMatch: 'tests/e2e/auth-debug.spec.ts',
|
||||
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: false, // Auth tests should run sequentially to avoid conflicts
|
||||
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : 1, // Auth tests work better with single worker
|
||||
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: [
|
||||
['html', { outputFolder: 'playwright-report-auth' }],
|
||||
['json', { outputFile: 'playwright-report-auth.json' }],
|
||||
['list'],
|
||||
['junit', { outputFile: 'playwright-auth-results.xml' }],
|
||||
],
|
||||
|
||||
/* Shared settings for all the projects below. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: 'http://localhost:8080',
|
||||
|
||||
/* Collect trace when retrying the failed test. */
|
||||
trace: 'retain-on-failure',
|
||||
|
||||
/* Take screenshot on failure */
|
||||
screenshot: 'only-on-failure',
|
||||
|
||||
/* Record video on failure */
|
||||
video: 'retain-on-failure',
|
||||
|
||||
/* Extended timeouts for auth operations */
|
||||
actionTimeout: 15000,
|
||||
navigationTimeout: 30000,
|
||||
|
||||
/* Ignore HTTPS errors */
|
||||
ignoreHTTPSErrors: true,
|
||||
|
||||
/* Accept downloads */
|
||||
acceptDownloads: false,
|
||||
|
||||
/* Viewport settings */
|
||||
viewport: { width: 1280, height: 720 },
|
||||
|
||||
/* Locale for testing */
|
||||
locale: 'en-US',
|
||||
|
||||
/* Timezone for consistent testing */
|
||||
timezoneId: 'America/New_York',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'auth-debug-chromium',
|
||||
use: {
|
||||
...devices['Desktop Chrome'],
|
||||
// Additional Chrome flags for debugging
|
||||
launchOptions: {
|
||||
args: [
|
||||
'--disable-web-security',
|
||||
'--disable-features=VizDisplayCompositor',
|
||||
'--no-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'auth-debug-firefox',
|
||||
use: {
|
||||
...devices['Desktop Firefox'],
|
||||
// Firefox specific settings
|
||||
launchOptions: {
|
||||
firefoxUserPrefs: {
|
||||
'security.tls.insecure_fallback_hosts': 'localhost',
|
||||
'network.stricttransportsecurity.preloadlist': false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'auth-debug-webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
|
||||
/* Test against mobile viewports for responsive auth */
|
||||
{
|
||||
name: 'auth-debug-mobile-chrome',
|
||||
use: { ...devices['Pixel 5'] },
|
||||
},
|
||||
{
|
||||
name: 'auth-debug-mobile-safari',
|
||||
use: { ...devices['iPhone 12'] },
|
||||
},
|
||||
],
|
||||
|
||||
/* Global setup and teardown */
|
||||
globalSetup: './auth-debug-setup.ts',
|
||||
globalTeardown: './auth-debug-teardown.ts',
|
||||
|
||||
/* Test timeout for auth operations */
|
||||
timeout: 60000, // 1 minute per test
|
||||
expect: {
|
||||
timeout: 10000, // 10 seconds for assertions
|
||||
},
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: [
|
||||
{
|
||||
command: 'bun run dev',
|
||||
port: 8080,
|
||||
timeout: 120000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
env: {
|
||||
NODE_ENV: 'test',
|
||||
VITE_COUCHDB_URL: 'http://localhost:5984',
|
||||
VITE_COUCHDB_USERNAME: 'admin',
|
||||
VITE_COUCHDB_PASSWORD: 'password',
|
||||
},
|
||||
},
|
||||
{
|
||||
command: 'docker-compose -f docker/docker-compose.yaml up -d',
|
||||
timeout: 60000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
],
|
||||
|
||||
/* Output directories */
|
||||
outputDir: 'test-results-auth/',
|
||||
|
||||
/* Metadata for reporting */
|
||||
metadata: {
|
||||
testType: 'Authentication Debug',
|
||||
environment: process.env.NODE_ENV || 'test',
|
||||
version: process.env.APP_VERSION || 'development',
|
||||
author: 'Medication Reminder App Team',
|
||||
description:
|
||||
'Comprehensive authentication flow debugging and validation tests',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user