7.7 KiB
Playwright E2E Testing Guide for Bakery-IA
This directory contains end-to-end (E2E) tests for the Bakery-IA SaaS application using Playwright.
📁 Project Structure
tests/
├── auth/ # Authentication tests (login, register, logout)
├── onboarding/ # Onboarding wizard tests
├── dashboard/ # Dashboard and main page tests
├── operations/ # Business operations tests
├── analytics/ # Analytics page tests (to be added)
├── settings/ # Settings page tests (to be added)
├── fixtures/ # Test data files (CSV, images, etc.)
├── helpers/ # Utility functions and helpers
│ ├── auth.ts # Authentication helpers
│ └── utils.ts # General utilities
├── .auth/ # Stored authentication states (gitignored)
├── .gitignore # Files to ignore in git
└── auth.setup.ts # Global authentication setup
🚀 Getting Started
Prerequisites
- Node.js 20+
- npm installed
- Playwright browsers installed
Installation
Playwright is already installed in this project. If you need to reinstall browsers:
npx playwright install
🎯 Running Tests
Run all tests (headless)
npm run test:e2e
Run tests with UI (interactive mode)
npm run test:e2e:ui
Run tests in headed mode (see browser)
npm run test:e2e:headed
Run tests in debug mode (step through tests)
npm run test:e2e:debug
Run specific test file
npx playwright test tests/auth/login.spec.ts
Run tests matching a pattern
npx playwright test --grep "login"
View test report
npm run test:e2e:report
🎬 Recording Tests (Codegen)
Playwright has a built-in test generator that records your actions:
npm run test:e2e:codegen
This opens a browser where you can interact with your app. Playwright will generate test code for your actions.
🔐 Authentication
Tests use a global authentication setup to avoid logging in before every test.
How it works:
auth.setup.tsruns once before all tests- Logs in with test credentials
- Saves authentication state to
tests/.auth/user.json - Other tests reuse this state
Test Credentials
Set these environment variables (or use defaults):
export TEST_USER_EMAIL="test@bakery.com"
export TEST_USER_PASSWORD="test-password-123"
Creating authenticated tests
import { test, expect } from '@playwright/test';
test.describe('My Test Suite', () => {
// Use saved auth state
test.use({ storageState: 'tests/.auth/user.json' });
test('my test', async ({ page }) => {
// Already logged in!
await page.goto('/app/dashboard');
});
});
📝 Writing Tests
Basic Test Structure
import { test, expect } from '@playwright/test';
test.describe('Feature Name', () => {
test.beforeEach(async ({ page }) => {
// Setup before each test
await page.goto('/your-page');
});
test('should do something', async ({ page }) => {
// Your test code
await page.getByRole('button', { name: 'Click me' }).click();
await expect(page).toHaveURL('/expected-url');
});
});
Using Helpers
import { login, logout, TEST_USER } from '../helpers/auth';
import { waitForLoadingToFinish, expectToastMessage } from '../helpers/utils';
test('my test with helpers', async ({ page }) => {
await login(page, TEST_USER);
await waitForLoadingToFinish(page);
await expectToastMessage(page, 'Success!');
});
Best Practices
-
Use semantic selectors
// ✅ Good page.getByRole('button', { name: 'Submit' }) page.getByLabel('Email') // ❌ Avoid page.locator('.btn-primary') page.locator('#email-input') -
Wait for elements properly
// ✅ Good - Auto-waits await page.getByText('Hello').click(); // ❌ Avoid - Manual waits await page.waitForTimeout(3000); -
Use data-testid for complex elements
// In your component <div data-testid="product-card">...</div> // In your test await page.getByTestId('product-card').click(); -
Reuse authentication
// ✅ Good - Reuse saved state test.use({ storageState: 'tests/.auth/user.json' }); // ❌ Avoid - Login in every test test.beforeEach(async ({ page }) => { await login(page); });
🔍 Debugging Tests
1. Use Playwright Inspector
npm run test:e2e:debug
2. Use console.log
test('debug test', async ({ page }) => {
console.log('Current URL:', page.url());
});
3. Take screenshots
await page.screenshot({ path: 'screenshot.png' });
4. View trace
When tests fail, check the trace viewer:
npx playwright show-trace test-results/trace.zip
🎨 Test Reports
After running tests, view the HTML report:
npm run test:e2e:report
This shows:
- ✅ Passed tests
- ❌ Failed tests
- 📸 Screenshots on failure
- 🎥 Videos on failure
- 📊 Traces for debugging
🌐 Multi-Browser Testing
Tests run on multiple browsers automatically:
- Chromium (Chrome/Edge)
- Firefox
- WebKit (Safari)
- Mobile Chrome
- Mobile Safari
Configure in playwright.config.ts.
📱 Mobile Testing
Tests automatically run on mobile viewports. To test specific viewport:
test('mobile test', async ({ page }) => {
await page.setViewportSize({ width: 375, height: 667 });
// Your test
});
🔄 CI/CD Integration
Tests run automatically on GitHub Actions:
- ✅ On every push to
mainordevelop - ✅ On every pull request
- ✅ Uploads test reports as artifacts
- ✅ Comments on PRs with results
GitHub Secrets Required
Set these in your repository settings:
TEST_USER_EMAIL: Test user emailTEST_USER_PASSWORD: Test user password
🧪 Test Coverage
Current test coverage:
- ✅ Authentication (login, register, logout)
- ✅ Onboarding wizard
- ✅ Dashboard smoke tests
- ✅ Purchase order management
- ✅ Product/Recipe creation
- 🔜 Analytics pages
- 🔜 Settings pages
- 🔜 Team management
- 🔜 Payment flows
🚨 Common Issues
Tests fail with "timeout exceeded"
- Check if dev server is running
- Increase timeout in
playwright.config.ts - Check network speed
Authentication fails
- Verify test credentials are correct
- Check if test user exists in database
- Clear
.auth/user.jsonand re-run
"Element not found"
- Check if selectors match your UI
- Add
await page.pause()to inspect - Use Playwright Inspector
Tests work locally but fail in CI
- Check environment variables
- Ensure database is seeded with test data
- Check for timing issues (add explicit waits)
📚 Resources
🤝 Contributing
When adding new features:
- Write E2E tests for critical user flows
- Use existing helpers and utilities
- Follow the established test structure
- Add test data to
fixtures/if needed - Update this README if adding new patterns
💡 Tips
- Use
test.only()to run a single test during development - Use
test.skip()to temporarily disable a test - Group related tests with
test.describe() - Use
test.beforeEach()for common setup - Keep tests independent and isolated
- Name tests descriptively: "should [action] when [condition]"
Happy Testing! 🎭