diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index ef823f9d..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Use Node.js - uses: actions/setup-node@v4 - with: - cache: 'npm' - - run: npm ci diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 00000000..7d2addd8 --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,26 @@ +name: End-to-end tests +on: + pull_request: + push: + branches: [ main ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 1c0876b2..2bca8c01 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ node_modules/ /cypress/temp tmp/ package-lock.json +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/e2e/app.spec.js b/e2e/app.spec.js new file mode 100644 index 00000000..4050d4f7 --- /dev/null +++ b/e2e/app.spec.js @@ -0,0 +1,10 @@ +// @ts-check +const { test, expect } = require('@playwright/test'); + +test('homepage loads', async ({ page }) => { + await page.goto('/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle("Home – dxw Prototype Library"); + await expect(page.getByRole('heading', { name: "dxw Prototype Gallery" })).toBeVisible(); +}); diff --git a/package-lock.json b/package-lock.json index d08adef5..769ac4aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,10 @@ "hmrc-frontend": "^6.0.0", "jquery": "3.7.1", "notifications-node-client": "5.2.3" + }, + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/node": "^22.9.0" } }, "node_modules/@govuk-prototype-kit/step-by-step": { @@ -343,6 +347,22 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@playwright/test": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz", + "integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.48.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", @@ -378,12 +398,12 @@ } }, "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.19.8" } }, "node_modules/@types/qs": { @@ -2876,6 +2896,38 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz", + "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.48.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz", + "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/portscanner": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", diff --git a/package.json b/package.json index e06fa7bd..5d6a206e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "scripts": { "dev": "govuk-prototype-kit dev", "serve": "govuk-prototype-kit serve", - "start": "govuk-prototype-kit start" + "start": "govuk-prototype-kit start", + "test": "npx playwright test" }, "name": "govuk-prototype-kit", "dependencies": { @@ -13,5 +14,9 @@ "hmrc-frontend": "^6.0.0", "jquery": "3.7.1", "notifications-node-client": "5.2.3" + }, + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/node": "^22.9.0" } } diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 00000000..e955ce44 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,48 @@ +// @ts-check +const { defineConfig, devices } = require('@playwright/test'); + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config({ path: path.resolve(__dirname, '.env') }); + +/** + * @see https://playwright.dev/docs/test-configuration + */ +module.exports = defineConfig({ + testDir: './e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run dev', + url: 'http://127.0.0.1:3000', + reuseExistingServer: !process.env.CI, + }, +});