* chore: bump version to 2.22.1 and update dependencies - Updated application version from 2.22.0 to 2.22.1 in package.json. - Updated various dependencies including @marsidev/react-turnstile to 1.4.1, @stripe/react-stripe-js to 5.4.1, @stripe/stripe-js to 8.6.1, and react-hook-form to 7.70.0. - Adjusted lucide-react version to be referenced from the catalog across multiple package.json files. - Enhanced consistency in pnpm-lock.yaml and pnpm-workspace.yaml with updated package versions. * chore: bump version to 2.23.0 and update dependencies - Updated application version from 2.22.1 to 2.23.0 in package.json. - Upgraded turbo dependency from 2.7.1 to 2.7.3 in package.json and pnpm-lock.yaml. - Enhanced end-to-end testing documentation in AGENTS.md and CLAUDE.md with instructions for running tests. - Updated AuthPageObject to use a new secret for user creation in auth.po.ts. - Refactored team ownership transfer and member role update dialogs to close on success. - Improved error handling for weak passwords in AuthErrorAlert component. - Adjusted database schemas and tests to reflect changes in invitation policies and role management.
125 lines
3.2 KiB
Markdown
125 lines
3.2 KiB
Markdown
|
|
## End-to-End Testing with Playwright
|
|
|
|
## Running Tests
|
|
|
|
Running the tests for testing single file:
|
|
```bash
|
|
pnpm --filter web-e2e exec playwright test <partial-name-or-folder-name> --workers=1
|
|
```
|
|
|
|
Example:
|
|
```bash
|
|
pnpm --filter web-e2e exec playwright test <partial-name-or-folder-name> --workers=1
|
|
```
|
|
|
|
This is useful for quickly testing a single file or a specific feature and should be your default choice.
|
|
|
|
Running all tests (rarely needed, only use if asked by the user):
|
|
|
|
```bash
|
|
pnpm test
|
|
```
|
|
|
|
### Page Object Pattern (Required)
|
|
|
|
Always use Page Objects for test organization and reusability:
|
|
|
|
```typescript
|
|
// Example: auth.po.ts
|
|
export class AuthPageObject {
|
|
constructor(private readonly page: Page) {}
|
|
|
|
async signIn(params: { email: string; password: string }) {
|
|
await this.page.fill('input[name="email"]', params.email);
|
|
await this.page.fill('input[name="password"]', params.password);
|
|
await this.page.click('button[type="submit"]');
|
|
}
|
|
|
|
async signOut() {
|
|
await this.page.click('[data-test="account-dropdown-trigger"]');
|
|
await this.page.click('[data-test="account-dropdown-sign-out"]');
|
|
}
|
|
}
|
|
```
|
|
|
|
### Reliability Patterns
|
|
|
|
**Use `toPass()` for flaky operations** - Always wrap unreliable operations:
|
|
|
|
```typescript
|
|
// ✅ CORRECT - Reliable email/OTP operations
|
|
await expect(async () => {
|
|
const otpCode = await this.getOtpCodeFromEmail(email);
|
|
expect(otpCode).not.toBeNull();
|
|
await this.enterOtpCode(otpCode);
|
|
}).toPass();
|
|
|
|
// ✅ CORRECT - Network requests with validation
|
|
await expect(async () => {
|
|
const response = await this.page.waitForResponse(resp =>
|
|
resp.url().includes('auth/v1/user')
|
|
);
|
|
expect(response.status()).toBe(200);
|
|
}).toPass();
|
|
|
|
// ✅ CORRECT - Complex operations with custom intervals
|
|
await expect(async () => {
|
|
await auth.submitMFAVerification(AuthPageObject.MFA_KEY);
|
|
}).toPass({
|
|
intervals: [500, 2500, 5000, 7500, 10_000, 15_000, 20_000]
|
|
});
|
|
```
|
|
|
|
### Test Data Management
|
|
|
|
**Email Testing**: Use `createRandomEmail()` for unique test emails:
|
|
```typescript
|
|
createRandomEmail() {
|
|
const value = Math.random() * 10000000000000;
|
|
return `${value.toFixed(0)}@makerkit.dev`;
|
|
}
|
|
```
|
|
|
|
**User Bootstrapping**: Use `bootstrapUser()` for consistent test user creation:
|
|
```typescript
|
|
await auth.bootstrapUser({
|
|
email: 'test@example.com',
|
|
password: 'testingpassword',
|
|
name: 'Test User'
|
|
});
|
|
```
|
|
|
|
This method creates a user with an API call.
|
|
|
|
To sign in:
|
|
|
|
```tsx
|
|
await auth.loginAsUser({
|
|
email: 'test@example.com',
|
|
password: 'testingpassword',
|
|
});
|
|
```
|
|
|
|
### Test Selectors
|
|
|
|
**Always use `data-test` attributes** for reliable element selection:
|
|
```typescript
|
|
// ✅ CORRECT - Use data-test attributes
|
|
await this.page.click('[data-test="submit-button"]');
|
|
await this.page.fill('[data-test="email-input"]', email);
|
|
|
|
// ✅ OR
|
|
await this.page.getByTestId('submit-button').click();
|
|
|
|
// ❌ AVOID - Fragile selectors
|
|
await this.page.click('.btn-primary');
|
|
await this.page.click('button:nth-child(2)');
|
|
```
|
|
|
|
### Test Organization
|
|
|
|
- **Feature-based folders**: `/tests/authentication/`, `/tests/billing/`
|
|
- **Page Objects**: `*.po.ts` files for reusable page interactions
|
|
- **Setup files**: `auth.setup.ts` for global test setup
|
|
- **Utility classes**: `/tests/utils/` for shared functionality |