首页 >web前端 >js教程 >Heroku 中的 Playwright 和 Chrome 浏览器测试

Heroku 中的 Playwright 和 Chrome 浏览器测试

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-12-06 10:35:12224浏览

我一直喜欢观看我的单元测试运行(并通过)。它们速度很快,并且通过测试让我确信我的个人作品表现得像他们应该的那样。相反,我经常很难确定浏览器端到端测试的优先级,因为编写和运行它们的速度非常慢。

幸运的是,多年来,用于端到端浏览器内测试的工具已经变得更好更快。通过无头浏览器设置,我可以运行浏览器测试作为 CI 的一部分。

最近,我看到这篇 Heroku 博客文章,讨论在 Heroku CI 中使用无头 Chrome 进行自动化浏览器内测试。 Heroku 有一个安装 headless Chrome 的构建包,您可以在 CI 管道中调用它来进行测试。

博客文章中的示例设置是使用 Puppeteer 和 Jest 测试的 React 应用程序。这是一个很好的开始……但是如果我使用 Playwright 而不是 Puppeteer 呢?可以吗?

我决定调查一下。事实证明 — 是的,您也可以使用 Playwright 来做到这一点!因此,我捕获了在 Heroku CI 中使用的无头 Chrome 浏览器上运行 Playwright 测试所需的步骤。在这篇文章中,我将引导您完成设置步骤。

关于端到端测试的浏览器自动化的简短介绍

端到端测试捕获用户如何在浏览器中实际与您的应用交互,从而验证完整的工作流程。 Playwright 通过在 Chrome、Firefox 和 Safari 中进行测试,使这一过程变得非常无缝。当然,在 CI 中运行完整的浏览器测试非常繁重,这就是无头模式有帮助的原因。

Heroku 的用于测试的 Chrome 构建包将 Chrome 安装在 Heroku 应用程序上,因此您可以通过非常轻量级的设置在 Heroku CI 中运行 Playwright 测试。

测试申请简介

因为我只是尝试这个,所以我分叉了最初在 Heroku 博客文章中引用的 GitHub 存储库。该应用程序是一个简单的 React 应用程序,带有链接、文本输入和提交按钮。共有三个测试:

  1. 验证链接是否有效并重定向到正确的位置。

  2. 验证文本输入是否正确显示用户输入。

  3. 验证提交表单是否会更新页面上显示的文本。

非常简单。现在,我只需更改代码以使用 Playwright 而不是 Puppeteer 和 Jest。哦,我还想使用 pnpm 而不是 npm。这是我分叉的 GitHub 存储库的链接。

修改代码以使用 Playwright

让我们看看我修改代码的步骤。我从我的分叉存储库开始,与 heroku-examples 存储库相同。

使用pnpm

我想使用 pnpm 而不是 npm。 (个人喜好。)所以,这就是我首先做的:

~/project$ corepack enable pnpm


~/project$ corepack use pnpm@latest

Installing pnpm@9.12.3 in the project…
…
Progress: resolved 1444, reused 1441, downloaded 2, added 1444, done
…
Done in 14.4s

~/project$ rm package-lock.json


~/project$ pnpm install # just to show everything's good


Lockfile is up to date, resolution step is skipped
Already up to date
Done in 1.3s

将剧作家添加到项目中

接下来,我删除了 Puppeteer 和 Jest,并添加了 Playwright。

~/project$ pnpm remove \
           babel-jest jest jest-puppeteer @testing-library/jest-dom

~/project$ $ pnpm create playwright
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
✔ Do you want to use TypeScript or JavaScript? · JavaScript
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · false
✔ Install Playwright browsers (can be done manually via 'pnpm exec playwright install')? (Y/n) · false
✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo pnpm exec playwright install-deps')? (y/N) · false

Installing Playwright Test (pnpm add --save-dev @playwright/test)…
…
Installing Types (pnpm add --save-dev @types/node)…
…
Done in 2.7s
Writing playwright.config.js.
Writing tests/example.spec.js.
Writing tests-examples/demo-todo-app.spec.js.
Writing package.json.

我还从 package.json 中删除了 Jest 配置部分。

