Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ cypress/integration/examples
.netlify
.env
.astro

# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
64 changes: 64 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# E2E Tests with Playwright and Guidepup

This directory contains end-to-end tests for the website using Playwright and Guidepup for accessibility testing.

## Prerequisites

Before running the tests, you need to install Playwright browsers:

```bash
pnpm exec playwright install --with-deps chromium
```

## Running Tests

There are several ways to run the tests:

### Run all tests (headless)
```bash
pnpm run test:e2e
```

### Run tests with UI mode (recommended for development)
```bash
pnpm run test:e2e:ui
```

### Run tests in headed mode (see the browser)
```bash
pnpm run test:e2e:headed
```

### Debug mode
```bash
pnpm run test:e2e:debug
```

### View test report
```bash
pnpm run test:e2e:report
```

## Test Structure

- `smoke.spec.ts` - Basic smoke tests that verify:
- The site renders successfully
- The page title is correct
- Main heading is visible
- Page structure includes proper landmarks
- Links are accessible
- Screen reader accessibility (VoiceOver on macOS)
- Proper heading hierarchy

## Accessibility Testing

The tests include Guidepup integration for screen reader testing. The VoiceOver test will only run on macOS with WebKit browser.

## Configuration

The Playwright configuration is in `playwright.config.ts` at the root of the project. It's configured to:

- Start the dev server automatically before running tests
- Use http://localhost:4321 as the base URL
- Run tests in Chromium by default
- Generate an HTML report after test completion
88 changes: 88 additions & 0 deletions e2e/smoke.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { test, expect } from '@playwright/test';
import { voiceOver } from '@guidepup/playwright';

test.describe('Smoke tests', () => {
test('should render the homepage successfully', async ({ page }) => {
await page.goto('/');

// Wait for the page to be fully loaded
await page.waitForLoadState('networkidle');

// Check that the page has loaded
expect(await page.title()).toBeTruthy();
});

test('should display the correct page title', async ({ page }) => {
await page.goto('/');

// Verify the page title
const title = await page.title();
expect(title).toContain('Dan Matthew is an accessibility and design systems consultant');
});

test('should have the main heading visible', async ({ page }) => {
await page.goto('/');

// Check for the main heading text
const heading = page.getByText('Accessibility and design systems consultant');
await expect(heading).toBeVisible();
});

test('should have proper page structure', async ({ page }) => {
await page.goto('/');

// Check for main landmark
const main = page.locator('main#main');
await expect(main).toBeVisible();

// Check for navigation
const nav = page.locator('nav');
await expect(nav).toBeVisible();
});

test('should have accessible links', async ({ page }) => {
await page.goto('/');

// Check that social links are present and accessible
const socialLinks = page.getByRole('link', { name: /github|linkedin|bluesky/i });
expect(await socialLinks.count()).toBeGreaterThan(0);
});
});

test.describe('Screen reader accessibility', () => {
test('should be navigable with VoiceOver', async ({ page, browserName }) => {
test.skip(browserName !== 'webkit', 'VoiceOver is only available on macOS');

await page.goto('/');

// Start VoiceOver
await voiceOver.start(page);

try {
// Navigate to the main content
await voiceOver.next();

// Get the spoken phrase
const spokenPhrase = await voiceOver.lastSpokenPhrase();

// Verify that VoiceOver is reading content
expect(spokenPhrase).toBeTruthy();

} finally {
// Always stop VoiceOver
await voiceOver.stop();
}
});

test('should have proper heading hierarchy', async ({ page }) => {
await page.goto('/');

// Check that headings are properly structured
const h1Count = await page.locator('h1').count();
expect(h1Count).toBeGreaterThanOrEqual(1);

// Verify the page has a logical heading structure
const headings = await page.locator('h1, h2, h3, h4, h5, h6').all();
expect(headings.length).toBeGreaterThan(0);
});
});
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"description": "",
"main": "index.js",
"devDependencies": {
"@guidepup/playwright": "^0.14.2",
"@playwright/test": "^1.56.1",
"eslint-config-prettier": "^9.1.0",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
Expand Down Expand Up @@ -36,6 +38,11 @@
"format:eslint": "eslint --ext .js,.html . --fix --ignore-path .gitignore",
"format:prettier": "prettier \"**/*.js\" --write",
"test": "cypress run --spec \"cypress/integration/home_page.spec.js\"",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:debug": "playwright test --debug",
"test:e2e:headed": "playwright test --headed",
"test:e2e:report": "playwright show-report",
"release": "npx standard-version && git push --follow-tags"
},
"repository": {
Expand Down
30 changes: 30 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineConfig, devices } from '@playwright/test';

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:4321',
trace: 'on-first-retry',
},

projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],

webServer: {
command: 'pnpm run dev',
url: 'http://localhost:4321',
reuseExistingServer: !process.env.CI,
},
});
Loading