From e2e-test-framework
Executes end-to-end tests for full user workflows across frontend and backend using Playwright, Cypress, or Selenium. Use for specialized testing of user journeys.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin e2e-test-frameworkThis skill is limited to using the following tools:
!`cat package.json 2>/dev/null | grep -oE 'playwright|cypress|selenium' || echo 'No E2E framework detected'`
Configures and writes end-to-end tests with Playwright or Cypress for validating user flows, browser integration, CI E2E tests, acceptance tests, and production smoke tests.
Builds end-to-end automated tests simulating real user interactions across full app stack using Playwright, Cypress, Selenium with pytest. For user journeys, cross-browser testing, and integration validation.
Share bugs, ideas, or general feedback.
!cat package.json 2>/dev/null | grep -oE 'playwright|cypress|selenium' || echo 'No E2E framework detected'
Execute end-to-end tests that simulate real user workflows across the full application stack -- browser interactions, API calls, database operations, and third-party integrations. Supports Playwright (recommended), Cypress, Selenium, and Puppeteer.
npx playwright install or Cypress binary)data-testid attributes as primary selectors for stability.beforeEach to navigate to the starting page and reset state.afterEach to capture screenshots on failure.storageState in Playwright).expect with auto-waiting locators (Playwright) instead of explicit waits.networkidle or domcontentloaded wait conditions for page transitions.tests/e2e/ or e2e/tests/e2e/pages/| Error | Cause | Solution |
|---|---|---|
| Element not found / timeout | Selector changed or element lazy-loaded after timeout | Use data-testid attributes; increase timeout; use waitFor with proper state checks |
| Test passes locally but fails in CI | Headless browser behavior differs or CI is slower | Run CI in headless mode locally to reproduce; increase timeouts; check viewport size |
| Authentication state expired | Stored session tokens have short TTL | Regenerate auth state before each test run; use long-lived test account tokens |
| Flaky test due to animation | Click registered before animation completes | Disable CSS animations in test config; use force: true on click; add waitForLoadState |
| Database state pollution | Previous test left data that affects current test | Seed database in beforeEach; use transactional rollback; reset via API endpoint |
Playwright test for user registration flow:
import { test, expect } from '@playwright/test';
test('new user can register and see dashboard', async ({ page }) => {
await page.goto('/register');
await page.getByTestId('name-input').fill('Test User');
await page.getByTestId('email-input').fill('test@example.com');
await page.getByTestId('password-input').fill('SecurePass123!');
await page.getByTestId('register-button').click();
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByTestId('welcome-message')).toContainText('Test User');
});
Page object model:
export class LoginPage {
constructor(private page: Page) {}
async login(email: string, password: string) {
await this.page.goto('/login');
await this.page.getByTestId('email').fill(email);
await this.page.getByTestId('password').fill(password);
await this.page.getByTestId('submit').click();
await this.page.waitForURL(/\/dashboard/);
}
}
Playwright config with multi-browser projects:
export default defineConfig({
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'mobile', use: { ...devices['iPhone 14'] } },
],
use: { screenshot: 'only-on-failure', trace: 'on-first-retry' },
});