将 Playwright 配置为仅使用 Chromium

您可以在 Chrome、Firefox 和 Safari 中运行 Playwright 测试。由于我专注于 Chrome,因此我从生成的 playwright.config.js 文件的项目部分中删除了其他浏览器:

  /* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },

//    {
//      name: 'firefox',
//      use: { ...devices['Desktop Firefox'] },
//    },
//
//    {
//      name: 'webkit',
//      use: { ...devices['Desktop Safari'] },
//    },


  ],
…

将 Puppeteer 测试代码交换为 Playwright 测试代码

原始代码有一个 Puppeteer 测试文件,位于 src/tests/puppeteer.test.js。我将该文件移至tests/playwright.spec.js。然后,我更新了测试以使用剧作家的约定,它映射得相当干净。新的测试文件如下所示:

const ROOT_URL = 'http://localhost:8080';
const { test, expect } = require('@playwright/test');

const inputSelector = 'input[name="name"]';
const submitButtonSelector = 'button[type="submit"]';
const greetingSelector = 'h5#greeting';
const name = 'John Doe';

test.beforeEach(async ({ page }) => {
  await page.goto(ROOT_URL);
});

test.describe('Playwright link', () => {
  test('should navigate to Playwright documentation page', async ({ page }) => {
    await page.click('a[href="https://playwright.dev/"]');
    await expect(page.title()).resolves.toMatch('| Playwright');
  });
});

test.describe('Text input', () => {
  test('should display the entered text in the text input', async ({ page }) => {
    await page.fill(inputSelector, name);

    // Verify the input value
    const inputValue = await page.inputValue(inputSelector);
    expect(inputValue).toBe(name);
  });
});

test.describe('Form submission', () => {
  test('should display the "Hello, X" message after form submission', async ({ page }) => {
    const expectedGreeting = `Hello, ${name}.`;
    await page.fill(inputSelector, name);
    await page.click(submitButtonSelector);

    await page.waitForSelector(greetingSelector);
    const greetingText = await page.textContent(greetingSelector);
    expect(greetingText).toBe(expectedGreeting);
  });
});

删除 start-server-and-test,改用 Playwright 的 webServer

为了测试我的 React 应用程序,我需要首先在一个单独的进程中启动它(在 http://localhost:8080),然后我可以运行我的测试。无论我使用 Puppeteer 还是 Playwright,都会出现这种情况。对于 Puppeteer,Heroku 示例使用了 start-server-and-test 包。但是,您可以配置 Playwright 在运行测试之前启动应用程序。这真是太方便了!

我从我的项目中删除了 start-server-and-test。

~/project$ pnpm remove start-server-and-test

在 playwright.config.js 中,我取消了底部 webServer 部分的注释,将其修改为如下所示:

  /* Run your local dev server before starting the tests */
  webServer: {
     command: 'pnpm start',
     url: 'http://127.0.0.1:8080',
     reuseExistingServer: !process.env.CI,
  },

然后,我从原始 package.json 文件中删除了 test:ci 脚本。相反,我的测试脚本如下所示:

  "scripts": {
    …
    "test": "playwright test --project=chromium --reporter list"
  },

在我的本地计算机上安装 Playwright 浏览器

Playwright 安装最新的浏览器二进制文件以用于其测试。因此,在我的本地计算机上,我需要 Playwright 安装其版本的 Chromium。

~/project$ pnpm playwright install chromium


Downloading Chromium 130.0.6723.31 (playwright build v1140)
from https://playwright.azureedge.net/builds/chromium/1140/chromium-linux.zip
164.5 MiB [====================] 100%

注意: Heroku 上的用于测试的 Chrome 构建包安装了我们将用于测试的浏览器。我们将设置 CI,以便 Playwright 使用该浏览器,而不是花费时间和资源安装自己的浏览器。

在本地运行测试

这样,我就一切准备就绪了。是时候在本地尝试我的测试了。

~/project$ pnpm test

> playwright test --project=chromium --reporter list

