10 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
Testing Against Local Dev Server (Default)
These commands test against the Vite dev server running on localhost:5173:
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
Testing Against Local Kubernetes/Tilt Environment
These commands test against your Tilt-managed Kubernetes cluster on localhost:
Prerequisites
- Tilt must be running:
tilt up - Frontend service must be accessible at
http://localhost(via ingress) - All services should be healthy (check with
tilt statusor the Tilt UI)
Run all tests against K8s (headless)
npm run test:e2e:k8s
Run tests with UI (interactive mode)
npm run test:e2e:k8s:ui
Run tests in headed mode (see browser)
npm run test:e2e:k8s:headed
Run tests in debug mode
npm run test:e2e:k8s:debug
Record tests against K8s environment
npm run test:e2e:k8s:codegen
Custom base URL
If your K8s ingress uses a different URL (e.g., bakery-ia.local):
PLAYWRIGHT_BASE_URL=http://bakery-ia.local npm run test:e2e:k8s
General Test Commands
Run specific test file
npx playwright test tests/auth/login.spec.ts
# Or against K8s:
npx playwright test --config=playwright.k8s.config.ts tests/auth/login.spec.ts
Run tests matching a pattern
npx playwright test --grep "login"
# Or against K8s:
npx playwright test --config=playwright.k8s.config.ts --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 (for regular tests)
- For K8s tests: Verify Tilt is running and services are healthy
- Increase timeout in
playwright.config.tsorplaywright.k8s.config.ts - Check network speed
Authentication fails
- Verify test credentials are correct
- Check if test user exists in database
- For K8s tests: Ensure the database is seeded with test data
- 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)
K8s-Specific Issues
Cannot connect to http://localhost
# Check if ingress is running
kubectl get ingress -n bakery-ia
# Verify services are up
tilt status
# Check if you can access the frontend manually
curl http://localhost
Ingress returns 404 or 503
- Verify all Tilt resources are healthy in the Tilt UI
- Check frontend pod logs:
kubectl logs -n bakery-ia -l app=frontend - Restart Tilt:
tilt down && tilt up
Tests are slower in K8s than dev server
- This is expected due to ingress routing overhead
- The K8s config has increased
navigationTimeoutto 30 seconds - Consider running fewer browsers in parallel for K8s tests
Authentication state doesn't work
- Test credentials must match what's seeded in K8s database
- Check orchestrator logs for auth issues:
kubectl logs -n bakery-ia -l app=orchestrator - Delete
.auth/user.jsonand re-run setup
Using custom ingress host (e.g., bakery-ia.local)
# Add to /etc/hosts
echo "127.0.0.1 bakery-ia.local" | sudo tee -a /etc/hosts
# Run tests with custom URL
PLAYWRIGHT_BASE_URL=http://bakery-ia.local npm run test:e2e:k8s
📚 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! 🎭