diff --git a/Jenkinsfile b/Jenkinsfile index 8776310..d9bf2b9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,8 +1,18 @@ pipeline { agent any + options { + skipDefaultCheckout(true) + } + + parameters { + booleanParam(name: 'RUN_FULL_E2E', defaultValue: false, description: '是否在部署后额外执行全量 E2E(失败仅标记 UNSTABLE)') + } + environment { APP_NAME = 'no-whatever' + CI_IMAGE = 'mcr.microsoft.com/playwright:v1.51.1-jammy' + NPM_CACHE_VOLUME = 'no-whatever-npm-cache' } triggers { @@ -31,42 +41,30 @@ pipeline { sh ''' set -e - if docker image inspect node:20-bookworm >/dev/null 2>&1; then - echo "node:20-bookworm already exists, skip pull" + if docker image inspect ${CI_IMAGE} >/dev/null 2>&1; then + echo "${CI_IMAGE} already exists, skip pull" else - docker pull node:20-bookworm - fi - - if docker image inspect mcr.microsoft.com/playwright:v1.51.1-jammy >/dev/null 2>&1; then - echo "mcr.microsoft.com/playwright:v1.51.1-jammy already exists, skip pull" - else - docker pull mcr.microsoft.com/playwright:v1.51.1-jammy + docker pull ${CI_IMAGE} fi ''' } } } - stage('Quality Gate') { - steps { - sh ''' - set -e - cid=$(docker create node:20-bookworm sh -lc "cd /workspace && npm ci && npm run lint && npx tsc --noEmit && npm run test:coverage") - trap 'docker rm -f "$cid" >/dev/null 2>&1 || true' EXIT - docker cp . "$cid":/workspace - docker start -a "$cid" - ''' - } - } - - stage('E2E Gate') { + stage('CI Gate (Lint + TypeCheck + Unit + Smoke E2E)') { options { - timeout(time: 20, unit: 'MINUTES') + timeout(time: 30, unit: 'MINUTES') } steps { sh ''' set -e - cid=$(docker create --ipc=host mcr.microsoft.com/playwright:v1.51.1-jammy sh -lc "cd /workspace && npm ci && npm run test:e2e") + rm -rf playwright-report test-results + cid=$(docker create --ipc=host \ + -e HOME=/tmp \ + -e NPM_CONFIG_CACHE=/npm-cache \ + -v ${NPM_CACHE_VOLUME}:/npm-cache \ + ${CI_IMAGE} \ + sh -lc "cd /workspace && npm ci --prefer-offline --no-audit --progress=false && npm run lint && npx tsc --noEmit && npm run test:coverage && npm run test:e2e:smoke") cleanup() { docker rm -f "$cid" >/dev/null 2>&1 || true } @@ -123,6 +121,46 @@ pipeline { } } } + + stage('Full E2E (Optional, Non-Blocking)') { + when { + expression { return params.RUN_FULL_E2E } + } + options { + timeout(time: 30, unit: 'MINUTES') + } + steps { + catchError(buildResult: 'UNSTABLE', stageResult: 'UNSTABLE') { + sh ''' + set -e + rm -rf playwright-report-full test-results-full + cid=$(docker create --ipc=host \ + -e HOME=/tmp \ + -e NPM_CONFIG_CACHE=/npm-cache \ + -v ${NPM_CACHE_VOLUME}:/npm-cache \ + ${CI_IMAGE} \ + sh -lc "cd /workspace && npm ci --prefer-offline --no-audit --progress=false && npm run test:e2e") + cleanup() { + docker rm -f "$cid" >/dev/null 2>&1 || true + } + trap cleanup EXIT + docker cp . "$cid":/workspace + set +e + docker start -a "$cid" + status=$? + set -e + docker cp "$cid":/workspace/playwright-report ./playwright-report-full 2>/dev/null || true + docker cp "$cid":/workspace/test-results ./test-results-full 2>/dev/null || true + exit $status + ''' + } + } + post { + always { + archiveArtifacts artifacts: 'playwright-report-full/**,test-results-full/**', allowEmptyArchive: true + } + } + } } post { diff --git a/e2e/home-navigation.spec.ts b/e2e/home-navigation.spec.ts index dcc32b8..a892afd 100644 --- a/e2e/home-navigation.spec.ts +++ b/e2e/home-navigation.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; -test("首页模式卡片可正确导航", async ({ page }) => { +test("@smoke 首页模式卡片可正确导航", async ({ page }) => { await page.goto("/"); await expect(page.getByRole("heading", { name: "NoWhatever" })).toBeVisible(); diff --git a/e2e/panic-join.spec.ts b/e2e/panic-join.spec.ts index 7c419cb..44c6620 100644 --- a/e2e/panic-join.spec.ts +++ b/e2e/panic-join.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; -test("Panic 手动加入房间会规范化房间号并发起 join 请求", async ({ page }) => { +test("@smoke Panic 手动加入房间会规范化房间号并发起 join 请求", async ({ page }) => { const joinBodies: Array<{ userId?: string }> = []; await page.route("**/api/room/*/join", async (route) => { diff --git a/package.json b/package.json index 08055f1..62ccc9f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "test:watch": "vitest", "test:coverage": "vitest run --coverage", "test:e2e:install": "playwright install chromium", + "test:e2e:smoke": "playwright test --grep @smoke", "test:e2e": "playwright test", "test:e2e:headed": "playwright test --headed" },