diff --git a/.gitignore b/.gitignore index 28f8ac3..f9b94f8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ node_modules .output .idea /test-results +playwright-report diff --git a/.husky/pre-commit b/.husky/pre-commit index 2312dc5..3496908 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,2 @@ npx lint-staged +npm run test diff --git a/README.md b/README.md index 3129065..285f736 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,18 @@ This is currently a WIP. Please feel free to raise any issues that you come acro 1. Install dependencies: -```bash -npm install -``` + ```bash + npm install + ``` 2. Start the app: -```bash -npm run dev + ```bash + npm run dev -# or start the server and open the app in a new browser tab -npm run dev -- --open -``` + # or start the server and open the app in a new browser tab + npm run dev -- --open + ``` ## Running the tests @@ -38,7 +38,11 @@ npm run test:ui You can also run them via the Playwright VS Code extension. -The tests generate page previews in different device sizes. The screenshots are saved under `tests\page-previews`. +### Visual comparison tests + +The tests generate page previews in different device sizes and test to ensure that they haven't changed. The screenshots are saved under `tests\__screenshots__`. and can be regenerated with `npm run test:update-screenshots`. + +If a visual test fails, look under the attachments in the report for a visual diff. ## Contributing @@ -77,3 +81,20 @@ Background colour classes to set the sections to the predefined colours: ``` + +### Tests + +When adding a new page, add the name and route to `tests\all-pages-to-test.ts` to enable automated accessibility and visual comparison tests. + +If adding or changing a link in the nav, ensure it is add/changed in `tests\navigation.spec.ts`. + +### Pre-commit hooks + +> [!IMPORTANT] +> Playwright tests are run on pre-commit hooks and will fail if Playwright is not installed. See [running the tests](#running-the-tests) for info on how to set up Playwright + +Pre-commit hooks are managed by [Husky](https://typicode.github.io/husky/get-started.html) and will be run whenever you make a commit. If they fail then the commit will be aborted and you will see an error. + +To run pre-commit hooks without committing, stage all your changes and then execute the `.husky/pre-commit` file. + +To commit but skip pre-commit hooks, run `git commit -m "my amazing commit message" --no-verify` diff --git a/package.json b/package.json index 1fcf7e9..eca4bf0 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "build": "vite build", "package": "svelte-kit package", "preview": "vite preview", - "test": "playwright test --retries=3", + "test": "playwright test", "test:ui": "playwright test --ui", - "test:page-previews": "playwright test tests/page-previews.spec.ts", + "test:update-screenshots": "playwright test tests/visual-comparison.spec.ts --update-snapshots", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --check . & eslint .", diff --git a/playwright.config.ts b/playwright.config.ts index e55fe61..24393ae 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,6 +1,6 @@ -import type { PlaywrightTestConfig } from '@playwright/test'; +import { defineConfig } from '@playwright/test'; -const config: PlaywrightTestConfig = { +export default defineConfig({ webServer: { command: 'npm run dev', url: 'http://127.0.0.1:5173', @@ -9,7 +9,8 @@ const config: PlaywrightTestConfig = { use: { baseURL: 'http://127.0.0.1:5173/' }, - fullyParallel: true -}; - -export default config; + fullyParallel: true, + reporter: [['list'], ['html']], + testDir: './tests', + snapshotPathTemplate: '{testDir}/__screenshots__/{arg}{ext}' +}); diff --git a/tests/__screenshots__/About-desktop.png b/tests/__screenshots__/About-desktop.png new file mode 100644 index 0000000..f0aa17b Binary files /dev/null and b/tests/__screenshots__/About-desktop.png differ diff --git a/tests/__screenshots__/About-mobile.png b/tests/__screenshots__/About-mobile.png new file mode 100644 index 0000000..4e42188 Binary files /dev/null and b/tests/__screenshots__/About-mobile.png differ diff --git a/tests/__screenshots__/About-tablet.png b/tests/__screenshots__/About-tablet.png new file mode 100644 index 0000000..3081e18 Binary files /dev/null and b/tests/__screenshots__/About-tablet.png differ diff --git a/tests/__screenshots__/Code-of-conduct-desktop.png b/tests/__screenshots__/Code-of-conduct-desktop.png new file mode 100644 index 0000000..a80e954 Binary files /dev/null and b/tests/__screenshots__/Code-of-conduct-desktop.png differ diff --git a/tests/__screenshots__/Code-of-conduct-internal--desktop.png b/tests/__screenshots__/Code-of-conduct-internal--desktop.png new file mode 100644 index 0000000..0d6cfca Binary files /dev/null and b/tests/__screenshots__/Code-of-conduct-internal--desktop.png differ diff --git a/tests/__screenshots__/Code-of-conduct-internal--mobile.png b/tests/__screenshots__/Code-of-conduct-internal--mobile.png new file mode 100644 index 0000000..29d2734 Binary files /dev/null and b/tests/__screenshots__/Code-of-conduct-internal--mobile.png differ diff --git a/tests/__screenshots__/Code-of-conduct-internal--tablet.png b/tests/__screenshots__/Code-of-conduct-internal--tablet.png new file mode 100644 index 0000000..ce49d32 Binary files /dev/null and b/tests/__screenshots__/Code-of-conduct-internal--tablet.png differ diff --git a/tests/__screenshots__/Code-of-conduct-mobile.png b/tests/__screenshots__/Code-of-conduct-mobile.png new file mode 100644 index 0000000..3245f27 Binary files /dev/null and b/tests/__screenshots__/Code-of-conduct-mobile.png differ diff --git a/tests/__screenshots__/Code-of-conduct-tablet.png b/tests/__screenshots__/Code-of-conduct-tablet.png new file mode 100644 index 0000000..8641e84 Binary files /dev/null and b/tests/__screenshots__/Code-of-conduct-tablet.png differ diff --git a/tests/__screenshots__/Home-desktop.png b/tests/__screenshots__/Home-desktop.png new file mode 100644 index 0000000..5368526 Binary files /dev/null and b/tests/__screenshots__/Home-desktop.png differ diff --git a/tests/__screenshots__/Home-mobile.png b/tests/__screenshots__/Home-mobile.png new file mode 100644 index 0000000..f3e3e57 Binary files /dev/null and b/tests/__screenshots__/Home-mobile.png differ diff --git a/tests/__screenshots__/Home-tablet.png b/tests/__screenshots__/Home-tablet.png new file mode 100644 index 0000000..f0d09bb Binary files /dev/null and b/tests/__screenshots__/Home-tablet.png differ diff --git a/tests/__screenshots__/New-speakers-workshop-desktop.png b/tests/__screenshots__/New-speakers-workshop-desktop.png new file mode 100644 index 0000000..109e074 Binary files /dev/null and b/tests/__screenshots__/New-speakers-workshop-desktop.png differ diff --git a/tests/__screenshots__/New-speakers-workshop-mobile.png b/tests/__screenshots__/New-speakers-workshop-mobile.png new file mode 100644 index 0000000..2509eff Binary files /dev/null and b/tests/__screenshots__/New-speakers-workshop-mobile.png differ diff --git a/tests/__screenshots__/New-speakers-workshop-tablet.png b/tests/__screenshots__/New-speakers-workshop-tablet.png new file mode 100644 index 0000000..fa8abab Binary files /dev/null and b/tests/__screenshots__/New-speakers-workshop-tablet.png differ diff --git a/tests/__screenshots__/Sponsorship-desktop.png b/tests/__screenshots__/Sponsorship-desktop.png new file mode 100644 index 0000000..c90c038 Binary files /dev/null and b/tests/__screenshots__/Sponsorship-desktop.png differ diff --git a/tests/__screenshots__/Sponsorship-mobile.png b/tests/__screenshots__/Sponsorship-mobile.png new file mode 100644 index 0000000..866157e Binary files /dev/null and b/tests/__screenshots__/Sponsorship-mobile.png differ diff --git a/tests/__screenshots__/Sponsorship-tablet.png b/tests/__screenshots__/Sponsorship-tablet.png new file mode 100644 index 0000000..36451f0 Binary files /dev/null and b/tests/__screenshots__/Sponsorship-tablet.png differ diff --git a/tests/__screenshots__/Venue-desktop.png b/tests/__screenshots__/Venue-desktop.png new file mode 100644 index 0000000..44de81d Binary files /dev/null and b/tests/__screenshots__/Venue-desktop.png differ diff --git a/tests/__screenshots__/Venue-mobile.png b/tests/__screenshots__/Venue-mobile.png new file mode 100644 index 0000000..bc84e20 Binary files /dev/null and b/tests/__screenshots__/Venue-mobile.png differ diff --git a/tests/__screenshots__/Venue-tablet.png b/tests/__screenshots__/Venue-tablet.png new file mode 100644 index 0000000..e219f42 Binary files /dev/null and b/tests/__screenshots__/Venue-tablet.png differ diff --git a/tests/a11y.spec.ts b/tests/a11y.spec.ts index 644e70c..c8b4270 100644 --- a/tests/a11y.spec.ts +++ b/tests/a11y.spec.ts @@ -1,5 +1,7 @@ import { test, devices, expect } from '@playwright/test'; import AxeBuilder from '@axe-core/playwright'; +import { devicesToTest } from './all-devices-to-test'; +import { pagesToTest } from './all-pages-to-test'; let accessibilityScanner: AxeBuilder; @@ -12,28 +14,12 @@ test.beforeEach(({ page }) => { ]); }); -const viewPorts = new Map([ - ['mobile', 'iPhone SE'], - ['tablet', 'iPad Mini'], - ['desktop', 'Desktop Chrome'] -]); -for (const [viewportName, viewportDevice] of viewPorts) { - //Home page - test(`Home page a11y checks - ${viewportName}`, async ({ page }) => { - await page.setViewportSize(devices[viewportDevice].viewport); +for (const [pageName, path] of pagesToTest) { + for (const [deviceName, deviceViewport] of devicesToTest) { + test(`${pageName} page a11y checks on ${deviceName}}`, async ({ page }) => { + await page.setViewportSize(devices[deviceViewport].viewport); - await page.goto('/'); - - await reportAccessibilityViolations(); - }); - - // Content pages - const routes = ['about', 'sponsorship', '2024', 'code-of-conduct', 'new-speakers-workshop']; - for (const route of routes) { - test(`${route} page a11y checks - ${viewportName}`, async ({ page }) => { - await page.setViewportSize(devices[viewportDevice].viewport); - - await page.goto(route); + await page.goto(path); await reportAccessibilityViolations(); }); @@ -42,7 +28,7 @@ for (const [viewportName, viewportDevice] of viewPorts) { async function reportAccessibilityViolations() { // Scan the page with axe to look for a11y violations - let violations = (await accessibilityScanner.analyze()).violations; + const violations = (await accessibilityScanner.analyze()).violations; // Make Playwright output the key information as a (more) human readable string let violationDescription = ''; @@ -50,14 +36,14 @@ async function reportAccessibilityViolations() { violationDescription = `Warning - ${violations.length} a11y rule violations found\n\n`; for (let i = 0; i < violations.length; i++) { - let violation = violations[i]; + const violation = violations[i]; violationDescription += `########################################################\n`; violationDescription += `Rule Violation ${i + 1}\n`; violationDescription += `${violation.impact?.toUpperCase()} - ${violation.help}\n`; violationDescription += `${violation.helpUrl}\n`; for (let j = 0; j < violation.nodes.length; j++) { - let instance = violation.nodes[j]; + const instance = violation.nodes[j]; violationDescription += `--------------------------------------------------------\n`; violationDescription += `Instance ${j + 1}/${violation.nodes.length}\n\n`; diff --git a/tests/all-devices-to-test.ts b/tests/all-devices-to-test.ts new file mode 100644 index 0000000..0ed6f15 --- /dev/null +++ b/tests/all-devices-to-test.ts @@ -0,0 +1,5 @@ +export const devicesToTest: [deviceName: string, deviceViewport: string][] = [ + ['desktop', 'Desktop Chrome'], + ['tablet', 'iPad Mini'], + ['mobile', 'iPhone SE'] +]; diff --git a/tests/all-pages-to-test.ts b/tests/all-pages-to-test.ts new file mode 100644 index 0000000..4a40405 --- /dev/null +++ b/tests/all-pages-to-test.ts @@ -0,0 +1,9 @@ +export const pagesToTest: [pageName: string, path: string][] = [ + ['Home', '/'], + ['About', 'about'], + ['Sponsorship', 'sponsorship'], + ['Venue', 'venue'], + ['Code of conduct', 'code-of-conduct'], + ['Code of conduct (internal)', 'code-of-conduct/internal'], + ['New speakers workshop', 'new-speakers-workshop'] +]; diff --git a/tests/navbar.spec.ts b/tests/navbar.spec.ts index ccd9de5..091d464 100644 --- a/tests/navbar.spec.ts +++ b/tests/navbar.spec.ts @@ -1,96 +1,85 @@ import { test, expect, devices } from '@playwright/test'; +import { Header } from './page-object/header'; -test('Clicking nav button displays nav links dropdown', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); +test.describe('Navbar', () => { + let header: Header; - // Click nav drop down - await page.locator('.main-nav-button').click(); + test.beforeEach(async ({ page }) => { + // Go to about page (to avoid carousel weirdness) + await page.goto('/about'); - await expect(page.locator('.nav-link-container')).toBeVisible(); -}); + //Ensure everything has loaded to prevent flakiness + await page.waitForLoadState('networkidle'); -test('Clicking nav button closes nav links dropdown', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + header = new Header(page); + }); - // Click nav drop down - await page.locator('.main-nav-button').click(); + test('Clicking nav button displays nav links dropdown', async () => { + // Click nav drop down + await header.navDropDownButton.click(); - // Click nav drop down again - await page.locator('.main-nav-button').click(); + await expect(header.navDropDown).toBeVisible(); + }); - await expect(page.locator('.nav-link-container')).toBeHidden(); -}); + test('Clicking nav button closes nav links dropdown', async () => { + // Click nav drop down + await header.navDropDownButton.click(); -test('Clicking nav link closes nav links dropdown', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + // Click nav drop down again + await header.navDropDownButton.click(); - // Click nav drop down - await page.locator('.main-nav-button').click(); + await expect(header.navDropDown).toBeHidden(); + }); - // Click a nav link - await page.locator('.nav-link-container a[href="/sponsorship"]').click(); + test('Clicking nav link closes nav links dropdown', async () => { + // Click nav drop down + await header.navDropDownButton.click(); - await expect(page.locator('.nav-link-container')).toBeHidden(); -}); + // Click a nav link + await header.getNavLinkTo('sponsorship').click(); -test('Clicking logo closes nav links dropdown', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + await expect(header.navDropDown).toBeHidden(); + }); - // Click nav drop down - await page.locator('.main-nav-button').click(); + test('Clicking logo closes nav links dropdown', async () => { + // Click nav drop down + await header.navDropDownButton.click(); - // Click logo - await page.locator('img[class~="logo"]').click(); + // Click logo + await header.logo.click(); - await expect(page.locator('.nav-link-container')).toBeHidden(); -}); + await expect(header.navDropDown).toBeHidden(); + }); -test('Clicking logo does not open nav links dropdown', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + test('Clicking logo does not open nav links dropdown', async () => { + // Click logo + await header.logo.click(); - // Click logo - await page.locator('img[class~="logo"]').click(); + await expect(header.navDropDown).toBeHidden(); + }); - await expect(page.locator('.nav-link-container')).toBeHidden(); -}); - -test('Displays down arrow icon in unexpanded state', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + test('Displays down arrow icon in unexpanded state', async () => { + await expect(header.navDropDownButton).toContainText('expand_more'); + }); - await expect(page.locator('.main-nav-button span.icon')).toContainText('expand_more'); -}); + test('Displays up arrow icon in expanded state', async () => { + // Click nav drop down + await header.navDropDownButton.click(); -test('Displays up arrow icon in expanded state', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + await expect(header.navDropDownButton).toContainText('expand_less'); + }); - // Click nav drop down - await page.locator('.main-nav-button').click(); - - await expect(page.locator('.main-nav-button span.icon')).toContainText('expand_less'); -}); - -test('Does not show current route in nav links drop down', async ({ page }) => { - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); - - // Click nav drop down - await page.locator('.main-nav-button').click(); - - await expect(page.locator('.nav-link-container a[href="/about"]')).toBeHidden(); -}); + test('Does not show current route in nav links drop down', async () => { + // Click nav drop down + await header.navDropDownButton.click(); -test('Does not show button text in smaller screens', async ({ page }) => { - await page.setViewportSize(devices['iPhone SE'].viewport); + await expect(header.getNavLinkTo('about')).toBeHidden(); + }); - // Go to about page (to avoid carousel weirdness) - await page.goto('/about'); + test('Does not show button text in smaller screens', async ({ page }) => { + // Set to mobile view + await page.setViewportSize(devices['iPhone SE'].viewport); - await expect(page.locator('.nav-button-text')).toBeHidden(); + await expect(page.locator('.nav-button-text')).toBeHidden(); + }); }); diff --git a/tests/navigation.spec.ts b/tests/navigation.spec.ts index 97168ec..95ae61b 100644 --- a/tests/navigation.spec.ts +++ b/tests/navigation.spec.ts @@ -1,27 +1,59 @@ import { test, expect } from '@playwright/test'; +import { Header } from './page-object/header'; -const routes = ['about', 'sponsorship', '2024', 'code-of-conduct', 'new-speakers-workshop']; -for (const route of routes) { - test(`Can navigate to ${route} page from Home via the nav bar`, async ({ page }) => { - // Go to Home page - await page.goto('/'); +test.describe('Navigation', () => { + let header: Header; - // Click nav drop down - await page.locator('.main-nav-button').click(); + test.beforeEach(async ({ page }) => { + header = new Header(page); + }); + + test.describe('From home', () => { + test.beforeEach(async ({ page }) => { + // Go to Home page + await page.goto('/'); - // Click the nav link - await page.locator(`.nav-link-container a[href="/${route}"]`).click(); + //Ensure everything has loaded to prevent flakiness + await page.waitForLoadState('networkidle'); + }); - await expect(page).toHaveURL(`http://127.0.0.1:5173/${route}`); + const routes = ['about', 'sponsorship', 'code-of-conduct']; + for (const route of routes) { + test(`Can navigate to ${route} page via the nav bar`, async ({ page }) => { + // Click nav drop down + await header.navDropDownButton.click(); + + // Click the nav link + await header.getNavLinkTo(route).click(); + + await expect(page).toHaveURL(`http://127.0.0.1:5173/${route}`); + }); + } }); -} -test('Can navigate to Home from content page by clicking logo', async ({ page }) => { - // Go to about page - await page.goto('/about'); + test('Can navigate to Home from content page by clicking logo', async ({ page }) => { + // Go to about page + await page.goto('/about'); + //Ensure everything has loaded to prevent flakiness + await page.waitForLoadState('networkidle'); - // Click logo - await page.locator('img[class~="logo"]').click(); + // Click logo + await header.logo.click(); - await expect(page).toHaveURL('http://127.0.0.1:5173/'); + await expect(page).toHaveURL('http://127.0.0.1:5173/'); + }); + + test('Can navigate to Home from content page via the nav bar', async ({ page }) => { + // Go to about page + await page.goto('/about'); + //Ensure everything has loaded to prevent flakiness + await page.waitForLoadState('networkidle'); + + // Click nav drop down + await header.navDropDownButton.click(); + // Click nav link to home + await header.getNavLinkTo('').click(); + + await expect(page).toHaveURL('http://127.0.0.1:5173/'); + }); }); diff --git a/tests/page-object/header.ts b/tests/page-object/header.ts new file mode 100644 index 0000000..c21a4bb --- /dev/null +++ b/tests/page-object/header.ts @@ -0,0 +1,21 @@ +import type { Page, Locator } from '@playwright/test'; + +export class Header { + readonly page: Page; + readonly navMenu: Locator; + readonly navDropDownButton: Locator; + readonly navDropDown: Locator; + readonly logo: Locator; + + constructor(page: Page) { + this.page = page; + this.navDropDownButton = page.getByRole('button', { name: 'Find out more' }); + this.navMenu = page.getByRole('navigation').filter({ has: this.navDropDownButton }); + this.navDropDown = this.navMenu.locator('.nav-link-container'); + this.logo = page.getByRole('link', { name: 'The DDD South West logo' }); + } + + getNavLinkTo(route: string): Locator { + return this.navMenu.locator(`a[href="/${route}"]`); + } +} diff --git a/tests/page-previews.spec.ts b/tests/page-previews.spec.ts deleted file mode 100644 index bc4e6ad..0000000 --- a/tests/page-previews.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Tests to generate page previews in different screen sizes -import { test, devices, type Page } from '@playwright/test'; - -test('Captures Home preview - mobile', async ({ page }) => { - await page.setViewportSize(devices['iPhone SE'].viewport); - - await savePagePreviewImage(page, '/', 'home-mobile'); -}); - -test('Captures Home preview - tablet', async ({ page }) => { - await page.setViewportSize(devices['iPad Mini'].viewport); - - await savePagePreviewImage(page, '/', 'home-tablet'); -}); - -test('Captures Home preview - desktop', async ({ page }) => { - await page.setViewportSize(devices['Desktop Chrome'].viewport); - - await savePagePreviewImage(page, '/', 'home-desktop'); -}); - -// Content pages -const routes = ['about', 'sponsorship', 'venue', 'code-of-conduct', 'code-of-conduct/internal', 'new-speakers-workshop']; -for (const route of routes) { - test(`Captures ${route} preview - mobile`, async ({ page }) => { - await page.setViewportSize(devices['iPhone SE'].viewport); - - await savePagePreviewImage(page, route, `${route}-mobile`); - }); - - test(`Captures ${route} preview - tablet`, async ({ page }) => { - await page.setViewportSize(devices['iPad Mini'].viewport); - - await savePagePreviewImage(page, route, `${route}-tablet`); - }); - - test(`Captures ${route} preview - desktop`, async ({ page }) => { - await page.setViewportSize(devices['Desktop Chrome'].viewport); - - await savePagePreviewImage(page, route, `${route}-desktop`); - }); -} - -async function savePagePreviewImage(page: Page, route: string, imageName: string) { - // Go to page - await page.goto(route); - - // Wait for everything to have definitely finished loading (like maps) - await page.waitForLoadState('networkidle'); - - // Save screenshot - await page.screenshot({ path: `tests/page-previews/${imageName}.png`, fullPage: true }); -} diff --git a/tests/page-previews/about-desktop.png b/tests/page-previews/about-desktop.png deleted file mode 100644 index 09edaa4..0000000 Binary files a/tests/page-previews/about-desktop.png and /dev/null differ diff --git a/tests/page-previews/about-mobile.png b/tests/page-previews/about-mobile.png deleted file mode 100644 index bba2f54..0000000 Binary files a/tests/page-previews/about-mobile.png and /dev/null differ diff --git a/tests/page-previews/about-tablet.png b/tests/page-previews/about-tablet.png deleted file mode 100644 index 5bfc31e..0000000 Binary files a/tests/page-previews/about-tablet.png and /dev/null differ diff --git a/tests/page-previews/code-of-conduct-desktop.png b/tests/page-previews/code-of-conduct-desktop.png deleted file mode 100644 index f1fe934..0000000 Binary files a/tests/page-previews/code-of-conduct-desktop.png and /dev/null differ diff --git a/tests/page-previews/code-of-conduct-mobile.png b/tests/page-previews/code-of-conduct-mobile.png deleted file mode 100644 index b65c8b1..0000000 Binary files a/tests/page-previews/code-of-conduct-mobile.png and /dev/null differ diff --git a/tests/page-previews/code-of-conduct-tablet.png b/tests/page-previews/code-of-conduct-tablet.png deleted file mode 100644 index c5bdc10..0000000 Binary files a/tests/page-previews/code-of-conduct-tablet.png and /dev/null differ diff --git a/tests/page-previews/code-of-conduct/internal-desktop.png b/tests/page-previews/code-of-conduct/internal-desktop.png deleted file mode 100644 index 769ba5f..0000000 Binary files a/tests/page-previews/code-of-conduct/internal-desktop.png and /dev/null differ diff --git a/tests/page-previews/code-of-conduct/internal-mobile.png b/tests/page-previews/code-of-conduct/internal-mobile.png deleted file mode 100644 index 2507969..0000000 Binary files a/tests/page-previews/code-of-conduct/internal-mobile.png and /dev/null differ diff --git a/tests/page-previews/code-of-conduct/internal-tablet.png b/tests/page-previews/code-of-conduct/internal-tablet.png deleted file mode 100644 index 4bb148c..0000000 Binary files a/tests/page-previews/code-of-conduct/internal-tablet.png and /dev/null differ diff --git a/tests/page-previews/home-desktop.png b/tests/page-previews/home-desktop.png deleted file mode 100644 index 43b3098..0000000 Binary files a/tests/page-previews/home-desktop.png and /dev/null differ diff --git a/tests/page-previews/home-mobile.png b/tests/page-previews/home-mobile.png deleted file mode 100644 index d5cbc76..0000000 Binary files a/tests/page-previews/home-mobile.png and /dev/null differ diff --git a/tests/page-previews/home-tablet.png b/tests/page-previews/home-tablet.png deleted file mode 100644 index b10f067..0000000 Binary files a/tests/page-previews/home-tablet.png and /dev/null differ diff --git a/tests/page-previews/new-speakers-workshop-desktop.png b/tests/page-previews/new-speakers-workshop-desktop.png deleted file mode 100644 index ba084a8..0000000 Binary files a/tests/page-previews/new-speakers-workshop-desktop.png and /dev/null differ diff --git a/tests/page-previews/new-speakers-workshop-mobile.png b/tests/page-previews/new-speakers-workshop-mobile.png deleted file mode 100644 index ff46118..0000000 Binary files a/tests/page-previews/new-speakers-workshop-mobile.png and /dev/null differ diff --git a/tests/page-previews/new-speakers-workshop-tablet.png b/tests/page-previews/new-speakers-workshop-tablet.png deleted file mode 100644 index 2a8505e..0000000 Binary files a/tests/page-previews/new-speakers-workshop-tablet.png and /dev/null differ diff --git a/tests/page-previews/sponsorship-desktop.png b/tests/page-previews/sponsorship-desktop.png deleted file mode 100644 index 8a14e00..0000000 Binary files a/tests/page-previews/sponsorship-desktop.png and /dev/null differ diff --git a/tests/page-previews/sponsorship-mobile.png b/tests/page-previews/sponsorship-mobile.png deleted file mode 100644 index 09e0c59..0000000 Binary files a/tests/page-previews/sponsorship-mobile.png and /dev/null differ diff --git a/tests/page-previews/sponsorship-tablet.png b/tests/page-previews/sponsorship-tablet.png deleted file mode 100644 index d07290c..0000000 Binary files a/tests/page-previews/sponsorship-tablet.png and /dev/null differ diff --git a/tests/page-previews/venue-desktop.png b/tests/page-previews/venue-desktop.png deleted file mode 100644 index 37765ab..0000000 Binary files a/tests/page-previews/venue-desktop.png and /dev/null differ diff --git a/tests/page-previews/venue-mobile.png b/tests/page-previews/venue-mobile.png deleted file mode 100644 index 02bb2c7..0000000 Binary files a/tests/page-previews/venue-mobile.png and /dev/null differ diff --git a/tests/page-previews/venue-tablet.png b/tests/page-previews/venue-tablet.png deleted file mode 100644 index 0384efa..0000000 Binary files a/tests/page-previews/venue-tablet.png and /dev/null differ diff --git a/tests/visual-comparison.spec.ts b/tests/visual-comparison.spec.ts new file mode 100644 index 0000000..6ac4bc0 --- /dev/null +++ b/tests/visual-comparison.spec.ts @@ -0,0 +1,28 @@ +// Tests to ensure that pages haven't visually changed +// This is useful to ensure CSS changes haven't changed unexpected things +// If a visual change is intentional then run `npm run test:update-screenshots` +import { test, devices, expect } from '@playwright/test'; +import { pagesToTest } from './all-pages-to-test'; +import { devicesToTest } from './all-devices-to-test'; + +for (const [pageName, path] of pagesToTest) { + for (const [deviceName, deviceViewport] of devicesToTest) { + test(`${pageName} page has no visual changes on ${deviceName}}`, async ({ page }) => { + //Set viewport + page.setViewportSize(devices[deviceViewport].viewport); + + // Go to page + await page.goto(path); + + // Don't capture these elements because they are external to our site and we expect them to change + const locatorsToIgnore = [page.locator('iframe')]; + + // Compare screenshot to saved expectation (or save a new one if regenerating) + await expect(page).toHaveScreenshot(`${pageName}-${deviceName}.png`, { + fullPage: true, + mask: locatorsToIgnore, + maxDiffPixelRatio: 0.01 //experimenting to find right value, increase if tests fail on neglibible rendering change + }); + }); + } +}