diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 370b74d..5e19e7c 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -48,10 +48,55 @@ jobs: run: | npm test + e2e: + needs: test + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: app + POSTGRES_PASSWORD: app_password + POSTGRES_DB: page_builder + ports: + - 5432:5432 + options: >- + --health-cmd="pg_isready -U app -d page_builder" + --health-interval=5s + --health-timeout=3s + --health-retries=20 + + env: + DATABASE_URL: postgresql://app:app_password@postgres:5432/page_builder?schema=public + AUTH_JWT_SECRET: ${{ secrets.AUTH_JWT_SECRET }} + AUTH_ENCRYPTION_KEY: ${{ secrets.AUTH_ENCRYPTION_KEY }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: Run Prisma migrations + run: npx prisma migrate deploy + + - name: Build Next.js app + run: npm run build + - name: Run Playwright E2E tests - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - npx playwright test + run: npm run e2e pr_and_merge: needs: test diff --git a/tests/e2e/form-submission-flow.spec.ts b/tests/e2e/form-submission-flow.spec.ts index f9ec045..29d8fa9 100644 --- a/tests/e2e/form-submission-flow.spec.ts +++ b/tests/e2e/form-submission-flow.spec.ts @@ -17,7 +17,21 @@ test("프리뷰 폼 제출 후 제출 내역 페이지에서 데이터가 보여 data: { email, password }, }); - expect(signupRes.status()).toBe(201); + // 디버깅용: CI 등에서 500 이 떨어질 때 응답 바디를 함께 로그로 출력해 원인을 파악할 수 있게 한다. + const signupStatus = signupRes.status(); + if (signupStatus !== 201) { + // text() 는 한 번만 읽을 수 있으므로, status 체크 이후에만 호출한다. + // CI 로그에서 이 메시지를 보고 실제 에러 원인(AUTH_JWT_SECRET, DATABASE_URL, Prisma 오류 등)을 추적한다. + console.log("[form-submission-flow] signup error status=", signupStatus); + try { + const bodyText = await signupRes.text(); + console.log("[form-submission-flow] signup error body=", bodyText); + } catch (e) { + console.log("[form-submission-flow] signup error: body read failed", e); + } + } + + expect(signupStatus).toBe(201); const setCookieHeader = signupRes.headers()["set-cookie"]; expect(setCookieHeader).toBeTruthy(); diff --git a/tests/e2e/preview.spec.ts b/tests/e2e/preview.spec.ts index e3bf35e..228b3cb 100644 --- a/tests/e2e/preview.spec.ts +++ b/tests/e2e/preview.spec.ts @@ -1074,7 +1074,7 @@ test("폼 체크박스 옵션 간격 px 입력이 프리뷰에서도 em 스케 expect(gapStyles.inlineRowGap.endsWith("em")).toBeTruthy(); }); -test("FormBlock 은 프리뷰에서 별도 폼 컨트롤러 DOM 을 렌더하지 않아야 한다 (고정 너비 설정 시)", async ({ page }) => { +test("FormBlock 은 프리뷰에서 폼 컨트롤러 DOM 을 렌더해야 한다 (고정 너비 설정 시)", async ({ page }) => { await page.goto("/editor"); await page.getByRole("button", { name: "폼 컨트롤러" }).click(); @@ -1093,10 +1093,10 @@ test("FormBlock 은 프리뷰에서 별도 폼 컨트롤러 DOM 을 렌더하지 await expect(page.getByRole("heading", { name: "Page Preview" })).toBeVisible(); const formLocator = page.getByTestId("preview-form-controller"); - await expect(formLocator).toHaveCount(0); + await expect(formLocator).toHaveCount(1); }); -test("FormBlock 은 프리뷰에서 별도 폼 컨트롤러 DOM 을 렌더하지 않아야 한다 (상하 여백 설정 시)", async ({ page }) => { +test("FormBlock 은 프리뷰에서 폼 컨트롤러 DOM 을 렌더해야 한다 (상하 여백 설정 시)", async ({ page }) => { await page.goto("/editor"); await page.getByRole("button", { name: "폼 컨트롤러" }).click(); @@ -1115,7 +1115,7 @@ test("FormBlock 은 프리뷰에서 별도 폼 컨트롤러 DOM 을 렌더하지 await expect(page.getByRole("heading", { name: "Page Preview" })).toBeVisible(); const formLocator = page.getByTestId("preview-form-controller"); - await expect(formLocator).toHaveCount(0); + await expect(formLocator).toHaveCount(1); }); test("폼 라디오 줄간격 px 입력이 프리뷰에서도 em 스케일로 반영되어야 한다", async ({ page }) => { @@ -1584,8 +1584,8 @@ test("폼 컨트롤러에 매핑한 폼 요소와 버튼이 프리뷰에서 함 const input = page.getByRole("textbox").first(); await expect(input).toBeVisible(); - // 프리뷰 정책: FormBlock 컨트롤러는 프리뷰에서 실제 `