Running 3 tests using 3 workers

  ✓  1 [chromium] > playwright.spec.js:21:3 > Text input > should display the entered text in the text input (911ms)
  ✘  2 [chromium] > playwright.spec.js:14:3 > Playwright link > should navigate to Playwright documentation page (5.2s)
  ✓  3 [chromium] > playwright.spec.js:31:3 > Form submission > should display the "Hello, X" message after form submission (959ms)

...
      - waiting for locator('a[href="https://playwright.dev/"]')


      13 | test.describe('Playwright link', () => {
      14 |   test('should navigate to Playwright documentation page', async ({ page }) => {
    > 15 |     await page.click('a[href="https://playwright.dev/"]');
         |                ^
      16 |     await expect(page.title()).resolves.toMatch('| Playwright');
      17 |   });
      18 | });

哦!这是正确的。我修改了测试,期望应用程序中的链接将我带到 Playwright 的文档而不是 Puppeteer 的文档。我需要在第 19 行更新 src/App.js:

<Link href="https://playwright.dev/" rel="noopener">
  Playwright Documentation
</Link>

现在,是时候再次运行测试了......

~/project$ pnpm test

> playwright test --project=chromium --reporter list

Running 3 tests using 3 workers

  ✓  1 [chromium] > playwright.spec.js:21:3 > Text input > should display the entered text in the text input (1.1s)
  ✓  2 [chromium] > playwright.spec.js:14:3 > Playwright link > should navigate to Playwright documentation page (1.1s)
  ✓  3 [chromium] > playwright.spec.js:31:3 > Form submission > should display the "Hello, X" message after form submission (1.1s)

  3 passed (5.7s)

测试通过了!接下来,是时候让我们进入 Heroku CI 了。

部署到 Heroku 以使用 CI 管道

我按照 Heroku 博客文章中的说明在 Heroku CI 管道中设置了我的应用程序。

创建 Heroku 管道

在 Heroku 中,我创建了一个新管道并将其连接到我分叉的 GitHub 存储库。

Playwright and Chrome Browser Testing in Heroku

接下来,我将我的应用程序添加到了 staging。

Playwright and Chrome Browser Testing in Heroku

然后,我转到 测试 选项卡并单击 启用 Heroku CI

Playwright and Chrome Browser Testing in Heroku

最后,我修改了 app.json 文件以删除设置为调用 npm test:ci 的测试脚本。我已经从我的 package.json 文件中删除了 test:ci 脚本。现在要使用 package.json 中的测试脚本,Heroku CI 将默认查找该脚本。

我的 app.json 文件确保使用 Chrome 进行测试构建包,如下所示:

~/project$ corepack enable pnpm


~/project$ corepack use pnpm@latest

Installing pnpm@9.12.3 in the project…
…
Progress: resolved 1444, reused 1441, downloaded 2, added 1444, done
…
Done in 14.4s

~/project$ rm package-lock.json


~/project$ pnpm install # just to show everything's good


Lockfile is up to date, resolution step is skipped
Already up to date
Done in 1.3s

初始测试运行

我将代码推送到 GitHub,这触发了 Heroku CI 中的测试运行。

Playwright and Chrome Browser Testing in Heroku

试运行失败了,但我并不担心。我知道需要做一些 Playwright 配置。

在测试日志中挖掘,我发现了这个:

~/project$ pnpm remove \
           babel-jest jest jest-puppeteer @testing-library/jest-dom

~/project$ $ pnpm create playwright
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
✔ Do you want to use TypeScript or JavaScript? · JavaScript
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · false
✔ Install Playwright browsers (can be done manually via 'pnpm exec playwright install')? (Y/n) · false
✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo pnpm exec playwright install-deps')? (y/N) · false

Installing Playwright Test (pnpm add --save-dev @playwright/test)…
…
Installing Types (pnpm add --save-dev @types/node)…
…
Done in 2.7s
Writing playwright.config.js.
Writing tests/example.spec.js.
Writing tests-examples/demo-todo-app.spec.js.
Writing package.json.

Playwright 正在寻找 Chrome 浏览器实例。我可以使用 playwright install chromium 命令安装它,作为我的 CI 测试设置的一部分。但这将违背 Chrome 测试构建包的全部目的。 Chrome 已安装;我只需要正确指出它即可。

