mirror of
https://github.com/OHTU-German-learning-website/OHTU-German-learning-website.git
synced 2026-10-12 19:13:51 +03:00
Renamed, reformatted and expanded project readmes in anticipation of project handover.
This commit is contained in:
@@ -1,14 +1,35 @@
|
||||
# End-to-End Testing with Playwright
|
||||
|
||||
## Setup
|
||||
_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
|
||||
@@ -16,18 +37,75 @@ npm run test:e2e:debug # Run in debug mode
|
||||
npx playwright test [file] # Run specific test file
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
## 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
|
||||
|
||||
## Key Findings
|
||||
## 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
|
||||
@@ -39,30 +117,84 @@ npx playwright test [file] # Run specific test file
|
||||
- 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. Use `page-analyzer.spec.js` to understand page structure
|
||||
2. Review screenshots in `screenshots/` to understand the UI
|
||||
3. Use role-based selectors: `getByRole('link', { name: 'Kapitel 1' })`
|
||||
4. For navigation, use direct `page.goto()` rather than clicking links
|
||||
5. Add appropriate assertions to verify page content
|
||||
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
|
||||
## Common Issues & Debugging
|
||||
|
||||
- **Element not found**: Use more robust selectors
|
||||
- **Strict mode violations**: Use more specific selectors when multiple elements match
|
||||
- **Navigation timeouts**: Use direct navigation
|
||||
- **Timing issues**: Use `waitForLoadState('networkidle')`
|
||||
### Element Not Found
|
||||
|
||||
## Next Steps
|
||||
- **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())`
|
||||
|
||||
1. Form submission tests after analyzing form behavior
|
||||
2. Content interaction tests
|
||||
3. User journey tests
|
||||
### 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)
|
||||
- [API Reference](https://playwright.dev/docs/api/class-playwright)
|
||||
- [Best Practices](https://playwright.dev/docs/best-practices)
|
||||
- [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
|
||||
|
||||
Reference in New Issue
Block a user