Skip to content

Commit 0969e00

Browse files
committed
refactor(e2e): rewrite test suite to focus on user journeys
Completely rewrites the E2E test suite from ~2000 lines to ~280 lines, focusing on critical user journeys rather than edge cases. Changes: - Remove heavy mocking infrastructure (setup-api-mocks, api-responses) - Delete 8 verbose spec files with defensive assertions - Add 6 focused spec files testing real user journeys - Add data-testid attributes to ServiceCard and GroupedServiceCard - Add dotenv loading to playwright config for environment variables - Skip database-dependent tests gracefully when MONGODB_URI unavailable Test coverage: - 10 tests always run (smoke, location pages, navigation, touch targets) - 10 tests require database (find-help flow, organisation pages, services) In PRs without secrets: 10 pass, 10 skip with clear message On main/staging with secrets: all 20 tests pass
1 parent 7c07ed7 commit 0969e00

21 files changed

+292
-2501
lines changed

config/playwright.config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
import { defineConfig } from '@playwright/test';
2+
import * as dotenv from 'dotenv';
3+
import * as path from 'path';
4+
import { fileURLToPath } from 'url';
5+
6+
// Load environment variables from .env file (ESM compatible)
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
dotenv.config({ path: path.resolve(__dirname, '../.env') });
210

311
export default defineConfig({
412
testDir: '../tests/e2e',

src/components/FindHelp/FindHelpResults.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ export default React.memo(function FindHelpResults({
376376
</div>
377377
</div>
378378
) : sortedGroups.length === 0 ? (
379-
<div className="text-center py-8">
379+
<div className="text-center py-8" data-testid="no-results">
380380
<p className="text-gray-600 mb-2">No services found matching your criteria.</p>
381381
<p className="text-sm text-gray-500">Try adjusting your filters or search in a different area.</p>
382382
</div>

src/components/FindHelp/GroupedServiceCard.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ const GroupedServiceCard = React.memo(function GroupedServiceCard({
105105
}}
106106
className={`card card-compact ${isLoading ? 'loading-card' : ''}`}
107107
aria-label={`View details for ${decodedOrgName}`}
108+
data-testid="service-card"
108109
>
109110
<div className="flex justify-between items-start mb-2">
110111
<div className="flex items-center gap-2 flex-wrap">

src/components/FindHelp/ServiceCard.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,14 @@ const ServiceCard = React.memo(function ServiceCard({ service, isOpen, onToggle,
107107
decodedOrgName,
108108
categoryName
109109
);
110-
110+
111111
if (onCardClick) {
112112
onCardClick();
113113
}
114114
}}
115115
className={`card card-compact ${isLoading ? 'loading-card' : ''}`}
116116
aria-label={`View details for ${decodedName}`}
117+
data-testid="service-card"
117118
>
118119
<div className="flex justify-between items-start mb-2">
119120
<div className="flex items-center gap-2 flex-wrap">

tests/e2e/error-handling.spec.ts

Lines changed: 0 additions & 460 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { test, expect, TEST_LOCATION, HAS_DATABASE } from './fixtures/base-test';
2+
3+
test.describe('Find Help Journey', () => {
4+
// All tests in this suite require database access
5+
test.beforeEach(async () => {
6+
test.skip(!HAS_DATABASE, 'Skipping - requires database connection (MONGODB_URI)');
7+
});
8+
9+
test('find services by selecting location', async ({ page }) => {
10+
await page.goto('/find-help');
11+
12+
// Click to show location options
13+
await page.getByRole('button', { name: /enter postcode/i }).click();
14+
15+
// Select Manchester from the location dropdown
16+
await page.locator('#location-select').selectOption(TEST_LOCATION.slug);
17+
18+
// Click find services
19+
await page.getByRole('button', { name: /find services in/i }).click();
20+
21+
// Should show services results page - wait for service cards to appear
22+
await expect(page.locator('[data-testid="service-card"]').first()).toBeVisible({ timeout: 30000 });
23+
});
24+
25+
test('filter services by category', async ({ page }) => {
26+
// Start with location already set via URL params
27+
await page.goto(`/find-help?lat=${TEST_LOCATION.lat}&lng=${TEST_LOCATION.lng}`);
28+
29+
// Wait for services to load
30+
await expect(page.locator('[data-testid="service-card"]').first()).toBeVisible({ timeout: 30000 });
31+
32+
// Select a category filter
33+
const categorySelect = page.locator('#category');
34+
await categorySelect.selectOption({ index: 1 });
35+
36+
// Page should update (either show filtered results or "no results")
37+
await expect(
38+
page.locator('[data-testid="service-card"], [data-testid="no-results"]').first()
39+
).toBeVisible();
40+
});
41+
42+
test('view service details', async ({ page }) => {
43+
await page.goto(`/find-help?lat=${TEST_LOCATION.lat}&lng=${TEST_LOCATION.lng}`);
44+
45+
// Wait for services
46+
await expect(page.locator('[data-testid="service-card"]').first()).toBeVisible();
47+
48+
// Click first service
49+
await page.locator('[data-testid="service-card"]').first().click();
50+
51+
// Should navigate to organisation page
52+
await expect(page).toHaveURL(/\/find-help\/organisation\//);
53+
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
54+
});
55+
56+
test('toggle map view', async ({ page }) => {
57+
await page.goto(`/find-help?lat=${TEST_LOCATION.lat}&lng=${TEST_LOCATION.lng}`);
58+
59+
// Wait for services
60+
await expect(page.locator('[data-testid="service-card"]').first()).toBeVisible({ timeout: 30000 });
61+
62+
// Toggle map on
63+
await page.getByRole('button', { name: /show map/i }).click();
64+
await expect(page.locator('[data-testid="map-container"]')).toBeVisible();
65+
66+
// Toggle map off
67+
await page.getByRole('button', { name: /hide map/i }).click();
68+
await expect(page.locator('[data-testid="map-container"]')).not.toBeVisible();
69+
});
70+
71+
test('use geolocation', async ({ page, context }) => {
72+
// Grant geolocation permission
73+
await context.grantPermissions(['geolocation']);
74+
await context.setGeolocation({ latitude: TEST_LOCATION.lat, longitude: TEST_LOCATION.lng });
75+
76+
await page.goto('/find-help');
77+
78+
// Click use location
79+
await page.getByRole('button', { name: /use my current location/i }).click();
80+
81+
// Should show services
82+
await expect(page.locator('[data-testid="service-card"]').first()).toBeVisible({ timeout: 30000 });
83+
});
84+
});

0 commit comments

Comments
 (0)