diff --git a/.gitignore b/.gitignore index d2fcaf2..2046892 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ yarn-error.log* dist/ .direnv/ .devenv/ +packages/web/playwright-report +packages/web/test-results diff --git a/bun.lockb b/bun.lockb index f24e64a..d75fa9e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/flake.nix b/flake.nix index 8d7fa81..8c6f71e 100644 --- a/flake.nix +++ b/flake.nix @@ -47,8 +47,14 @@ name = "TODO-template-name"; + env = { + PLAYWRIGHT_BROWSERS_PATH = pkgs.playwright-driver.browsers; + PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = true; + }; + packages = [ pkgs.biome + pkgs.playwright-driver.browsers ]; processes = { diff --git a/packages/web/package.json b/packages/web/package.json index ffeb837..031740c 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -10,7 +10,8 @@ "typecheck": "react-router typegen && tsc", "lint": "biome lint . && stylelint **/*.css", "preview": "vite preview", - "test": "vitest" + "test": "vitest", + "playwright": "playwright test" }, "dependencies": { "@pigment-css/react": "0.0.30", @@ -27,6 +28,7 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@pigment-css/vite-plugin": "0.0.30", + "@playwright/test": "1.50.1", "@react-router/dev": "7.4.1", "@types/lodash": "4.17.16", "@types/node": "22.13.17", diff --git a/packages/web/playwright.config.ts b/packages/web/playwright.config.ts new file mode 100644 index 0000000..0d87814 --- /dev/null +++ b/packages/web/playwright.config.ts @@ -0,0 +1,44 @@ +import { defineConfig, devices } from "@playwright/test"; + +export default defineConfig({ + // Look for test files in the "tests" directory, relative to this configuration file. + testDir: "tests", + + // Run all tests in parallel. + fullyParallel: true, + + ...(process.env["CI"] + ? { + // Fail the build on CI if you accidentally left test.only in the source code. + forbidOnly: true, + // Retry on CI only. + retries: 2, + // Opt out of parallel tests on CI. + workers: 1, + } + : {}), + + // Reporter to use + reporter: "html", + + use: { + // Base URL to use in actions like `await page.goto('/')`. + baseURL: "http://localhost:5173", + + // Collect trace when retrying the failed test. + 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 start", + // url: "http://localhost:3000", + // reuseExistingServer: !process.env["CI"], + // }, +}); diff --git a/packages/web/tests/example.spec.ts b/packages/web/tests/example.spec.ts new file mode 100644 index 0000000..529e40e --- /dev/null +++ b/packages/web/tests/example.spec.ts @@ -0,0 +1,18 @@ +import { expect, test } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +}); diff --git a/packages/web/tsconfig.json b/packages/web/tsconfig.json index 0769318..ebb61cd 100644 --- a/packages/web/tsconfig.json +++ b/packages/web/tsconfig.json @@ -1,7 +1,7 @@ { "files": [], "extends": "../../tsconfig.base.json", - "include": ["app", "*.ts"], + "include": ["app", "*.ts", "tests"], "compilerOptions": { "types": ["vitest/importMeta", "vite/client", "node"], "rootDirs": [".", "./.react-router/types"],