回顾 Heroku 的测试设置日志,我发现了这些行:

  /* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },

//    {
//      name: 'firefox',
//      use: { ...devices['Desktop Firefox'] },
//    },
//
//    {
//      name: 'webkit',
//      use: { ...devices['Desktop Safari'] },
//    },


  ],
…

所以,我想使用的浏览器位于/app/.chrome-for-testing/chrome-linux64/chrome。我只需要剧作家去那里寻找它。

帮助 Playwright 找到已安装的 Chrome 浏览器

注意:如果您对此处的具体细节不感兴趣,您可以跳过此部分,只需将完整的 app.json 复制到下方即可。这应该为您提供在 Heroku CI 上使用 Playwright 启动和运行所需的信息。

在 Playwright 的文档中,我发现您可以设置一个环境变量,告诉 Playwright 您是否为其所有浏览器安装使用了自定义位置。该环境变量是 PLAYWRIGHT_BROWSERS_PATH。我决定从这里开始。

在 app.json 中,我设置了一个这样的环境变量:

const ROOT_URL = 'http://localhost:8080';
const { test, expect } = require('@playwright/test');

const inputSelector = 'input[name="name"]';
const submitButtonSelector = 'button[type="submit"]';
const greetingSelector = 'h5#greeting';
const name = 'John Doe';

test.beforeEach(async ({ page }) => {
  await page.goto(ROOT_URL);
});

test.describe('Playwright link', () => {
  test('should navigate to Playwright documentation page', async ({ page }) => {
    await page.click('a[href="https://playwright.dev/"]');
    await expect(page.title()).resolves.toMatch('| Playwright');
  });
});

test.describe('Text input', () => {
  test('should display the entered text in the text input', async ({ page }) => {
    await page.fill(inputSelector, name);

    // Verify the input value
    const inputValue = await page.inputValue(inputSelector);
    expect(inputValue).toBe(name);
  });
});

test.describe('Form submission', () => {
  test('should display the "Hello, X" message after form submission', async ({ page }) => {
    const expectedGreeting = `Hello, ${name}.`;
    await page.fill(inputSelector, name);
    await page.click(submitButtonSelector);

    await page.waitForSelector(greetingSelector);
    const greetingText = await page.textContent(greetingSelector);
    expect(greetingText).toBe(expectedGreeting);
  });
});

我将代码推送到 GitHub,看看 CI 中的测试会发生什么。

果然,又失败了。然而,日志错误显示:

~/project$ corepack enable pnpm


~/project$ corepack use pnpm@latest

Installing pnpm@9.12.3 in the project…
…
Progress: resolved 1444, reused 1441, downloaded 2, added 1444, done
…
Done in 14.4s

~/project$ rm package-lock.json


~/project$ pnpm install # just to show everything's good


Lockfile is up to date, resolution step is skipped
Already up to date
Done in 1.3s

这让我非常接近。我决定这样做:

  • 创建 Playwright 期望 Chrome 浏览器所在位置所需的文件夹。那将是一个像这样的命令:
~/project$ pnpm remove \
           babel-jest jest jest-puppeteer @testing-library/jest-dom

~/project$ $ pnpm create playwright
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
✔ Do you want to use TypeScript or JavaScript? · JavaScript
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · false
✔ Install Playwright browsers (can be done manually via 'pnpm exec playwright install')? (Y/n) · false
✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo pnpm exec playwright install-deps')? (y/N) · false

Installing Playwright Test (pnpm add --save-dev @playwright/test)…
…
Installing Types (pnpm add --save-dev @types/node)…
…
Done in 2.7s
Writing playwright.config.js.
Writing tests/example.spec.js.
Writing tests-examples/demo-todo-app.spec.js.
Writing package.json.
  • 在此文件夹中创建一个符号链接以指向 Heroku buildpack 安装的 Chrome 二进制文件。那看起来像这样:
  /* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },

//    {
//      name: 'firefox',
//      use: { ...devices['Desktop Firefox'] },
//    },
//
//    {
//      name: 'webkit',
//      use: { ...devices['Desktop Safari'] },
//    },


  ],
…

但是,我担心这是否能经得起未来的考验。最终,Playwright 将使用新版本的 Chromium,并且它不会再出现在 chromium-1140 文件夹中。我怎样才能知道剧作家会看哪里?

就在那时我发现你可以进行浏览器安装试运行。

const ROOT_URL = 'http://localhost:8080';
const { test, expect } = require('@playwright/test');

const inputSelector = 'input[name="name"]';
const submitButtonSelector = 'button[type="submit"]';
const greetingSelector = 'h5#greeting';
const name = 'John Doe';

test.beforeEach(async ({ page }) => {
  await page.goto(ROOT_URL);
});

test.describe('Playwright link', () => {
  test('should navigate to Playwright documentation page', async ({ page }) => {
    await page.click('a[href="https://playwright.dev/"]');
    await expect(page.title()).resolves.toMatch('| Playwright');
  });
});

test.describe('Text input', () => {
  test('should display the entered text in the text input', async ({ page }) => {
    await page.fill(inputSelector, name);

    // Verify the input value
    const inputValue = await page.inputValue(inputSelector);
    expect(inputValue).toBe(name);
  });
});

test.describe('Form submission', () => {
  test('should display the "Hello, X" message after form submission', async ({ page }) => {
    const expectedGreeting = `Hello, ${name}.`;
    await page.fill(inputSelector, name);
    await page.click(submitButtonSelector);

    await page.waitForSelector(greetingSelector);
    const greetingText = await page.textContent(greetingSelector);
    expect(greetingText).toBe(expectedGreeting);
  });
});

“安装位置”这一行至关重要。而且,如果我们设置 PLAYWRIGHT_BROWSERS_PATH,我们将看到以下内容:

~/project$ pnpm remove start-server-and-test

这就是我想要的。借助一点 awk 的魔力,我做到了:

  /* Run your local dev server before starting the tests */
  webServer: {
     command: 'pnpm start',
     url: 'http://127.0.0.1:8080',
     reuseExistingServer: !process.env.CI,
  },

