Lab 23: E2E Testing with Playwright
π Resourcesβ
π Starter Codeβ
step-21-album-wholesale-v21-post-test-vittest
In this lab you will write end-to-end tests for the album wholesale app using Playwright. You will use role-based selectors, fill forms, and verify navigation flows.
π Instructionsβ
Step 1: Install Playwrightβ
npm install --save-dev @playwright/test
npx playwright install chromium
Then initialize the project structure:
npx playwright init
When prompted:
- TypeScript: Yes
- Tests folder:
e2e - Add GitHub Actions: No (for now)
Step 2: Configure Playwrightβ
Update playwright.config.ts:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
retries: 0,
use: {
baseURL: 'http://localhost:4200',
trace: 'on-first-retry',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
],
webServer: {
command: 'ng serve',
url: 'http://localhost:4200',
reuseExistingServer: !process.env['CI'],
},
});
Step 3: Write a Basic Navigation Testβ
Create e2e/navigation.spec.ts:
import { test, expect } from '@playwright/test';
test('homepage loads and shows album list', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
await expect(page.locator('.album-card').first()).toBeVisible();
});
test('can navigate to album detail', async ({ page }) => {
await page.goto('/');
await page.locator('.album-card').first().click();
await expect(page.getByRole('heading', { level: 2 })).toBeVisible();
});
Step 4: Test the Search / Filter Featureβ
Create e2e/search.spec.ts:
import { test, expect } from '@playwright/test';
test('can search for an album', async ({ page }) => {
await page.goto('/');
await page.getByRole('searchbox').fill('jazz');
await expect(page.locator('.album-card')).toHaveCount(
await page.locator('.album-card').count()
);
});
Step 5: Test the Cart Flowβ
Create e2e/cart.spec.ts:
import { test, expect } from '@playwright/test';
test('can add an album to the cart', async ({ page }) => {
await page.goto('/');
await page.locator('.album-card').first()
.getByRole('button', { name: /add to cart/i }).click();
await expect(page.getByTestId('cart-count')).toContainText('1');
});
test('cart persists across navigation', async ({ page }) => {
await page.goto('/');
await page.locator('.album-card').first()
.getByRole('button', { name: /add to cart/i }).click();
await page.getByRole('link', { name: /home/i }).click();
await expect(page.getByTestId('cart-count')).toContainText('1');
});
Step 6: Use Role-Based Selectorsβ
Prefer accessible selectors over CSS classes:
// By role
page.getByRole('button', { name: 'Submit' });
page.getByRole('link', { name: 'Home' });
page.getByRole('textbox', { name: 'Search' });
// By label
page.getByLabel('Email address');
// By test id (add data-testid attributes in template)
page.getByTestId('cart-count');
Step 7: Run the Testsβ
# Run all tests
npx playwright test
# Run with UI mode
npx playwright test --ui
# Run a specific file
npx playwright test e2e/cart.spec.ts
# Show HTML report
npx playwright show-report
If a test fails, Playwright captures a screenshot and trace automatically. Open the report to inspect the failure.