From b0b497f95b14e0e9995a4dc7f7745e41995bbb7b Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 29 Mar 2024 17:52:04 +0900 Subject: [PATCH] test: setup e2e --- .github/workflows/ci.yml | 23 ++++++++++++++ examples/react-server/e2e/basic.test.ts | 9 ++++++ examples/react-server/package.json | 2 ++ examples/react-server/playwright.config.ts | 28 +++++++++++++++++ examples/react-server/tsconfig.json | 4 ++- examples/react-ssr/e2e/basic.test.ts | 9 ++++++ examples/react-ssr/package.json | 2 ++ examples/react-ssr/playwright.config.ts | 28 +++++++++++++++++ examples/react-ssr/tsconfig.json | 2 +- package.json | 1 + pnpm-lock.yaml | 35 ++++++++++++++++++++++ 11 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 examples/react-server/e2e/basic.test.ts create mode 100644 examples/react-server/playwright.config.ts create mode 100644 examples/react-ssr/e2e/basic.test.ts create mode 100644 examples/react-ssr/playwright.config.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..b2310c3c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: ci +"on": + - push +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + - run: corepack enable + - run: pnpm i + - run: pnpm lint-check + - run: pnpm tsc + - run: pnpm build + - run: npx playwright install chromium + - run: pnpm -C examples/react-ssr test-e2e + - run: pnpm -C examples/react-ssr build + - run: pnpm -C examples/react-ssr test-e2e-preview + - run: pnpm -C examples/react-server test-e2e + - run: pnpm -C examples/react-server build + - run: pnpm -C examples/react-server test-e2e-preview diff --git a/examples/react-server/e2e/basic.test.ts b/examples/react-server/e2e/basic.test.ts new file mode 100644 index 00000000..18ee5084 --- /dev/null +++ b/examples/react-server/e2e/basic.test.ts @@ -0,0 +1,9 @@ +import { test, expect } from "@playwright/test"; + +test("basic", async ({ page }) => { + await page.goto("/"); + await expect(page.locator("#root")).toContainText("hydrated: true"); + await expect(page.locator("#root")).toContainText("Count: 0"); + await page.getByRole("button", { name: "+" }).click(); + await expect(page.locator("#root")).toContainText("Count: 1"); +}); diff --git a/examples/react-server/package.json b/examples/react-server/package.json index 1639e489..ca80b0f2 100644 --- a/examples/react-server/package.json +++ b/examples/react-server/package.json @@ -6,6 +6,8 @@ "dev": "vite", "build": "vite build --all", "preview": "vite preview", + "test-e2e": "playwright test", + "test-e2e-preview": "E2E_PREVIEW=1 playwright test", "cf-build": "SERVER_ENTRY=/src/adapters/cloudflare-workers.ts pnpm build && bash misc/cloudflare-workers/build.sh", "cf-preview": "cd misc/cloudflare-workers && wrangler dev", "cf-release": "cd misc/cloudflare-workers && wrangler deploy" diff --git a/examples/react-server/playwright.config.ts b/examples/react-server/playwright.config.ts new file mode 100644 index 00000000..056e6d4d --- /dev/null +++ b/examples/react-server/playwright.config.ts @@ -0,0 +1,28 @@ +import { defineConfig, devices } from "@playwright/test"; + +const port = Number(process.env["E2E_PORT"] || 6174); +const isPreview = Boolean(process.env["E2E_PREVIEW"]); +const command = isPreview + ? `pnpm preview --port ${port} --strict-port` + : `pnpm dev --port ${port} --strict-port`; + +export default defineConfig({ + testDir: "e2e", + use: { + trace: "on-first-retry", + }, + projects: [ + { + name: "chromium", + use: devices["Desktop Chrome"], + }, + ], + webServer: { + command, + port, + }, + grepInvert: isPreview ? /@dev/ : /@build/, + forbidOnly: !!process.env["CI"], + retries: process.env["CI"] ? 2 : 0, + reporter: "list", +}); diff --git a/examples/react-server/tsconfig.json b/examples/react-server/tsconfig.json index f8e3beb0..53e8f553 100644 --- a/examples/react-server/tsconfig.json +++ b/examples/react-server/tsconfig.json @@ -3,7 +3,9 @@ "include": [ "src", "vite.config.ts", - "vite-plugin-environment-optimize-deps.ts" + "vite-plugin-environment-optimize-deps.ts", + "e2e", + "playwright.config.ts" ], "compilerOptions": { "noUncheckedIndexedAccess": false, diff --git a/examples/react-ssr/e2e/basic.test.ts b/examples/react-ssr/e2e/basic.test.ts new file mode 100644 index 00000000..18ee5084 --- /dev/null +++ b/examples/react-ssr/e2e/basic.test.ts @@ -0,0 +1,9 @@ +import { test, expect } from "@playwright/test"; + +test("basic", async ({ page }) => { + await page.goto("/"); + await expect(page.locator("#root")).toContainText("hydrated: true"); + await expect(page.locator("#root")).toContainText("Count: 0"); + await page.getByRole("button", { name: "+" }).click(); + await expect(page.locator("#root")).toContainText("Count: 1"); +}); diff --git a/examples/react-ssr/package.json b/examples/react-ssr/package.json index 9253386f..a536d7ca 100644 --- a/examples/react-ssr/package.json +++ b/examples/react-ssr/package.json @@ -6,6 +6,8 @@ "dev": "vite", "build": "vite build --all", "preview": "vite preview", + "test-e2e": "playwright test", + "test-e2e-preview": "E2E_PREVIEW=1 playwright test", "vc-build": "SERVER_ENTRY=/src/adapters/vercel-edge.ts pnpm build && bash misc/vercel-edge/build.sh", "vc-release": "vercel deploy --prebuilt misc/vercel-edge --prod" }, diff --git a/examples/react-ssr/playwright.config.ts b/examples/react-ssr/playwright.config.ts new file mode 100644 index 00000000..056e6d4d --- /dev/null +++ b/examples/react-ssr/playwright.config.ts @@ -0,0 +1,28 @@ +import { defineConfig, devices } from "@playwright/test"; + +const port = Number(process.env["E2E_PORT"] || 6174); +const isPreview = Boolean(process.env["E2E_PREVIEW"]); +const command = isPreview + ? `pnpm preview --port ${port} --strict-port` + : `pnpm dev --port ${port} --strict-port`; + +export default defineConfig({ + testDir: "e2e", + use: { + trace: "on-first-retry", + }, + projects: [ + { + name: "chromium", + use: devices["Desktop Chrome"], + }, + ], + webServer: { + command, + port, + }, + grepInvert: isPreview ? /@dev/ : /@build/, + forbidOnly: !!process.env["CI"], + retries: process.env["CI"] ? 2 : 0, + reporter: "list", +}); diff --git a/examples/react-ssr/tsconfig.json b/examples/react-ssr/tsconfig.json index 015a49df..aa702900 100644 --- a/examples/react-ssr/tsconfig.json +++ b/examples/react-ssr/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "@tsconfig/strictest/tsconfig.json", - "include": ["src", "vite.config.ts"], + "include": ["src", "vite.config.ts", "e2e", "playwright.config.ts"], "compilerOptions": { "exactOptionalPropertyTypes": false, "verbatimModuleSyntax": true, diff --git a/package.json b/package.json index bb342a59..09e8711a 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "devDependencies": { "@hattip/adapter-node": "^0.0.44", "@hiogawa/utils": "1.6.4-pre.1", + "@playwright/test": "^1.42.1", "@tsconfig/strictest": "^2.0.4", "@types/node": "^20.11.30", "@vitejs/plugin-react": "^4.2.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2cc7551d..f5bb67d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@hiogawa/utils': specifier: 1.6.4-pre.1 version: 1.6.4-pre.1 + '@playwright/test': + specifier: ^1.42.1 + version: 1.42.1 '@tsconfig/strictest': specifier: ^2.0.4 version: 2.0.4 @@ -786,6 +789,14 @@ packages: resolution: {integrity: sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==} dev: true + /@playwright/test@1.42.1: + resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright: 1.42.1 + dev: true + /@rollup/rollup-android-arm-eabi@4.13.0: resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} cpu: [arm] @@ -1375,6 +1386,14 @@ packages: fast-decode-uri-component: 1.0.1 dev: true + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1505,6 +1524,22 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + /playwright-core@1.42.1: + resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==} + engines: {node: '>=16'} + hasBin: true + dev: true + + /playwright@1.42.1: + resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright-core: 1.42.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14}