Skip to content

Commit 31e1e0b

Browse files
committed
Implement and debug service list and item view page e2e tests
1 parent 29cc7e7 commit 31e1e0b

2 files changed

Lines changed: 114 additions & 86 deletions

File tree

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,82 @@
11
/**
22
* Service Detail Page E2E Tests
33
* Tests for individual service pages
4-
* Note: Tests are generated dynamically per service
4+
* Note: Tests are dynamically generated for each service
55
*/
66
import { test, expect } from '@playwright/test'
7+
import { setupConsoleErrorChecker } from '@test/e2e/helpers/console-errors'
78

8-
test.describe('Service Detail Page', () => {
9-
test.skip('@wip service page loads with content', async ({ page }) => {
10-
// Expected: Service page should load with title and content
11-
// Actual: Unknown - needs testing
12-
// Note: Will dynamically generate tests per service
13-
await page.goto('/services/example-service')
14-
await expect(page.locator('h1')).toBeVisible()
15-
})
9+
/**
10+
* Create a test suite for a specific service
11+
*/
12+
function createServiceTests(serviceId: string, serviceTitle: string) {
13+
const serviceUrl = `/services/${serviceId}`
1614

17-
test.skip('@wip service overview section displays', async ({ page }) => {
18-
// Expected: Should show service overview/description
19-
// Actual: Unknown - needs testing
20-
await page.goto('/services/example-service')
21-
await expect(page.locator('article, .service-content')).toBeVisible()
22-
})
15+
test.describe(`Service: ${serviceTitle}`, () => {
16+
test('@ready service page loads with content', async ({ page }) => {
17+
await page.goto(serviceUrl)
18+
await page.waitForLoadState('networkidle')
2319

24-
test.skip('@wip features/benefits list present', async ({ page }) => {
25-
// Expected: Should show list of features or benefits
26-
// Actual: Unknown - needs testing
27-
await page.goto('/services/example-service')
28-
// Check for features list
29-
})
20+
// Page should have main content
21+
const main = page.locator('main')
22+
await expect(main).toBeVisible()
3023

31-
test.skip('@wip pricing information displays', async ({ page }) => {
32-
// Expected: Should show pricing or consultation info
33-
// Actual: Unknown - needs testing
34-
await page.goto('/services/example-service')
35-
// Check for pricing section
36-
})
24+
// Should have h1 heading (page may have multiple h1 in suggested services, use first)
25+
const heading = page.locator('h1').first()
26+
await expect(heading).toBeVisible()
3727

38-
test.skip('@wip contact CTA present', async ({ page }) => {
39-
// Expected: Should have CTA to contact or get started
40-
// Actual: Unknown - needs testing
41-
await page.goto('/services/example-service')
42-
const cta = page.locator('a[href*="contact"], button:has-text("Contact")')
43-
// CTA may not always be present
44-
})
28+
// Should have article container with id (main article, not carousel articles)
29+
const article = page.locator('article[itemscope]')
30+
await expect(article).toBeVisible()
31+
})
4532

46-
test.skip('@wip related services carousel displays', async ({ page }) => {
47-
// Expected: Should show related services if applicable
48-
// Actual: Unknown - needs testing
49-
await page.goto('/services/example-service')
50-
// Check for carousel
51-
})
33+
test('@ready service title displays correctly', async ({ page }) => {
34+
await page.goto(serviceUrl)
35+
// Use the main article heading, not headings from suggested services carousel
36+
const heading = page.locator('h1#article-title')
37+
await expect(heading).toContainText(serviceTitle)
38+
})
39+
40+
test('@ready service content renders', async ({ page }) => {
41+
await page.goto(serviceUrl)
5242

53-
test.skip('@wip page has no console errors', async ({ page }) => {
54-
// Expected: No console errors on page load
55-
// Actual: Unknown - needs testing
56-
await page.goto('/services/example-service')
57-
const errors: string[] = []
58-
page.on('console', (msg) => {
59-
if (msg.type() === 'error') errors.push(msg.text())
43+
// Should have content paragraphs
44+
const content = page.locator('article p')
45+
await expect(content.first()).toBeVisible()
46+
})
47+
48+
test('@ready suggested services carousel displays', async ({ page }) => {
49+
await page.goto(serviceUrl)
50+
51+
// Carousel should be present (if there are other services)
52+
const carousel = page.locator('.embla')
53+
// Carousel only shows if there are other services, so check count
54+
const count = await carousel.count()
55+
if (count > 0) {
56+
await expect(carousel.first()).toBeVisible()
57+
}
58+
})
59+
60+
test('@ready page has no console errors', async ({ page }) => {
61+
const errorChecker = setupConsoleErrorChecker(page)
62+
await page.goto(serviceUrl)
63+
await page.waitForLoadState('networkidle')
64+
65+
const filtered404s = errorChecker.getFiltered404s()
66+
expect(filtered404s.length).toBe(0)
67+
})
68+
69+
test('@ready page has no 404 errors', async ({ page }) => {
70+
const errorChecker = setupConsoleErrorChecker(page)
71+
await page.goto(serviceUrl)
72+
await page.waitForLoadState('networkidle')
73+
74+
const all404s = errorChecker.failed404s
75+
expect(all404s.length).toBe(0)
6076
})
61-
await page.reload()
62-
expect(errors).toHaveLength(0)
6377
})
64-
})
78+
}
79+
80+
// Generate tests for known services
81+
createServiceTests('overview', 'Services Overview')
82+
createServiceTests('create-custom-font-sets', 'Create Custom Font Sets')

‎test/e2e/specs/02-pages/services.spec.ts‎

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,70 @@
33
* Tests for /services index page
44
*/
55
import { test, expect } from '@playwright/test'
6-
import { TEST_URLS } from '../../fixtures/test-data'
6+
import { TEST_URLS } from '@test/e2e/fixtures/test-data'
7+
import { setupConsoleErrorChecker } from '@test/e2e/helpers/console-errors'
78

89
test.describe('Services List Page', () => {
910
test.beforeEach(async ({ page }) => {
1011
await page.goto(TEST_URLS.services)
1112
})
1213

13-
test.skip('@wip page loads with correct title', async ({ page }) => {
14-
// Expected: Services page should have descriptive title
15-
// Actual: Unknown - needs testing
14+
test('@ready page loads with correct title', async ({ page }) => {
1615
await expect(page).toHaveTitle(/Services/)
1716
})
1817

19-
test.skip('@wip hero section displays', async ({ page }) => {
20-
// Expected: Should have hero section with heading
21-
// Actual: Unknown - needs testing
22-
await expect(page.locator('h1')).toBeVisible()
18+
test('@ready page heading displays', async ({ page }) => {
19+
const heading = page.locator('h1')
20+
await expect(heading).toBeVisible()
21+
await expect(heading).toContainText(/Services/)
2322
})
2423

25-
test.skip('@wip services grid displays', async ({ page }) => {
26-
// Expected: Should show grid of service cards
27-
// Actual: Unknown - needs testing
28-
const serviceCards = page.locator('article, .service-card')
29-
await expect(serviceCards.first()).toBeVisible()
24+
test('@ready services section displays', async ({ page }) => {
25+
// Check for "Our Services" h2 heading
26+
const sectionHeading = page.locator('h2').filter({ hasText: 'Our Services' })
27+
await expect(sectionHeading).toBeVisible()
3028
})
3129

32-
test.skip('@wip service cards have required elements', async ({ page }) => {
33-
// Expected: Each card should have icon/image, title, description
34-
// Actual: Unknown - needs testing
35-
const firstCard = page.locator('article, .service-card').first()
36-
await expect(firstCard.locator('h2, h3')).toBeVisible()
30+
test('@ready service list displays', async ({ page }) => {
31+
// Services are in a list with .service-item class
32+
const serviceItems = page.locator('.service-item')
33+
await expect(serviceItems.first()).toBeVisible()
3734
})
3835

39-
test.skip('@wip service links are functional', async ({ page }) => {
40-
// Expected: Clicking service should navigate to detail page
41-
// Actual: Unknown - needs testing
42-
const firstLink = page.locator('article a, .service-card a').first()
43-
await expect(firstLink).toHaveAttribute('href', /.+/)
36+
test('@ready service cards have required elements', async ({ page }) => {
37+
const firstCard = page.locator('.service-item').first()
38+
39+
// Each service should have h3 title
40+
await expect(firstCard.locator('h3')).toBeVisible()
41+
42+
// Should have a link to the service detail page
43+
await expect(firstCard.locator('a')).toBeVisible()
4444
})
4545

46-
test.skip('@wip CTA section present', async ({ page }) => {
47-
// Expected: Should have call-to-action for consultation
48-
// Actual: Unknown - needs testing
49-
// Check for CTA button or section
46+
test('@ready service links are functional', async ({ page }) => {
47+
const firstLink = page.locator('.service-item a').first()
48+
await expect(firstLink).toHaveAttribute('href', /\/services\/.+/)
5049
})
5150

52-
test.skip('@wip page has no console errors', async ({ page }) => {
53-
// Expected: No console errors on page load
54-
// Actual: Unknown - needs testing
55-
const errors: string[] = []
56-
page.on('console', (msg) => {
57-
if (msg.type() === 'error') errors.push(msg.text())
58-
})
59-
await page.reload()
60-
expect(errors).toHaveLength(0)
51+
test('@ready clicking service navigates to detail page', async ({ page }) => {
52+
const firstLink = page.locator('.service-item a').first()
53+
const href = await firstLink.getAttribute('href')
54+
55+
await firstLink.click()
56+
await page.waitForLoadState('networkidle')
57+
58+
expect(page.url()).toContain(href!)
59+
})
60+
61+
test('@ready responsive: mobile view renders correctly', async ({ page }) => {
62+
await page.setViewportSize({ width: 375, height: 667 })
63+
await expect(page.locator('.service-item').first()).toBeVisible()
64+
})
65+
66+
test('@ready page has no console errors', async ({ page }) => {
67+
const errorChecker = setupConsoleErrorChecker(page)
68+
await page.goto(TEST_URLS.services)
69+
await page.waitForLoadState('networkidle')
70+
expect(errorChecker.getFiltered404s().length).toBe(0)
6171
})
6272
})

0 commit comments

Comments
 (0)