diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 233927d..9d19528 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,4 +19,7 @@ jobs: osv-config: "osv-scanner.toml" enable-l2: "true" l2-command: "bun run test:e2e" + enable-l3: "true" + l3-command: "bun run test:e2e:bdd" + l3-browser: "chromium" secrets: inherit diff --git a/e2e/bdd/navigation.spec.ts b/e2e/bdd/navigation.spec.ts new file mode 100644 index 0000000..bf8ca9b --- /dev/null +++ b/e2e/bdd/navigation.spec.ts @@ -0,0 +1,10 @@ +import { test, expect } from "@playwright/test" + +test.describe("App — BDD Smoke", () => { + test("Given the app is running, When I visit the terms page, Then I see the terms content", async ({ + page, + }) => { + await page.goto("/terms") + await expect(page.getByText("服务条款")).toBeVisible({ timeout: 15_000 }) + }) +}) diff --git a/e2e/navigation.spec.ts b/e2e/navigation.spec.ts deleted file mode 100644 index 9bec50b..0000000 --- a/e2e/navigation.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { test, expect } from "@playwright/test" - -test.describe("Navigation", () => { - test("should load the login page when not authenticated", async ({ page }) => { - await page.goto("/") - // Should redirect to login or show the app - await expect(page).toHaveTitle(/noheir|登录|Login/) - }) - - test("should navigate to terms page", async ({ page }) => { - await page.goto("/terms") - await expect(page.getByText("服务条款")).toBeVisible() - }) - - test("should navigate to privacy page", async ({ page }) => { - await page.goto("/privacy") - await expect(page.getByText("隐私政策")).toBeVisible() - }) - - test("should have working command palette shortcut", async ({ page }) => { - await page.goto("/terms") - // Press Cmd+K to open command palette - await page.keyboard.press("Meta+k") - // Command dialog should appear - await expect(page.getByPlaceholder("搜索页面或功能...")).toBeVisible() - }) - - test("should navigate via command palette", async ({ page }) => { - await page.goto("/terms") - await page.keyboard.press("Meta+k") - const input = page.getByPlaceholder("搜索页面或功能...") - await expect(input).toBeVisible() - await input.fill("隐私") - // Should show privacy policy in results - await expect(page.getByText("隐私政策")).toBeVisible() - }) -}) - -test.describe("Static pages", () => { - test("terms page has all sections", async ({ page }) => { - await page.goto("/terms") - await expect(page.getByText("服务说明")).toBeVisible() - await expect(page.getByText("数据所有权")).toBeVisible() - await expect(page.getByText("免责声明")).toBeVisible() - }) - - test("privacy page has all sections", async ({ page }) => { - await page.goto("/privacy") - await expect(page.getByText("数据收集")).toBeVisible() - await expect(page.getByText("数据存储")).toBeVisible() - await expect(page.getByText("AI 分析")).toBeVisible() - await expect(page.getByText("数据删除")).toBeVisible() - }) -}) - -test.describe("App shell", () => { - test("authenticated pages show sidebar", async ({ page }) => { - // Even if not authenticated, the page should render the layout - await page.goto("/settings") - // The page should have a heading - await expect(page.getByText("系统设置")).toBeVisible() - }) -}) diff --git a/package.json b/package.json index fe0e90a..2ea3044 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "test:worker": "cd worker && vitest run", "test:coverage": "vitest run --coverage", "test:e2e": "bun run scripts/run-e2e.ts", + "test:e2e:bdd": "bunx playwright test", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", "db:push": "drizzle-kit push", diff --git a/playwright.config.ts b/playwright.config.ts index 17b9870..f33d559 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,15 +1,16 @@ import { defineConfig, devices } from "@playwright/test" export default defineConfig({ - testDir: "./e2e", + testDir: "./e2e/bdd", fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : 2, reporter: "html", use: { - baseURL: process.env.PLAYWRIGHT_BASE_URL ?? "http://localhost:7004", + baseURL: process.env.PLAYWRIGHT_BASE_URL ?? "http://localhost:27004", trace: "on-first-retry", + headless: true, }, projects: [ { @@ -18,9 +19,9 @@ export default defineConfig({ }, ], webServer: { - command: "bun run dev", - url: "http://localhost:7004", + command: "bun run dev -- --port 27004", + url: "http://localhost:27004", reuseExistingServer: !process.env.CI, - timeout: 30000, + timeout: 60_000, }, })