Playwright E2E 测试在本地通过,但在使用 Next.js 14 App Router、TypeScript 的 GitHub Actions 中失败

问题描述 投票:0回答:1

我遇到了一个问题,我的 Playwright 端到端测试在本地计算机上运行得很好,但在 GitHub Actions 中执行时始终失败。我的设置涉及使用 App Router、TypeScript、Playwright 进行测试和 GitHub Actions for CI 的 Next.js 14 应用程序。

当地环境:

  • Node.js:v20.x
  • Next.js:14.x
  • 剧作家:1.x
  • 操作系统:macOS/Linux

GitHub Actions 环境:

  • ubuntu-latest
  • Node.js:20.x

代码概述:

  • setup.ts(设置测试的身份验证状态):
import { test, expect } from "@playwright/test";
import { mkdirSync } from "fs";
import { dirname } from "path";

const authFile = "playwright/.auth/user.json";

test("test", async ({ page }) => {
  mkdirSync(dirname(authFile), { recursive: true });

  await page.goto("http://localhost:3000/api/auth/signin?csrf=true");
  await page.getByRole("button", { name: "Sign in with Azure Active" }).click();
  await page.getByPlaceholder("Email, phone, or Skype").click();
  await page
    .getByPlaceholder("Email, phone, or Skype")
    .fill(process.env.PLAYWRIGHT_EMAIL ?? "");
  await page.getByRole("button", { name: "Next" }).click();
  await page.getByPlaceholder("Password").click();
  await page
    .getByPlaceholder("Password")
    .fill(process.env.PLAYWRIGHT_PASSWORD ?? "");
  await page.getByRole("button", { name: "Sign in" }).click();
  try {
    const yesButton = page.getByRole("button", { name: "Yes" });
    await yesButton.waitFor({ state: "visible", timeout: 10000 });
    await yesButton.click();
  } catch (error) {
    console.log(
      "The 'Yes' button was not found or not clickable within the time limit."
    );
  }
  await page.goto("http://localhost:3000/home");

  await page.context().storageState({ path: authFile });
});
  • redirect.spec.ts(测试路由逻辑):
import { test, expect } from "@playwright/test";

test("Authenticated root route redirects to home page", async ({ page }) => {
  await page.goto("http://localhost:3000/home");
  await expect(page).toHaveURL("http://localhost:3000/home");
  await page.goto("http://localhost:3000/");
  await expect(page).toHaveURL("http://localhost:3000/home");
});

test("Unauthenticated access redirects to login page for root and home routes", async ({ page }) => {
  await page.context().clearCookies();
  await page.goto("http://localhost:3000/");
  await expect(page).toHaveURL("http://localhost:3000/login");
  await page.goto("http://localhost:3000/home");
  await expect(page).toHaveURL("http://localhost:3000/login");
});
  • playwright.config.ts(Playwright 配置):
import { defineConfig, devices } from "@playwright/test";
import dotenv from "dotenv";
import path from "path";

dotenv.config({ path: path.resolve(__dirname, ".env.local") });

export default defineConfig({
  testDir: "./e2e-tests",
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: "html",
  use: {
    trace: "on-first-retry",
  },
  projects: [
    { name: "setup", testMatch: "setup.ts" },
    {
      name: "chromium",
      use: {
        ...devices["Desktop Chrome"],
        storageState: "playwright/.auth/user.json",
      },
      dependencies: ["setup"],
    },
    {
      name: "firefox",
      use: {
        ...devices["Desktop Firefox"],
        storageState: "playwright/.auth/user.json",
      },
      dependencies: ["setup"],
    },
    {
      name: "webkit",
      use: {
        ...devices["Desktop Safari"],
        storageState: "playwright/.auth/user.json",
      },
      dependencies: ["setup"],
    },
  ],
  webServer: {
    command: "npm run dev",
    url: "http://127.0.0.1:3000",
    reuseExistingServer: !process.env.CI,
  },
});
  • GitHub Actions 工作流程 (
    playwright.yml
    )
    :
name: Playwright Tests

on:
  pull_request:

jobs:
  end-to-end-test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20.x]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies
        run: npm install

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run Playwright tests
        env:
          PLAYWRIGHT_EMAIL: ${{ secrets.PLAYWRIGHT_EMAIL }}
          PLAYWRIGHT_PASSWORD: ${{ secrets.PLAYWRIGHT_PASSWORD }}
          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID}}
          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET}}
          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID}}
          NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET}}
          NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL}}
        run: npm run test:e2e
      - uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

问题:

测试在 GitHub Actions 上失败,并出现以下错误:

Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected)
Expected string: "***/home"
Received string: "***/login"

这表明身份验证步骤在 CI 环境中可能无法正常工作。然而,相同的设置在本地运行得非常好。

采取的故障排除步骤:

  • 已验证环境变量在 GitHub Actions 中设置正确。
  • 确保所有依赖项和浏览器版本都是最新的。
  • 尝试增加超时但仍然遇到同样的问题。

问题:

为什么我的 Playwright 测试在本地通过但在 GitHub Actions 中失败?我在配置或环境设置方面是否缺少某些内容可能会导致这种差异?任何帮助或指示将不胜感激。


typescript next.js github-actions playwright end-to-end
1个回答
0
投票

您已设置

trace: "on-first-retry",
retries: process.env.CI ? 2 : 0,
。调试问题的最简单方法是下载 CI 中最后一步中保存的 HTML 报告。

如果您不知道如何下载 GitHub 工件,请阅读本文 https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/downloading-workflow -文物

然后打开 HTML 报告,找到失败的测试,并将选项卡切换到“重试 #1”。在跟踪查看器中,您将看到到底发生了什么。以下是有关跟踪查看器的文章https://playwright.dev/docs/trace-viewer

您的存储状态文件可能是在没有会话 cookie 的情况下创建的。登录后您可能需要等待一段时间,例如。等到您看到个人资料图片。 在本地,您可以拥有更快的机器,它会创建。

© www.soinside.com 2019 - 2024. All rights reserved.