Imporve testing
This commit is contained in:
476
frontend/TESTING_ONBOARDING_GUIDE.md
Normal file
476
frontend/TESTING_ONBOARDING_GUIDE.md
Normal file
@@ -0,0 +1,476 @@
|
||||
# 🧪 Complete Onboarding Flow Testing Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to test the complete user registration and onboarding flow using **Playwright with Chrome** (or any browser) in your Bakery-IA application.
|
||||
|
||||
## 📦 Prerequisites
|
||||
|
||||
1. **Install dependencies** (if not already done):
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
```
|
||||
|
||||
2. **Install Playwright browsers** (including Chrome):
|
||||
```bash
|
||||
npx playwright install chromium
|
||||
# Or install all browsers
|
||||
npx playwright install
|
||||
```
|
||||
|
||||
3. **Set up environment variables** (optional):
|
||||
```bash
|
||||
# Create .env file in frontend directory
|
||||
echo "TEST_USER_EMAIL=ualfaro@gmail.com" >> .env
|
||||
echo "TEST_USER_PASSWORD=Admin123" >> .env
|
||||
```
|
||||
|
||||
## 🚀 Running the Tests
|
||||
|
||||
### Option 1: Run All Onboarding Tests in Chrome (Headless)
|
||||
|
||||
```bash
|
||||
npm run test:e2e -- --project=chromium tests/onboarding/
|
||||
```
|
||||
|
||||
### Option 2: Run with Visible Browser Window (Headed Mode)
|
||||
|
||||
**This is the best option to see what's happening!**
|
||||
|
||||
```bash
|
||||
npm run test:e2e:headed -- --project=chromium tests/onboarding/
|
||||
```
|
||||
|
||||
### Option 3: Run in Debug Mode (Step-by-Step)
|
||||
|
||||
```bash
|
||||
npm run test:e2e:debug -- tests/onboarding/complete-registration-flow.spec.ts
|
||||
```
|
||||
|
||||
This will:
|
||||
- Open Playwright Inspector
|
||||
- Allow you to step through each test action
|
||||
- Pause on failures
|
||||
|
||||
### Option 4: Run with Interactive UI Mode
|
||||
|
||||
```bash
|
||||
npm run test:e2e:ui -- --project=chromium
|
||||
```
|
||||
|
||||
This opens Playwright's UI where you can:
|
||||
- Select specific tests to run
|
||||
- Watch tests in real-time
|
||||
- Time-travel through test steps
|
||||
- See screenshots and traces
|
||||
|
||||
### Option 5: Run Specific Test
|
||||
|
||||
```bash
|
||||
# Run only the complete registration flow test
|
||||
npx playwright test tests/onboarding/complete-registration-flow.spec.ts --headed --project=chromium
|
||||
|
||||
# Run only wizard navigation tests
|
||||
npx playwright test tests/onboarding/wizard-navigation.spec.ts --headed --project=chromium
|
||||
|
||||
# Run only file upload tests
|
||||
npx playwright test tests/onboarding/file-upload.spec.ts --headed --project=chromium
|
||||
```
|
||||
|
||||
## 🎯 What Gets Tested
|
||||
|
||||
### 1. Complete Registration Flow (`complete-registration-flow.spec.ts`)
|
||||
|
||||
**Phase 1: User Registration**
|
||||
- ✅ Navigate to registration page
|
||||
- ✅ Fill basic information (name, email, password)
|
||||
- ✅ Password validation (strength requirements)
|
||||
- ✅ Password confirmation matching
|
||||
- ✅ Terms and conditions acceptance
|
||||
- ✅ Marketing and analytics consent
|
||||
- ✅ Subscription plan selection
|
||||
- ✅ Payment information entry
|
||||
- ✅ Redirect to onboarding
|
||||
|
||||
**Phase 2: Onboarding Wizard**
|
||||
- ✅ Bakery type selection (Production/Retail/Mixed)
|
||||
- ✅ Tenant setup (bakery registration)
|
||||
- ✅ Sales data upload (or skip)
|
||||
- ✅ Inventory review
|
||||
- ✅ Initial stock entry
|
||||
- ✅ Suppliers setup
|
||||
- ✅ Recipes setup (conditional)
|
||||
- ✅ ML training
|
||||
- ✅ Completion and redirect to dashboard
|
||||
|
||||
**Validation Tests**
|
||||
- ✅ Weak password rejection
|
||||
- ✅ Invalid email format
|
||||
- ✅ Password mismatch detection
|
||||
- ✅ Required terms acceptance
|
||||
|
||||
### 2. Wizard Navigation (`wizard-navigation.spec.ts`)
|
||||
|
||||
- ✅ Step progression
|
||||
- ✅ Backward navigation
|
||||
- ✅ Progress indicator visibility
|
||||
- ✅ Skip functionality
|
||||
- ✅ Step validation
|
||||
|
||||
### 3. File Upload (`file-upload.spec.ts`)
|
||||
|
||||
- ✅ CSV file upload
|
||||
- ✅ Drag and drop
|
||||
- ✅ File type validation
|
||||
- ✅ Invalid file rejection
|
||||
|
||||
## 📁 Test File Structure
|
||||
|
||||
```
|
||||
frontend/tests/
|
||||
├── auth.setup.ts # Authentication setup
|
||||
├── helpers/
|
||||
│ └── utils.ts # Test utilities
|
||||
└── onboarding/
|
||||
├── complete-registration-flow.spec.ts # ⭐ Full flow test (NEW)
|
||||
├── wizard-navigation.spec.ts # Wizard step navigation
|
||||
└── file-upload.spec.ts # File upload tests
|
||||
```
|
||||
|
||||
## 🎬 Step-by-Step: How to Test Manually with Playwright
|
||||
|
||||
### Method 1: Using Playwright Codegen (Record Your Actions)
|
||||
|
||||
This is perfect for creating new tests or understanding the flow:
|
||||
|
||||
```bash
|
||||
# Start the dev server first
|
||||
npm run dev
|
||||
|
||||
# In another terminal, start Playwright codegen
|
||||
npm run test:e2e:codegen
|
||||
```
|
||||
|
||||
Then:
|
||||
1. Navigate to `http://localhost:5173/register`
|
||||
2. Go through the registration process manually
|
||||
3. Playwright will record all your actions
|
||||
4. Copy the generated code to create new tests
|
||||
|
||||
### Method 2: Run Existing Test in Headed Mode
|
||||
|
||||
```bash
|
||||
# Make sure your dev server is running
|
||||
npm run dev
|
||||
|
||||
# In another terminal, run the test with Chrome visible
|
||||
npm run test:e2e:headed -- --project=chromium tests/onboarding/complete-registration-flow.spec.ts
|
||||
```
|
||||
|
||||
You'll see Chrome open and automatically:
|
||||
1. Navigate to registration
|
||||
2. Fill in the form
|
||||
3. Select a plan
|
||||
4. Complete payment
|
||||
5. Go through onboarding steps
|
||||
6. Reach the dashboard
|
||||
|
||||
## 🐛 Debugging Failed Tests
|
||||
|
||||
### View Test Report
|
||||
|
||||
After tests run, view the HTML report:
|
||||
|
||||
```bash
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
### View Screenshots
|
||||
|
||||
Failed tests automatically capture screenshots:
|
||||
|
||||
```
|
||||
frontend/test-results/
|
||||
├── screenshots/
|
||||
│ └── onboarding-stuck-step-X.png
|
||||
└── onboarding-completed.png
|
||||
```
|
||||
|
||||
### View Test Traces
|
||||
|
||||
For detailed debugging with timeline:
|
||||
|
||||
```bash
|
||||
# Run with trace enabled
|
||||
npx playwright test --trace on
|
||||
|
||||
# View trace
|
||||
npx playwright show-trace trace.zip
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Change Base URL
|
||||
|
||||
Edit `frontend/playwright.config.ts`:
|
||||
|
||||
```typescript
|
||||
use: {
|
||||
baseURL: 'http://localhost:5173', // Change this
|
||||
}
|
||||
```
|
||||
|
||||
Or set environment variable:
|
||||
|
||||
```bash
|
||||
export PLAYWRIGHT_BASE_URL=http://your-app.com
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
### Run Against Different Environment
|
||||
|
||||
```bash
|
||||
# Test against staging
|
||||
PLAYWRIGHT_BASE_URL=https://staging.bakery-ia.com npm run test:e2e:headed
|
||||
|
||||
# Test against production (careful!)
|
||||
PLAYWRIGHT_BASE_URL=https://app.bakery-ia.com npm run test:e2e
|
||||
```
|
||||
|
||||
### Test with Different Browsers
|
||||
|
||||
```bash
|
||||
# Firefox
|
||||
npm run test:e2e:headed -- --project=firefox
|
||||
|
||||
# Safari (WebKit)
|
||||
npm run test:e2e:headed -- --project=webkit
|
||||
|
||||
# Mobile Chrome
|
||||
npm run test:e2e:headed -- --project="Mobile Chrome"
|
||||
|
||||
# All browsers
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
## 💡 Tips & Best Practices
|
||||
|
||||
### 1. Run Dev Server First
|
||||
|
||||
The tests expect the app to be running. Start it with:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Or let Playwright auto-start it (configured in `playwright.config.ts`):
|
||||
|
||||
```typescript
|
||||
webServer: {
|
||||
command: 'npm run dev',
|
||||
url: 'http://localhost:5173',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Use Headed Mode for Debugging
|
||||
|
||||
Always use `--headed` when developing tests:
|
||||
|
||||
```bash
|
||||
npm run test:e2e:headed
|
||||
```
|
||||
|
||||
### 3. Use `.only` for Single Test
|
||||
|
||||
Temporarily run just one test:
|
||||
|
||||
```typescript
|
||||
test.only('should complete onboarding', async ({ page }) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Use `.skip` to Skip Tests
|
||||
|
||||
Skip flaky tests temporarily:
|
||||
|
||||
```typescript
|
||||
test.skip('flaky test', async ({ page }) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
### 5. Slow Down Tests for Visibility
|
||||
|
||||
Add `page.setDefaultTimeout()` or use `slow`:
|
||||
|
||||
```typescript
|
||||
test('my test', async ({ page }) => {
|
||||
test.slow(); // Triples the timeout
|
||||
await page.waitForTimeout(1000); // Wait 1 second
|
||||
});
|
||||
```
|
||||
|
||||
## 🔐 Testing with Authentication
|
||||
|
||||
The tests use authenticated state stored in `tests/.auth/user.json`. This is created by `auth.setup.ts`.
|
||||
|
||||
To update test credentials:
|
||||
|
||||
```bash
|
||||
# Edit the file
|
||||
vim frontend/tests/auth.setup.ts
|
||||
|
||||
# Or set environment variables
|
||||
export TEST_USER_EMAIL=your.email@example.com
|
||||
export TEST_USER_PASSWORD=YourPassword123
|
||||
```
|
||||
|
||||
## 📊 Test Data
|
||||
|
||||
### Default Test User (for existing tests)
|
||||
|
||||
```
|
||||
Email: ualfaro@gmail.com
|
||||
Password: Admin123
|
||||
```
|
||||
|
||||
### New Test Users (auto-generated)
|
||||
|
||||
The `complete-registration-flow.spec.ts` test creates unique users on each run:
|
||||
|
||||
```javascript
|
||||
const testUser = {
|
||||
fullName: `Test User ${Date.now()}`,
|
||||
email: `test.user.${Date.now()}@bakery-test.com`,
|
||||
password: 'SecurePass123!@#'
|
||||
};
|
||||
```
|
||||
|
||||
### Stripe Test Cards
|
||||
|
||||
For payment testing, use Stripe test cards:
|
||||
|
||||
```
|
||||
Success: 4242 4242 4242 4242
|
||||
Decline: 4000 0000 0000 0002
|
||||
3D Secure: 4000 0027 6000 3184
|
||||
|
||||
Expiry: Any future date (e.g., 12/34)
|
||||
CVC: Any 3 digits (e.g., 123)
|
||||
```
|
||||
|
||||
## 🎯 Common Test Scenarios
|
||||
|
||||
### Test 1: Complete Happy Path
|
||||
|
||||
```bash
|
||||
# Run the complete flow test
|
||||
npx playwright test tests/onboarding/complete-registration-flow.spec.ts:6 --headed
|
||||
```
|
||||
|
||||
Line 6 is the "should complete full registration and onboarding flow for starter plan" test.
|
||||
|
||||
### Test 2: Test Validation Errors
|
||||
|
||||
```bash
|
||||
# Run validation test
|
||||
npx playwright test tests/onboarding/complete-registration-flow.spec.ts -g "validation errors" --headed
|
||||
```
|
||||
|
||||
### Test 3: Test Backward Navigation
|
||||
|
||||
```bash
|
||||
# Run backward navigation test
|
||||
npx playwright test tests/onboarding/wizard-navigation.spec.ts -g "backward navigation" --headed
|
||||
```
|
||||
|
||||
## 📹 Recording Test Videos
|
||||
|
||||
Videos are automatically recorded on failure. To record all tests:
|
||||
|
||||
Edit `playwright.config.ts`:
|
||||
|
||||
```typescript
|
||||
use: {
|
||||
video: 'on', // or 'retain-on-failure', 'on-first-retry'
|
||||
}
|
||||
```
|
||||
|
||||
## 🌐 Testing in Different Languages
|
||||
|
||||
The app supports multiple languages. Test with different locales:
|
||||
|
||||
```bash
|
||||
# Test in Spanish (default)
|
||||
npm run test:e2e:headed
|
||||
|
||||
# Test in English
|
||||
# You'd need to click the language selector in the test
|
||||
```
|
||||
|
||||
## ❓ Troubleshooting
|
||||
|
||||
### Issue: "Timed out waiting for webServer"
|
||||
|
||||
**Solution:** Your dev server isn't starting. Run it manually:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then run tests with:
|
||||
|
||||
```bash
|
||||
PLAYWRIGHT_BASE_URL=http://localhost:5173 npm run test:e2e -- --config=playwright.config.ts
|
||||
```
|
||||
|
||||
Or edit `playwright.config.ts` and set:
|
||||
|
||||
```typescript
|
||||
webServer: {
|
||||
reuseExistingServer: true, // Use already running server
|
||||
}
|
||||
```
|
||||
|
||||
### Issue: "Test failed: element not found"
|
||||
|
||||
**Solutions:**
|
||||
1. Increase timeout: `await element.waitFor({ timeout: 10000 })`
|
||||
2. Check selectors are correct for your language
|
||||
3. Run in headed mode to see what's happening
|
||||
4. Use Playwright Inspector: `npm run test:e2e:debug`
|
||||
|
||||
### Issue: "Authentication failed"
|
||||
|
||||
**Solution:** Update test credentials in `tests/auth.setup.ts` or use environment variables.
|
||||
|
||||
### Issue: "Payment test fails"
|
||||
|
||||
**Solution:**
|
||||
- Check if bypass payment toggle is enabled in your test environment
|
||||
- Verify Stripe is configured with test keys
|
||||
- Use valid Stripe test card numbers
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- [Playwright Documentation](https://playwright.dev)
|
||||
- [Playwright Best Practices](https://playwright.dev/docs/best-practices)
|
||||
- [Playwright Debugging](https://playwright.dev/docs/debug)
|
||||
- [Playwright CI/CD](https://playwright.dev/docs/ci)
|
||||
|
||||
## 🎓 Next Steps
|
||||
|
||||
1. **Run the existing tests** to understand the flow
|
||||
2. **Use Playwright Codegen** to record additional test scenarios
|
||||
3. **Add more test cases** for edge cases (enterprise tier, production bakery, etc.)
|
||||
4. **Set up CI/CD** to run tests automatically on pull requests
|
||||
5. **Monitor test flakiness** and improve reliability
|
||||
|
||||
---
|
||||
|
||||
Happy Testing! 🚀
|
||||
|
||||
For questions or issues, check the [Playwright Discord](https://discord.gg/playwright-807756831384403968) or create an issue in the repository.
|
||||
195
frontend/TEST_COMMANDS_QUICK_REFERENCE.md
Normal file
195
frontend/TEST_COMMANDS_QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# 🚀 Quick Test Commands Reference
|
||||
|
||||
## ⚡ Most Used Commands
|
||||
|
||||
### 1. Run Tests in Chrome (Watch Mode)
|
||||
```bash
|
||||
npm run test:e2e:headed -- --project=chromium tests/onboarding/
|
||||
```
|
||||
**Use this for:** Watching tests run in a visible Chrome window
|
||||
|
||||
### 2. Run Tests in UI Mode (Best for Development)
|
||||
```bash
|
||||
npm run test:e2e:ui
|
||||
```
|
||||
**Use this for:** Interactive test development and debugging
|
||||
|
||||
### 3. Debug Specific Test
|
||||
```bash
|
||||
npm run test:e2e:debug -- tests/onboarding/complete-registration-flow.spec.ts
|
||||
```
|
||||
**Use this for:** Step-by-step debugging with Playwright Inspector
|
||||
|
||||
### 4. Record New Tests (Codegen)
|
||||
```bash
|
||||
# Start dev server first
|
||||
npm run dev
|
||||
|
||||
# In another terminal
|
||||
npm run test:e2e:codegen
|
||||
```
|
||||
**Use this for:** Recording your actions to generate test code
|
||||
|
||||
### 5. Run Complete Flow Test Only
|
||||
```bash
|
||||
npx playwright test tests/onboarding/complete-registration-flow.spec.ts --headed --project=chromium
|
||||
```
|
||||
**Use this for:** Testing the full registration + onboarding flow
|
||||
|
||||
---
|
||||
|
||||
## 📋 All Available Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `npm run test:e2e` | Run all E2E tests (headless) |
|
||||
| `npm run test:e2e:ui` | Open Playwright UI mode |
|
||||
| `npm run test:e2e:headed` | Run tests with visible browser |
|
||||
| `npm run test:e2e:debug` | Debug tests with Playwright Inspector |
|
||||
| `npm run test:e2e:report` | View last test report |
|
||||
| `npm run test:e2e:codegen` | Record actions to generate tests |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Test Specific Scenarios
|
||||
|
||||
### Test Complete Registration Flow
|
||||
```bash
|
||||
npx playwright test complete-registration-flow --headed
|
||||
```
|
||||
|
||||
### Test Wizard Navigation Only
|
||||
```bash
|
||||
npx playwright test wizard-navigation --headed
|
||||
```
|
||||
|
||||
### Test File Upload Only
|
||||
```bash
|
||||
npx playwright test file-upload --headed
|
||||
```
|
||||
|
||||
### Test with Specific Browser
|
||||
```bash
|
||||
# Chrome
|
||||
npx playwright test --project=chromium --headed
|
||||
|
||||
# Firefox
|
||||
npx playwright test --project=firefox --headed
|
||||
|
||||
# Safari
|
||||
npx playwright test --project=webkit --headed
|
||||
|
||||
# Mobile Chrome
|
||||
npx playwright test --project="Mobile Chrome" --headed
|
||||
```
|
||||
|
||||
### Run Single Test by Name
|
||||
```bash
|
||||
npx playwright test -g "should complete full registration" --headed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Debugging Commands
|
||||
|
||||
### View Last Test Report
|
||||
```bash
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
### Run with Trace
|
||||
```bash
|
||||
npx playwright test --trace on
|
||||
```
|
||||
|
||||
### View Trace File
|
||||
```bash
|
||||
npx playwright show-trace trace.zip
|
||||
```
|
||||
|
||||
### Run in Slow Motion
|
||||
```bash
|
||||
npx playwright test --headed --slow-mo=1000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Before Running Tests
|
||||
|
||||
### 1. Make Sure Dev Server is Running
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 2. Or Let Playwright Auto-Start It
|
||||
The `playwright.config.ts` is already configured to auto-start the dev server.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Change Base URL
|
||||
```bash
|
||||
PLAYWRIGHT_BASE_URL=http://localhost:5173 npm run test:e2e:headed
|
||||
```
|
||||
|
||||
### Update Test User Credentials
|
||||
Edit `frontend/tests/auth.setup.ts` or set:
|
||||
```bash
|
||||
export TEST_USER_EMAIL=your.email@example.com
|
||||
export TEST_USER_PASSWORD=YourPassword123
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Example: Full Testing Workflow
|
||||
|
||||
```bash
|
||||
# 1. Start dev server
|
||||
npm run dev
|
||||
|
||||
# 2. In another terminal, run tests in UI mode
|
||||
npm run test:e2e:ui
|
||||
|
||||
# 3. Select "complete-registration-flow.spec.ts"
|
||||
|
||||
# 4. Click "Watch" and "Show browser"
|
||||
|
||||
# 5. See the magic happen! ✨
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎬 Pro Tips
|
||||
|
||||
1. **Always use `--headed` when developing tests** - you need to see what's happening
|
||||
2. **Use UI mode for test development** - it's the best experience
|
||||
3. **Use `test.only()` to run a single test** - faster iteration
|
||||
4. **Use `page.pause()` to pause execution** - inspect state mid-test
|
||||
5. **Check test-results/ folder for screenshots** - helpful for debugging
|
||||
|
||||
---
|
||||
|
||||
## 📁 Test Files Location
|
||||
|
||||
```
|
||||
frontend/tests/onboarding/
|
||||
├── complete-registration-flow.spec.ts ← Full flow (NEW!)
|
||||
├── wizard-navigation.spec.ts ← Wizard steps
|
||||
└── file-upload.spec.ts ← File uploads
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Quick Help
|
||||
|
||||
**Command not working?**
|
||||
1. Make sure you're in the `frontend/` directory
|
||||
2. Run `npm install` to ensure dependencies are installed
|
||||
3. Run `npx playwright install chromium` to install browsers
|
||||
4. Check that dev server is running on port 5173
|
||||
|
||||
**Need more help?**
|
||||
- Read the full guide: `TESTING_ONBOARDING_GUIDE.md`
|
||||
- Check Playwright docs: https://playwright.dev
|
||||
- View test report: `npx playwright show-report`
|
||||
431
frontend/tests/onboarding/complete-registration-flow.spec.ts
Normal file
431
frontend/tests/onboarding/complete-registration-flow.spec.ts
Normal file
@@ -0,0 +1,431 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { acceptCookieConsent, waitForNavigation } from '../helpers/utils';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Complete User Registration and Onboarding Flow Test
|
||||
*
|
||||
* This test suite covers the entire journey from registration to onboarding completion:
|
||||
* 1. User Registration (3-step process: basic info, subscription, payment)
|
||||
* 2. Onboarding Wizard (multiple steps based on business type and tier)
|
||||
*/
|
||||
|
||||
test.describe('Complete Registration and Onboarding Flow', () => {
|
||||
// Generate unique test user for each test run
|
||||
const generateTestUser = () => ({
|
||||
fullName: `Test User ${Date.now()}`,
|
||||
email: `test.user.${Date.now()}@bakery-test.com`,
|
||||
password: 'SecurePass123!@#',
|
||||
plan: 'starter' // or 'professional', 'enterprise'
|
||||
});
|
||||
|
||||
test('should complete full registration and onboarding flow for starter plan', async ({ page }) => {
|
||||
const testUser = generateTestUser();
|
||||
|
||||
// ============================================
|
||||
// PHASE 1: REGISTRATION
|
||||
// ============================================
|
||||
|
||||
await test.step('Navigate to registration page', async () => {
|
||||
await page.goto('/register');
|
||||
await acceptCookieConsent(page);
|
||||
|
||||
// Verify we're on the registration page
|
||||
await expect(page.getByRole('heading', { name: /crear cuenta|create account/i })).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('Fill basic information (Step 1/3)', async () => {
|
||||
// Fill in user details
|
||||
await page.getByLabel(/nombre completo|full name/i).fill(testUser.fullName);
|
||||
await page.getByLabel(/correo|email/i).fill(testUser.email);
|
||||
|
||||
// Fill password
|
||||
await page.getByLabel(/^contraseña|^password/i).first().fill(testUser.password);
|
||||
|
||||
// Fill confirm password
|
||||
await page.getByLabel(/confirmar contraseña|confirm password/i).fill(testUser.password);
|
||||
|
||||
// Wait for password match indicator
|
||||
await expect(page.getByText(/las contraseñas coinciden|passwords match/i)).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Accept terms and conditions
|
||||
await page.getByRole('checkbox', { name: /acepto los términos|accept terms/i }).check();
|
||||
|
||||
// Optional consents
|
||||
await page.getByRole('checkbox', { name: /marketing|promociones/i }).check();
|
||||
await page.getByRole('checkbox', { name: /analytics|analíticas/i }).check();
|
||||
|
||||
// Proceed to next step
|
||||
await page.getByRole('button', { name: /siguiente|next/i }).click();
|
||||
});
|
||||
|
||||
await test.step('Select subscription plan (Step 2/3)', async () => {
|
||||
// Wait for subscription page
|
||||
await expect(page.getByRole('heading', { name: /selecciona tu plan|select.*plan/i })).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Select starter plan (default is usually selected)
|
||||
const starterPlanButton = page.getByRole('button', { name: /starter|básico/i }).first();
|
||||
if (await starterPlanButton.isVisible().catch(() => false)) {
|
||||
await starterPlanButton.click();
|
||||
}
|
||||
|
||||
// Proceed to payment
|
||||
await page.getByRole('button', { name: /siguiente|next/i }).click();
|
||||
});
|
||||
|
||||
await test.step('Complete payment information (Step 3/3)', async () => {
|
||||
// Wait for payment page
|
||||
await expect(page.getByRole('heading', { name: /información de pago|payment info/i })).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Check if bypass payment toggle exists (for testing environments)
|
||||
const bypassToggle = page.getByRole('checkbox', { name: /bypass|omitir|skip.*payment/i });
|
||||
const hasBypassOption = await bypassToggle.isVisible({ timeout: 2000 }).catch(() => false);
|
||||
|
||||
if (hasBypassOption) {
|
||||
// Enable bypass for test environment
|
||||
await bypassToggle.check();
|
||||
await page.getByRole('button', { name: /completar registro|complete registration/i }).click();
|
||||
} else {
|
||||
// Fill Stripe test card details
|
||||
const cardFrame = page.frameLocator('iframe[name*="__privateStripeFrame"]').first();
|
||||
|
||||
// Wait for Stripe iframe to load
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Fill card number (Stripe test card)
|
||||
await cardFrame.getByPlaceholder(/card number|número.*tarjeta/i).fill('4242424242424242');
|
||||
|
||||
// Fill expiry date
|
||||
await cardFrame.getByPlaceholder(/mm.*yy|expir/i).fill('1234');
|
||||
|
||||
// Fill CVC
|
||||
await cardFrame.getByPlaceholder(/cvc|cvv/i).fill('123');
|
||||
|
||||
// Fill postal code if visible
|
||||
const postalCode = cardFrame.getByPlaceholder(/postal|zip/i);
|
||||
if (await postalCode.isVisible().catch(() => false)) {
|
||||
await postalCode.fill('12345');
|
||||
}
|
||||
|
||||
// Submit payment
|
||||
await page.getByRole('button', { name: /completar registro|complete registration|submit/i }).click();
|
||||
}
|
||||
|
||||
// Wait for redirect to onboarding
|
||||
await page.waitForURL(/\/app\/onboarding/, { timeout: 15000 });
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// PHASE 2: ONBOARDING WIZARD
|
||||
// ============================================
|
||||
|
||||
await test.step('Complete onboarding wizard', async () => {
|
||||
// Wait for onboarding page to load
|
||||
await expect(page.locator('body')).toContainText(/onboarding|configuración|bienvenido/i, { timeout: 10000 });
|
||||
|
||||
// The onboarding has multiple steps, we'll navigate through them
|
||||
let stepCount = 0;
|
||||
const maxSteps = 15; // Maximum expected steps
|
||||
|
||||
while (stepCount < maxSteps) {
|
||||
// Wait a bit for the step to render
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Look for various button types that indicate progression
|
||||
const nextButton = page.getByRole('button', { name: /next|siguiente|continuar/i });
|
||||
const skipButton = page.getByRole('button', { name: /skip|omitir|saltar/i });
|
||||
const finishButton = page.getByRole('button', { name: /finish|finalizar|completar/i });
|
||||
const goToDashboardButton = page.getByRole('button', { name: /ir al panel|go to dashboard/i });
|
||||
|
||||
// Check what step we're on and fill accordingly
|
||||
const bodyText = await page.locator('body').textContent();
|
||||
|
||||
// Step: Bakery Type Selection
|
||||
if (bodyText?.match(/tipo.*panadería|bakery.*type|selecciona.*tipo/i)) {
|
||||
console.log('📍 Step: Bakery Type Selection');
|
||||
const retailOption = page.getByRole('button', { name: /retail|minorista|venta/i }).first();
|
||||
if (await retailOption.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await retailOption.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Step: Tenant Setup (Register Bakery)
|
||||
else if (bodyText?.match(/registra.*panadería|register.*bakery|datos.*negocio/i)) {
|
||||
console.log('📍 Step: Tenant Setup');
|
||||
|
||||
// Fill bakery name if not filled
|
||||
const nameInput = page.getByLabel(/nombre.*panadería|bakery.*name|nombre.*negocio/i);
|
||||
if (await nameInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
const currentValue = await nameInput.inputValue();
|
||||
if (!currentValue) {
|
||||
await nameInput.fill(`Test Bakery ${Date.now()}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill address
|
||||
const addressInput = page.getByLabel(/dirección|address/i);
|
||||
if (await addressInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
const currentValue = await addressInput.inputValue();
|
||||
if (!currentValue) {
|
||||
await addressInput.fill('Calle Test 123');
|
||||
}
|
||||
}
|
||||
|
||||
// Fill postal code
|
||||
const postalInput = page.getByLabel(/código postal|postal.*code|zip/i);
|
||||
if (await postalInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
const currentValue = await postalInput.inputValue();
|
||||
if (!currentValue) {
|
||||
await postalInput.fill('28001');
|
||||
}
|
||||
}
|
||||
|
||||
// Fill city
|
||||
const cityInput = page.getByLabel(/ciudad|city/i);
|
||||
if (await cityInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
const currentValue = await cityInput.inputValue();
|
||||
if (!currentValue) {
|
||||
await cityInput.fill('Madrid');
|
||||
}
|
||||
}
|
||||
|
||||
// Fill phone
|
||||
const phoneInput = page.getByLabel(/teléfono|phone/i);
|
||||
if (await phoneInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
const currentValue = await phoneInput.inputValue();
|
||||
if (!currentValue) {
|
||||
await phoneInput.fill('666555444');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step: Upload Sales Data
|
||||
else if (bodyText?.match(/subir.*datos|upload.*sales|archivo.*ventas/i)) {
|
||||
console.log('📍 Step: Upload Sales Data');
|
||||
|
||||
// Try to skip this step if possible
|
||||
if (await skipButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await skipButton.click();
|
||||
stepCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, we'd need to upload a test CSV file
|
||||
// For now, we'll just proceed if there's a next button
|
||||
}
|
||||
|
||||
// Step: Inventory Review
|
||||
else if (bodyText?.match(/revisar.*inventario|inventory.*review|productos/i)) {
|
||||
console.log('📍 Step: Inventory Review');
|
||||
// Usually can skip or proceed with empty
|
||||
}
|
||||
|
||||
// Step: Initial Stock Entry
|
||||
else if (bodyText?.match(/stock.*inicial|initial.*stock|cantidad/i)) {
|
||||
console.log('📍 Step: Initial Stock Entry');
|
||||
|
||||
// Look for "Set all to 0" or skip button
|
||||
const setAllZeroButton = page.getByRole('button', { name: /establecer.*0|set.*all.*0/i });
|
||||
if (await setAllZeroButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await setAllZeroButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Step: Suppliers Setup
|
||||
else if (bodyText?.match(/proveedores|suppliers/i)) {
|
||||
console.log('📍 Step: Suppliers Setup');
|
||||
// Can skip for now
|
||||
}
|
||||
|
||||
// Step: Recipes Setup
|
||||
else if (bodyText?.match(/recetas|recipes/i)) {
|
||||
console.log('📍 Step: Recipes Setup');
|
||||
// Can skip for now
|
||||
}
|
||||
|
||||
// Step: ML Training
|
||||
else if (bodyText?.match(/entrenamiento|training|modelo.*ia|ai.*model/i)) {
|
||||
console.log('📍 Step: ML Training');
|
||||
|
||||
// Look for skip to dashboard button
|
||||
if (await goToDashboardButton.isVisible({ timeout: 5000 }).catch(() => false)) {
|
||||
await goToDashboardButton.click();
|
||||
// Should redirect to dashboard
|
||||
await page.waitForURL(/\/app\/(dashboard|operations)/, { timeout: 10000 });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Step: Completion
|
||||
else if (bodyText?.match(/completado|completed|felicidades|congratulations/i)) {
|
||||
console.log('📍 Step: Completion');
|
||||
|
||||
if (await goToDashboardButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await goToDashboardButton.click();
|
||||
await page.waitForURL(/\/app\/(dashboard|operations)/, { timeout: 10000 });
|
||||
break;
|
||||
} else if (await finishButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await finishButton.click();
|
||||
await page.waitForURL(/\/app\/(dashboard|operations)/, { timeout: 10000 });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to proceed to next step
|
||||
if (await nextButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await nextButton.click();
|
||||
stepCount++;
|
||||
} else if (await skipButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await skipButton.click();
|
||||
stepCount++;
|
||||
} else if (await finishButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await finishButton.click();
|
||||
// Should redirect to dashboard
|
||||
await page.waitForURL(/\/app\/(dashboard|operations)/, { timeout: 10000 });
|
||||
break;
|
||||
} else {
|
||||
// No more navigation buttons found
|
||||
console.log('ℹ️ No more navigation buttons found, checking if we reached dashboard');
|
||||
|
||||
// Check if we're already at dashboard
|
||||
if (page.url().includes('/app/dashboard') || page.url().includes('/app/operations')) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If we can't find any buttons and we're still on onboarding, something might be wrong
|
||||
if (page.url().includes('/onboarding')) {
|
||||
console.warn('⚠️ Still on onboarding page but no navigation buttons found');
|
||||
// Take a screenshot for debugging
|
||||
await page.screenshot({ path: `test-results/onboarding-stuck-step-${stepCount}.png` });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Safety check: wait a bit between steps
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
console.log(`✅ Completed ${stepCount} onboarding steps`);
|
||||
});
|
||||
|
||||
await test.step('Verify successful onboarding completion', async () => {
|
||||
// Should be redirected to dashboard
|
||||
await expect(page).toHaveURL(/\/app\/(dashboard|operations)/, { timeout: 10000 });
|
||||
|
||||
// Verify dashboard elements are visible
|
||||
await expect(page.locator('body')).toContainText(/dashboard|panel|operaciones|operations/i, { timeout: 5000 });
|
||||
|
||||
// Take final screenshot
|
||||
await page.screenshot({ path: 'test-results/onboarding-completed.png', fullPage: true });
|
||||
});
|
||||
});
|
||||
|
||||
test('should complete onboarding with manual data entry (no file upload)', async ({ page }) => {
|
||||
const testUser = generateTestUser();
|
||||
|
||||
// Quick registration (simplified for this test)
|
||||
await page.goto('/register');
|
||||
await acceptCookieConsent(page);
|
||||
|
||||
// Fill registration form quickly
|
||||
await page.getByLabel(/nombre completo|full name/i).fill(testUser.fullName);
|
||||
await page.getByLabel(/correo|email/i).fill(testUser.email);
|
||||
await page.getByLabel(/^contraseña|^password/i).first().fill(testUser.password);
|
||||
await page.getByLabel(/confirmar contraseña|confirm password/i).fill(testUser.password);
|
||||
await page.getByRole('checkbox', { name: /acepto los términos|accept terms/i }).check();
|
||||
|
||||
// Proceed through registration
|
||||
await page.getByRole('button', { name: /siguiente|next/i }).click();
|
||||
|
||||
// Select plan (if subscription step appears)
|
||||
await page.waitForTimeout(2000);
|
||||
const nextButtonAfterPlan = page.getByRole('button', { name: /siguiente|next/i });
|
||||
if (await nextButtonAfterPlan.isVisible({ timeout: 3000 }).catch(() => false)) {
|
||||
await nextButtonAfterPlan.click();
|
||||
}
|
||||
|
||||
// Handle payment page
|
||||
const bypassToggle = page.getByRole('checkbox', { name: /bypass|omitir|skip.*payment/i });
|
||||
if (await bypassToggle.isVisible({ timeout: 3000 }).catch(() => false)) {
|
||||
await bypassToggle.check();
|
||||
await page.getByRole('button', { name: /completar registro|complete registration/i }).click();
|
||||
}
|
||||
|
||||
// Wait for onboarding
|
||||
await page.waitForURL(/\/app\/onboarding/, { timeout: 15000 });
|
||||
|
||||
// Test specific scenario: Skip file upload and add products manually
|
||||
await test.step('Navigate to manual product entry', async () => {
|
||||
// Look for file upload step and skip it
|
||||
let attempts = 0;
|
||||
while (attempts < 10) {
|
||||
const bodyText = await page.locator('body').textContent();
|
||||
|
||||
if (bodyText?.match(/subir.*archivo|upload.*file|sales.*data/i)) {
|
||||
// Found upload step, try to skip
|
||||
const skipButton = page.getByRole('button', { name: /skip|omitir|saltar|manual/i });
|
||||
if (await skipButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await skipButton.click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Try next button if available
|
||||
const nextButton = page.getByRole('button', { name: /next|siguiente/i });
|
||||
if (await nextButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await nextButton.click();
|
||||
attempts++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('should handle validation errors gracefully', async ({ page }) => {
|
||||
await page.goto('/register');
|
||||
await acceptCookieConsent(page);
|
||||
|
||||
await test.step('Test password validation', async () => {
|
||||
// Try weak password
|
||||
await page.getByLabel(/nombre completo|full name/i).fill('Test User');
|
||||
await page.getByLabel(/correo|email/i).fill('test@example.com');
|
||||
await page.getByLabel(/^contraseña|^password/i).first().fill('weak');
|
||||
|
||||
// Next button should be disabled or show error
|
||||
const nextButton = page.getByRole('button', { name: /siguiente|next/i });
|
||||
|
||||
// Either button is disabled or we see password criteria errors
|
||||
const isDisabled = await nextButton.isDisabled();
|
||||
const hasPasswordError = await page.getByText(/mínimo|caracteres|mayúscula|minúscula/i).isVisible().catch(() => false);
|
||||
|
||||
expect(isDisabled || hasPasswordError).toBe(true);
|
||||
});
|
||||
|
||||
await test.step('Test email validation', async () => {
|
||||
// Try invalid email
|
||||
await page.getByLabel(/correo|email/i).fill('invalid-email');
|
||||
await page.getByLabel(/^contraseña|^password/i).first().click(); // Blur the email field
|
||||
|
||||
// Should show email error
|
||||
await expect(page.getByText(/email.*válido|valid.*email/i)).toBeVisible({ timeout: 3000 });
|
||||
});
|
||||
|
||||
await test.step('Test terms acceptance requirement', async () => {
|
||||
// Fill valid data but don't accept terms
|
||||
await page.getByLabel(/nombre completo|full name/i).fill('Test User');
|
||||
await page.getByLabel(/correo|email/i).fill('test@example.com');
|
||||
await page.getByLabel(/^contraseña|^password/i).first().fill('SecurePass123!');
|
||||
await page.getByLabel(/confirmar contraseña|confirm password/i).fill('SecurePass123!');
|
||||
|
||||
// Try to proceed without accepting terms
|
||||
const nextButton = page.getByRole('button', { name: /siguiente|next/i });
|
||||
|
||||
// Button should be disabled
|
||||
await expect(nextButton).toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user