diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index b7155f1..5634ea3 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -63,8 +63,23 @@ jobs: - uses: actions/upload-artifact@v3 if: ${{ failure() }} with: - name: playwright-test-results - path: test-results + name: playwright-e2e-test-results + path: tests/e2e/playwright-report + + - name: Run A11y tests + run: npm run test:a11y + env: + # Use a different port (from the one used with E2E tests) to workaround problem in CI/GitHub Actions, + # starting to occur with playwright/test 1.28.0: + # Error: http://localhost:4173 is already used ... + # See https://github.com/digitalservicebund/typescript-vite-application-template/actions/runs/3486985178/jobs/5834089375 + VITE_PORT: 4183 + + - uses: actions/upload-artifact@v3 + if: ${{ failure() }} + with: + name: playwright-a11y-test-results + path: tests/a11y/playwright-report - name: Build an image from Dockerfile run: | diff --git a/.gitignore b/.gitignore index 9d816dd..4b483a3 100644 --- a/.gitignore +++ b/.gitignore @@ -148,10 +148,11 @@ dist # Playwright /test-results/ /playwright-report/ +**/playwright-report/ /playwright/.cache/ # Lefthook lefthook-local.yml # Talisman -talisman_report \ No newline at end of file +talisman_report diff --git a/.talismanrc b/.talismanrc index 30c3411..cb23934 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,6 +1,6 @@ fileignoreconfig: - filename: .github/workflows/pipeline.yml - checksum: d08390039a10da00501e4278d261ee59fa09193a33893e01daf91d4c5015bf2d + checksum: dec3b1cb74779a0b9b6aecfc2d0a79200655838deb928593e3f9648f2fcabbfa - filename: .github/workflows/scan.yml checksum: b06430d20570ad4ce61e6078af8a2851ef1c1bf832f0a4f70c490bde1f533cdd - filename: README.md diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index fe2032b..3a4d1db 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -9,11 +9,11 @@ export const meta: MetaFunction = () => { export default function Index() { return ( -
+

Hello DigitalService!

-
+ ); } diff --git a/package-lock.json b/package-lock.json index c9f79aa..1e20800 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "tailwindcss": "^3.3.4" }, "devDependencies": { + "@axe-core/playwright": "^4.8.1", "@playwright/test": "^1.39.0", "@remix-run/dev": "^2.1.0", "@remix-run/eslint-config": "^2.1.0", @@ -78,6 +79,18 @@ "node": ">=6.0.0" } }, + "node_modules/@axe-core/playwright": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.8.1.tgz", + "integrity": "sha512-KC1X++UdRAwMLRvB+BIKFheyLHUnbJTL0t0Wbv6TJMozn2V2QyEtAcN6jyUiudtGiLUGhHCtj/eWorBnVZ4dAA==", + "dev": true, + "dependencies": { + "axe-core": "~4.8.2" + }, + "peerDependencies": { + "playwright-core": ">= 1.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", diff --git a/package.json b/package.json index 176dd54..8fe7ec1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "typecheck": "tsc", "test": "jest test", "test:generate-coverage": "jest --coverage", - "test:e2e": "playwright test", + "test:e2e": "playwright test --config=tests/e2e/playwright.config.ts", + "test:a11y": "playwright test --config=tests/a11y/playwright.config.ts", "lint:check": "eslint --ext .js,.ts --ignore-path .gitignore .", "lint:fix": "npm run lint:check -- --fix", "format:check": "prettier --check .", @@ -32,6 +33,7 @@ "tailwindcss": "^3.3.4" }, "devDependencies": { + "@axe-core/playwright": "^4.8.1", "@playwright/test": "^1.39.0", "@remix-run/dev": "^2.1.0", "@remix-run/eslint-config": "^2.1.0", diff --git a/tests/a11y/example.spec.ts b/tests/a11y/example.spec.ts new file mode 100644 index 0000000..6c7ea44 --- /dev/null +++ b/tests/a11y/example.spec.ts @@ -0,0 +1,14 @@ +import { test, expect } from "@playwright/test"; +import AxeBuilder from "@axe-core/playwright"; + +test.describe("index", () => { + test("should not have any automatically detectable accessibility issues", async ({ + page, + }) => { + await page.goto("/"); + + const accessibilityScanResults = await new AxeBuilder({ page }).analyze(); + + expect(accessibilityScanResults.violations).toEqual([]); + }); +}); diff --git a/playwright.config.ts b/tests/a11y/playwright.config.ts similarity index 93% rename from playwright.config.ts rename to tests/a11y/playwright.config.ts index db500df..60e8227 100644 --- a/playwright.config.ts +++ b/tests/a11y/playwright.config.ts @@ -8,7 +8,7 @@ import dotenv from "dotenv"; // Load both .env and test.env dotenv.config(); -dotenv.config({ path: "./tests/test.env" }); +dotenv.config({ path: "../test.env" }); const useDefaultBaseUrl = ["", undefined].includes(process.env.E2E_BASE_URL); const baseURL = useDefaultBaseUrl @@ -19,7 +19,7 @@ const baseURL = useDefaultBaseUrl * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: "./tests/e2e", + testDir: ".", /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ @@ -29,7 +29,14 @@ export default defineConfig({ /* 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", + reporter: [ + [ + "html", + { + outputFolder: "./playwright-report", + }, + ], + ], /* 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("/")`. */ diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts new file mode 100644 index 0000000..099922e --- /dev/null +++ b/tests/e2e/playwright.config.ts @@ -0,0 +1,91 @@ +import { defineConfig, devices } from "@playwright/test"; +import dotenv from "dotenv"; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ + +// Load both .env and test.env +dotenv.config(); +dotenv.config({ path: "../test.env" }); + +const useDefaultBaseUrl = ["", undefined].includes(process.env.E2E_BASE_URL); +const baseURL = useDefaultBaseUrl + ? "http://127.0.0.1:3000" + : process.env.E2E_BASE_URL; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: ".", + /* 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", + { + outputFolder: "./playwright-report", + }, + ], + ] /* 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, + /* 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"] }, + }, + + // { + // name: "firefox", + // use: { ...devices["Desktop Firefox"] }, + // }, + // + // { + // name: "webkit", + // use: { ...devices["Desktop Safari"] }, + // }, + + /* Test against mobile viewports. */ + // { + // name: "Mobile Chrome", + // use: { ...devices["Pixel 5"] }, + // }, + // { + // name: "Mobile Safari", + // use: { ...devices["iPhone 12"] }, + // }, + + /* Test against branded browsers. */ + // { + // name: "Microsoft Edge", + // use: { ...devices["Desktop Edge"], channel: "msedge" }, + // }, + // { + // name: "Google Chrome", + // use: { ...devices["Desktop Chrome"], channel: "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, + }, +});