Arre uses Playwright for comprehensive end-to-end (E2E) testing across multiple browsers and devices. Tests run against Firebase Emulators to ensure a consistent, reproducible testing environment.
Overview
The testing infrastructure provides:
Multi-browser coverage : Chromium, Firefox, and WebKit
Local Firebase Emulators for Auth and Firestore
Interactive UI mode for debugging
CI/CD integration with GitHub Actions
Parallel test execution for faster feedback
Getting Started
Install dependencies
Ensure all project dependencies are installed:
Install Playwright browsers
Playwright requires its own browser binaries: This downloads Chromium, Firefox, and WebKit test browsers.
Run tests
Execute the full test suite:
Running Tests
All Tests (Headless)
Interactive UI Mode
Specific Browser
Specific Test File
Run the complete test suite in headless mode: Or use the npm script: This executes all tests across Chromium, Firefox, and WebKit. Launch the Playwright UI for interactive debugging: Or via npm: UI mode lets you step through tests, inspect DOM state, view network requests, and see console logs in real-time.
Run tests on a single browser: # Chromium only
npx playwright test --project=chromium
# Firefox only
npx playwright test --project=firefox
# WebKit only
npx playwright test --project=webkit
Run a single test file: npx playwright test tests/new-task.spec.ts
Or use grep to filter by test name: npx playwright test -g "manual task"
Test Configuration
The Playwright configuration is defined in playwright.config.ts:6:
export default defineConfig ({
testDir: "./tests" ,
fullyParallel: true ,
forbidOnly: !! process . env . CI ,
retries: process . env . CI ? 2 : 0 ,
workers: process . env . CI ? 1 : undefined ,
reporter: process . env . CI
? [[ "html" ], [ "json" , { outputFile: "test-results.json" }]]
: "html" ,
use: {
baseURL: "http://localhost:5173" ,
trace: "on-first-retry" ,
} ,
projects: [
{ name: "chromium" , use: { ... devices [ "Desktop Chrome" ] } },
{ name: "firefox" , use: { ... devices [ "Desktop Firefox" ] } },
{ name: "webkit" , use: { ... devices [ "Desktop Safari" ] } },
] ,
webServer: {
command: "npm run dev" ,
url: "http://localhost:5173" ,
reuseExistingServer: ! process . env . CI ,
} ,
}) ;
Key Configuration Options
Option Description baseURLhttp://localhost:5173 - Vite dev serverfullyParallelRuns test files in parallel for speed retries2 retries on CI, 0 locally for faster debugging workers1 worker on CI (stability), unlimited locally traceCaptures trace on first retry for debugging webServerAuto-starts dev server before tests
The webServer option automatically starts npm run dev before running tests and stops it afterward.
Browser Coverage
Tests run on three major browser engines:
Chromium - Chrome, Edge, Brave, Opera
Firefox - Firefox
WebKit - Safari
Mobile viewports are currently disabled to focus on the desktop MVP:
// TEMPORARILY DISABLED: Focusing on Web (Desktop) MVP
// { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
// { name: 'Mobile Safari', use: { ...devices['iPhone 12'] } },
Test Structure
Test Files
Tests are organized by feature area:
tests/new-task.spec.ts - New Task modal flows
tests/task-actions.spec.ts - Task operations (complete, reschedule, delete)
tests/project-management.spec.ts - Project CRUD and organization
tests/logbook.spec.ts - Logbook view and completed tasks
tests/full-flow.spec.ts - End-to-end user journeys
tests/utils.ts - Shared test utilities
Writing Tests
Use data-testid attributes for reliable selectors:
< button data-testid = "btn-new-task-main" > New Task </ button >
Avoid CSS class selectors or text-based selectors that break when styling or copy changes. Use data-testid instead.
Test Examples
Manual Task Creation
From tests/new-task.spec.ts:45:
test ( 'should create a manual task' , async ({ page }) => {
await openModal ( page );
await page . getByTestId ( 'tab-manual' ). click ();
const taskTitle = 'E2E Test Task ' + Date . now ();
await page . getByTestId ( 'input-title' ). fill ( taskTitle );
// Select energy level
const modal = page . getByTestId ( 'new-task-modal' );
await modal . getByText ( 'high' , { exact: true }). click ();
await page . getByTestId ( 'btn-create-task' ). click ();
// Verify task appears in list
await expect ( page . getByText ( taskTitle )). toBeVisible ({ timeout: 10000 });
});
Full User Journey
From tests/full-flow.spec.ts:38:
test ( 'should support the full task lifecycle across views' , async ({ page }) => {
// 1. Navigate to Upcoming
await page . goto ( '/upcoming' );
await expect ( page ). toHaveURL ( '/upcoming' );
// 2. Create a task for tomorrow
await openNewTaskModal ( page );
await page . getByTestId ( 'tab-manual' ). click ();
const tomorrowTask = 'Meeting with Team ' + Date . now ();
await page . getByTestId ( 'input-title' ). fill ( tomorrowTask );
// Set date to tomorrow
const tomorrow = new Date ();
tomorrow . setDate ( tomorrow . getDate () + 1 );
const dateStr = tomorrow . toISOString (). split ( 'T' )[ 0 ];
await page . locator ( 'input[type="date"]' ). fill ( dateStr );
await page . getByTestId ( 'btn-create-task' ). click ();
// 3. Verify it appears in Upcoming
await expect ( page . getByText ( tomorrowTask )). toBeVisible ({ timeout: 10000 });
});
Test Utilities
Shared utilities in tests/utils.ts:3:
export async function login ( page : Page ) {
await page . goto ( '/login' );
await page . getByTestId ( 'dev-login-button' ). click ();
// Wait for redirect to dashboard
await expect ( page ). toHaveURL ( '/' );
}
Firebase Emulator Integration
Tests run against Firebase Emulators for:
Authentication - Anonymous dev login
Firestore - Isolated test database
Emulator Configuration
In CI, tests start emulators automatically:
CI = true npx firebase emulators:exec "npx playwright test" --project demo-test
Environment variables for emulator mode:
VITE_FIREBASE_API_KEY = "demo-api-key"
VITE_FIREBASE_AUTH_DOMAIN = "demo-test.firebaseapp.com"
VITE_FIREBASE_PROJECT_ID = "demo-test"
The emulator provides a clean, isolated environment for each test run. Data is ephemeral and discarded after tests complete.
Debugging Failed Tests
Check test output
Playwright displays detailed error messages: Error: locator.click: Timeout 30000ms exceeded.
=========================== logs ===========================
waiting for getByTestId ( 'btn-create-task' )
View trace files
Traces are captured on first retry. Open them with: npx playwright show-trace trace.zip
This shows:
Screenshot at each step
DOM snapshot
Network requests
Console logs
Use UI mode for live debugging
Run tests interactively: Step through actions, pause execution, and inspect state.
CI Integration
Tests run automatically on every pull request via the AI QA Agent workflow. See the CI/CD documentation for details.
On CI, tests run in Chromium only with 2 retries for flaky test resilience.
Best Practices
Use data-testid for selectors - Avoid brittle CSS or text selectors
Wait for async operations - Use expect().toBeVisible({ timeout: 10000 }) for Firestore sync
Generate unique test data - Use Date.now() to avoid conflicts
Clean up test state - Firebase emulators reset between runs automatically
Test user journeys, not implementation - Focus on what users do, not how code works
Next Steps
CI/CD Pipeline Learn how tests integrate with GitHub Actions and the AI QA Agent
Deployment Deploy to Firebase Hosting after tests pass