mirror of
https://github.com/OHTU-German-learning-website/OHTU-German-learning-website.git
synced 2026-10-12 19:13:51 +03:00
201 lines
6.3 KiB
Markdown
201 lines
6.3 KiB
Markdown
# End-to-End Testing with Playwright
|
|
|
|
_Last Updated: November 30, 2025_
|
|
|
|
This directory contains E2E tests using [Playwright](https://playwright.dev/) to test the application in real browsers.
|
|
|
|
## Prerequisites
|
|
|
|
- **Node.js**: v20+ (included in dev container)
|
|
- **Environment**: Run commands inside the dev container at `/host/gradesa`
|
|
- **Database**: Tests run against the test database (configured via `.env.test`)
|
|
|
|
## Initial Setup
|
|
|
|
Playwright is already configured in this project. If setting up from scratch:
|
|
|
|
```
|
|
npm install --save-dev @playwright/test
|
|
npx playwright install
|
|
```
|
|
|
|
## Quick E2E checklist
|
|
|
|
- Ensure the app is running (dev server at `http://localhost:3000`).
|
|
- Ensure the test database is migrated/available (`npm run db:migrate` with `.env.test` set if needed).
|
|
- Install Playwright browsers: `npx playwright install`.
|
|
- Run tests: `npm run test:e2e` (or `npx playwright test <file>`).
|
|
|
|
## Commands
|
|
|
|
Run these commands from `/host/gradesa` inside the container:
|
|
|
|
```bash
|
|
npm run test:e2e # Run all tests
|
|
npm run test:e2e:ui # Run with UI mode
|
|
npm run test:e2e:debug # Run in debug mode
|
|
npx playwright test [file] # Run specific test file
|
|
```
|
|
|
|
## CI/CD Integration
|
|
|
|
Playwright tests run automatically in the GitHub Actions pipeline:
|
|
|
|
- Triggered on pull requests to `master`
|
|
- Tests run in headless mode
|
|
- Screenshots and videos captured on failure
|
|
- Test results available in GitHub Actions artifacts
|
|
|
|
## Writing New Tests
|
|
|
|
### File Naming
|
|
|
|
Follow the existing pattern: `feature-name.spec.js`
|
|
|
|
### Test Structure
|
|
|
|
```javascript
|
|
import { test, expect } from "@playwright/test";
|
|
|
|
test.describe("Feature Name", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// Setup: navigate to page, login if needed
|
|
await page.goto("/your-route");
|
|
});
|
|
|
|
test("should do something specific", async ({ page }) => {
|
|
// Arrange: Set up test data
|
|
// Act: Perform user actions
|
|
// Assert: Verify results
|
|
await expect(page.locator("selector")).toBeVisible();
|
|
});
|
|
});
|
|
```
|
|
|
|
### Naming Conventions
|
|
|
|
- Use descriptive test names: `should display error message when form is invalid`
|
|
- Group related tests in `test.describe` blocks
|
|
- Use `test.beforeEach` for common setup
|
|
|
|
### Finding Elements
|
|
|
|
Prefer semantic selectors (in order of preference):
|
|
|
|
1. `getByRole()` - Most robust, uses accessibility roles
|
|
2. `getByLabel()` - For form fields
|
|
3. `getByText()` - For unique text content
|
|
4. `getByTestId()` - Last resort, requires adding `data-testid`
|
|
|
|
## Test Files Structure
|
|
|
|
Current test files in this directory:
|
|
|
|
- `homepage.spec.js` - Home page tests
|
|
- `navigation.spec.js` - Navigation tests
|
|
- `auth.spec.js` - Authentication tests
|
|
- `components.spec.js` - Component interaction tests
|
|
- `forms.spec.js` - Form tests
|
|
- `grammar.spec.js` - Grammar feature tests
|
|
- `page-analyzer.spec.js` - Page analysis utilities
|
|
- `advanced.spec.js` - Advanced interaction examples
|
|
- `utils/helpers.js` - Helper functions
|
|
|
|
## Developer Notes
|
|
|
|
The following sections contain observations and findings from E2E test development. These are helpful for understanding the application structure and writing effective tests.
|
|
|
|
### Key Findings
|
|
|
|
1. **Navigation** - `page.goto()` is more reliable than clicking links
|
|
2. **Selectors** - `getByRole()` is more reliable than `locator()` with CSS selectors
|
|
3. **Structure** - Main navigation has links to grammar, resources, and auth pages
|
|
|
|
## Page Structure Notes
|
|
|
|
- Home page: Links to resources, grammar, login, and register
|
|
- Resources: Chapter navigation and content
|
|
- No hamburger menu or mobile-specific UI elements
|
|
|
|
### Screenshots
|
|
|
|
Playwright automatically captures screenshots on test failures. These are saved in:
|
|
|
|
- `test-results/` directory (gitignored)
|
|
- Available as artifacts in CI/CD runs
|
|
|
|
To manually capture screenshots during development:
|
|
|
|
```javascript
|
|
await page.screenshot({ path: "debug-screenshot.png" });
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Understand page structure first**: Use `page-analyzer.spec.js` to explore pages
|
|
2. **Review screenshots**: Check `test-results/` and `screenshots/` to understand the UI
|
|
3. **Use semantic selectors**: Prefer `getByRole('link', { name: 'Kapitel 1' })`
|
|
4. **Direct navigation**: Use `page.goto()` for navigation rather than clicking links when appropriate
|
|
5. **Wait for stability**: Use `waitForLoadState('networkidle')` after navigation
|
|
6. **Isolate tests**: Each test should be independent and not rely on others
|
|
7. **Clean up**: Reset state after tests (e.g., delete created data)
|
|
|
|
## Common Issues & Debugging
|
|
|
|
### Element Not Found
|
|
|
|
- **Solution**: Use more robust selectors (role-based)
|
|
- **Debug**: Use `await page.pause()` to inspect the page
|
|
- **Debug**: Print available elements: `console.log(await page.content())`
|
|
|
|
### Strict Mode Violations
|
|
|
|
- **Error**: "locator resolved to multiple elements"
|
|
- **Solution**: Make selector more specific or use `.first()`, `.last()`, `.nth()`
|
|
|
|
### Navigation Timeouts
|
|
|
|
- **Solution**: Use direct navigation with `page.goto()`
|
|
- **Solution**: Increase timeout: `await page.goto(url, { timeout: 60000 })`
|
|
|
|
### Timing Issues
|
|
|
|
- **Solution**: Use Playwright's auto-waiting (preferred)
|
|
- **Solution**: Explicit waits: `await page.waitForSelector('selector')`
|
|
- **Avoid**: `page.waitForTimeout()` - this is an anti-pattern
|
|
|
|
### Debugging Tips
|
|
|
|
```javascript
|
|
// Pause test execution
|
|
await page.pause();
|
|
|
|
// Take screenshot at specific point
|
|
await page.screenshot({ path: "debug.png" });
|
|
|
|
// Print page HTML
|
|
console.log(await page.content());
|
|
|
|
// Check what's visible
|
|
const visible = await page.locator("selector").isVisible();
|
|
console.log("Element visible:", visible);
|
|
```
|
|
|
|
## Further Development
|
|
|
|
Planned improvements:
|
|
|
|
1. Form submission tests with various input scenarios
|
|
2. Content interaction tests (exercise completion flows)
|
|
3. User journey tests (end-to-end user scenarios)
|
|
4. Visual regression tests
|
|
5. Accessibility tests using Playwright's accessibility testing
|
|
|
|
## Resources
|
|
|
|
- [Playwright Documentation](https://playwright.dev/docs/intro) - Getting started guide
|
|
- [Playwright API Reference](https://playwright.dev/docs/api/class-playwright) - Complete API docs
|
|
- [Playwright Best Practices](https://playwright.dev/docs/best-practices) - Official best practices
|
|
- [Playwright Test Generator](https://playwright.dev/docs/codegen) - Generate tests by recording actions
|
|
- [Debugging Tests](https://playwright.dev/docs/debug) - Debugging guide
|