Skip to main content

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.