mcpField
E
E2E Testing (Frontend)

E2E Testing (Frontend)

github.com/exceptionlessTesting & quality2.5k37 installsUpdated 1d ago
Repository

About E2E Testing (Frontend)

A frontend E2E testing skill for projects using Playwright. It covers page objects, selector choices, backend test data setup, and accessibility audits; the README notes that coverage is currently limited.

Key features

  1. 01Run tests with Playwright
  2. 02Organize reusable page objects
  3. 03Prefer semantic selectors over CSS details
  4. 04Set up backend data through APIs or seeding
  5. 05Audit accessibility with axe-core

Use cases

  1. 01Test login and other frontend flows
  2. 02Prepare backend data for browser tests
  3. 03Check pages for accessibility violations

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/exceptionless/exceptionless --skill e2e-testing-(frontend)

After installing, type/e2e-testing-(frontend)in Claude Code to confirm it loaded.

Details

From the project README

E2E Testing (Frontend)

Note: E2E test coverage is currently limited. This is an area for improvement.

Running Tests

npx playwright install  # First time only
npm run test:e2e

Page Object Model

Create page objects for reusable page interactions:

// e2e/pages/login-page.ts
import { type Page, type Locator, expect } from '@playwright/test';

export class LoginPage {
    readonly page: Page;
    readonly emailInput: Locator;
    readonly passwordInput: Locator;
    readonly submitButton: Locator;
    readonly errorMessage: Locator;

    constructor(page: Page) {
        this.page = page;
        this.emailInput = page.getByLabel('Email');
        this.passwordInput = page.getByLabel('Password');
        this.submitButton = page.getByRole('button', { name: /log in/i });
        this.errorMessage = page.getByRole('alert');
    }

    async goto() {
        await this.page.goto('/login');
    }

    async login(email: string, password: string) {
        await this.emailInput.fill(email);
        await this.passwordInput.fill(password);
        await this.submitButton.click();
    }

    async expectError(message: string) {
        await expect(this.errorMessage).toContainText(message);
    }
}

Using Page Objects in Tests

// e2e/auth/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/login-page';

test.describe('Login', () => {
    test('successful login redirects to dashboard', async ({ page }) => {
        const loginPage = new LoginPage(page);

        await loginPage.goto();
        await loginPage.login('[email protected]', 'password123');

        await expect(page).toHaveURL('/');
    });

    test('invalid credentials shows error', async ({ page }) => {
        const loginPage = new LoginPage(page);

        await loginPage.goto();
        await loginPage.login('[email protected]', 'wrongpassword');

        await loginPage.expectError('Invalid email or password');
    });
});

Selector Priority

  1. Semantic selectors first:

    page.getByRole('button', { name: /submit/i });
    page.getByLabel('Email address');
    page.getByText('Welcome back');
    
  2. Fallback to test IDs:

    page.getByTestId('stack-trace');
    
  3. Avoid implementation details:

    // ❌ Avoid CSS classes and IDs
    page.locator('.btn-primary');
    

Backend Data Setup

E2E tests run against the full Aspire stack. The backend uses the same AppWebHostFactory infrastructure from backend-testing.

For tests requiring specific data, consider:

  1. API calls in beforeEach — Use Playwright's request context to set up data
  2. Test-specific endpoints — Create /api/test/* endpoints for test data management
  3. Database seeding — Seed required data before test runs
  4. Aspire orchestration — Tests start with Elasticsearch and Redis pre-configured
test.beforeEach(async ({ request }) => {
    // Set up test data via API
    await request.post('/api/test/seed', {
        data: { scenario: 'events-with-errors' }
    });
});

test.afterEach(async ({ request }) => {
    await request.delete('/api/test/cleanup');
});

Note: Backend services use in-memory implementations during tests. See AppWebHostFactory for how test infrastructure is configured.

Accessibility Audits

import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test('login page has no accessibility violations', async ({ page }) => {
    await page.goto('/login');

    const results = await new AxeBuilder({ page }).analyze();
    expect(results.violations).toEqual([]);
});

See accessibility for WCAG guidelines.

Comments

Markdown supported