Imporve testing

This commit is contained in:
Urtzi Alfaro
2025-12-24 11:25:08 +01:00
parent bfa5ff0637
commit 82567b8701
3 changed files with 1102 additions and 0 deletions

View 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.

View 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`

View 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();
});
});
});