弄清楚所有这些后,我只需要向 app.json 添加一个测试设置脚本即可。因为 PLAYWRIGHT_BROWSERS_PATH 已经在 env 中设置,所以我的脚本会更简单一些。这是我最终的 app.json 文件:

  "scripts": {
    …
    "test": "playwright test --project=chromium --reporter list"
  },

我将简要介绍一下测试设置的作用:

  1. 考虑到 PLAYWRIGHT_BROWSERS_PATH,使用 playwright install -- dry-run 和 awk 来确定 Playwright 将在其中查找 Chrome 浏览器的根文件夹。将其设置为 CHROMIUM_PATH 变量的值。

  2. 在 CHROMIUM_PATH/chrome-linux 中创建一个新文件夹(以及任何必要的父文件夹),这是 Playwright 将在其中查找 chrome 二进制文件的实际文件夹。

  3. 在该文件夹中创建一个符号链接,以便 chrome 指向 Chrome 的 Heroku buildpack 安装 (/app/.chrome-for-testing/chrome-linux64/chrome)。

再次运行测试

通过我更新的 app.json 文件,Playwright 应该能够使用 buildpack 中的 Chrome 安装。是时候再次运行测试了。

Playwright and Chrome Browser Testing in Heroku

成功!

测试设置脚本按预期运行。

Playwright and Chrome Browser Testing in Heroku

Playwright 能够访问 chrome 二进制文件并运行测试,并且通过了。

Playwright and Chrome Browser Testing in Heroku

结论

我的 Web 应用程序的端到端测试变得不再那么麻烦,因此我越来越优先考虑它。最近几天,这意味着更多地使用剧作家。它灵活且快速。现在我已经完成了工作(对我和你!),在 Heroku CI 中使用 Chrome for Test 构建包启动并运行它,我可以开始构建我的浏览器自动化测试套件了再次。

本演练的代码可在我的 GitHub 存储库中找到。

编码愉快!

以上是Heroku 中的 Playwright 和 Chrome 浏览器测试的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn