Files
myeasycms-v2/apps/e2e/AGENTS.md
Giancarlo Buomprisco d5dc6f2528 2.23.0: Enforce Policies API for invitations and creating accounts; added WeakPassword handling; Fix dialog open/closed states (#439)
* 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.
2026-01-07 17:00:11 +01:00

3.2 KiB

End-to-End Testing with Playwright

Running Tests

Running the tests for testing single file:

pnpm --filter web-e2e exec playwright test <partial-name-or-folder-name> --workers=1

Example:

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):

pnpm test

Page Object Pattern (Required)

Always use Page Objects for test organization and reusability:

// 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:

// ✅ 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:

createRandomEmail() {
  const value = Math.random() * 10000000000000;
  return `${value.toFixed(0)}@makerkit.dev`;
}

User Bootstrapping: Use bootstrapUser() for consistent test user creation:

await auth.bootstrapUser({
  email: 'test@example.com',
  password: 'testingpassword',
  name: 'Test User'
});

This method creates a user with an API call.

To sign in:

await auth.loginAsUser({
  email: 'test@example.com',
  password: 'testingpassword',
});

Test Selectors

Always use data-test attributes for reliable element selection:

// ✅ 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