--- title: End-to-End Testing sidebar_position: 4 --- # End-to-End Testing Apache Superset uses Playwright for end-to-end testing, migrating from the legacy Cypress tests. ## Running Tests ### Playwright (Recommended) ```bash cd superset-frontend # Run all tests npm run playwright:test # or: npx playwright test # Run specific test file npx playwright test tests/auth/login.spec.ts # Run with UI mode for debugging npm run playwright:ui # or: npx playwright test --ui # Run in headed mode (see browser) npm run playwright:headed # or: npx playwright test --headed # Debug specific test file npm run playwright:debug tests/auth/login.spec.ts # or: npx playwright test --debug tests/auth/login.spec.ts ``` ### Cypress (Deprecated) Cypress tests are being migrated to Playwright. For legacy tests: ```bash cd superset-frontend/cypress-base npm run cypress-run-chrome # Headless npm run cypress-debug # Interactive UI ``` ## Project Architecture ``` superset-frontend/playwright/ ├── components/core/ # Reusable UI components ├── pages/ # Page Object Models ├── tests/ # Test files organized by feature ├── utils/ # Shared constants and utilities └── playwright.config.ts ``` ## Design Principles We follow **YAGNI** (You Aren't Gonna Need It), **DRY** (Don't Repeat Yourself), and **KISS** (Keep It Simple, Stupid) principles: - Build only what's needed now - Reuse existing patterns and components - Keep solutions simple and maintainable ## Page Object Pattern Each page object encapsulates: - **Actions**: What you can do on the page - **Queries**: Information you can get from the page - **Selectors**: Centralized in private static SELECTORS constant - **NO Assertions**: Keep assertions in test files **Example Page Object:** ```typescript export class AuthPage { // Selectors centralized in the page object private static readonly SELECTORS = { LOGIN_FORM: '[data-test="login-form"]', USERNAME_INPUT: '[data-test="username-input"]', } as const; // Actions - what you can do async loginWithCredentials(username: string, password: string) {} // Queries - information you can get async getCurrentUrl(): Promise {} // NO assertions - those belong in tests } ``` **Example Test:** ```typescript import { test, expect } from '@playwright/test'; import { AuthPage } from '../../pages/AuthPage'; import { LOGIN } from '../../utils/urls'; test('should login with correct credentials', async ({ page }) => { const authPage = new AuthPage(page); await authPage.goto(); await authPage.loginWithCredentials('admin', 'general'); // Assertions belong in tests, not page objects expect(await authPage.getCurrentUrl()).not.toContain(LOGIN); }); ``` ## Core Components Reusable UI interaction classes for common elements (`components/core/`): - **Form**: Container with properly scoped child element access - **Input**: Supports `fill()`, `type()`, and `pressSequentially()` methods - **Button**: Standard click, hover, focus interactions **Usage Example:** ```typescript import { Form } from '../components/core'; const loginForm = new Form(page, '[data-test="login-form"]'); const usernameInput = loginForm.getInput('[data-test="username-input"]'); await usernameInput.fill('admin'); ``` ## Test Reports Playwright generates multiple reports for better visibility: ```bash # View interactive HTML report (opens automatically on failure) npm run playwright:report # or: npx playwright show-report # View test trace for debugging failures npx playwright show-trace test-results/[test-name]/trace.zip ``` ### Report Types - **List Reporter**: Shows progress and summary table in terminal - **HTML Report**: Interactive web interface with screenshots, videos, and traces - **JSON Report**: Machine-readable format in `test-results/results.json` - **GitHub Actions**: Annotations in CI for failed tests ### Debugging Failed Tests When tests fail, Playwright automatically captures: - **Screenshots** at the point of failure - **Videos** of the entire test run - **Traces** with timeline and network activity - **Error context** with detailed debugging information All debugging artifacts are available in the HTML report for easy analysis. ## Configuration - **Config**: `playwright.config.ts` - matches Cypress settings - **Base URL**: `http://localhost:8088` (assumes Superset running) - **Browsers**: Chrome only for Phase 1 (YAGNI) - **Retries**: 2 in CI, 0 locally (matches Cypress) ## Contributing Guidelines ### Adding New Tests 1. **Check existing components** before creating new ones 2. **Use page objects** for page interactions 3. **Keep assertions in tests**, not page objects 4. **Follow naming conventions**: `feature.spec.ts` ### Adding New Components 1. **Follow YAGNI**: Only build what's immediately needed 2. **Use Locator-based scoping** for proper element isolation 3. **Support both string selectors and Locator objects** via constructor overloads 4. **Add to `components/core/index.ts`** for easy importing ### Adding New Page Objects 1. **Centralize selectors** in private static SELECTORS constant 2. **Import shared constants** from `utils/urls.ts` 3. **Actions and queries only** - no assertions 4. **Use existing components** for DOM interactions ## Migration from Cypress When porting Cypress tests: 1. **Port the logic**, not the implementation 2. **Use page objects** instead of inline selectors 3. **Replace `cy.intercept/cy.wait`** with `page.waitForRequest()` 4. **Use shared constants** from `utils/urls.ts` 5. **Follow the established patterns** shown in `tests/auth/login.spec.ts` ## Best Practices - **Centralize selectors** in page objects - **Centralize URLs** in `utils/urls.ts` - **Use meaningful test descriptions** - **Keep page objects action-focused** - **Put assertions in tests, not page objects** - **Follow the existing patterns** for consistency