我一直喜欢观看我的单元测试运行(并通过)。它们速度很快,并且通过测试让我确信我的个人作品表现得像他们应该的那样。相反,我经常很难确定浏览器端到端测试的优先级,因为编写和运行它们的速度非常慢。
幸运的是,多年来,用于端到端浏览器内测试的工具已经变得更好更快。通过无头浏览器设置,我可以运行浏览器测试作为 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 应用程序,带有链接、文本输入和提交按钮。共有三个测试:
验证链接是否有效并重定向到正确的位置。
验证文本输入是否正确显示用户输入。
验证提交表单是否会更新页面上显示的文本。
非常简单。现在,我只需更改代码以使用 Playwright 而不是 Puppeteer 和 Jest。哦,我还想使用 pnpm 而不是 npm。这是我分叉的 GitHub 存储库的链接。
让我们看看我修改代码的步骤。我从我的分叉存储库开始,与 heroku-examples 存储库相同。
我想使用 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 配置部分。
您可以在 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 测试文件,位于 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); }); });
为了测试我的 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 安装其版本的 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 博客文章中的说明在 Heroku CI 管道中设置了我的应用程序。
在 Heroku 中,我创建了一个新管道并将其连接到我分叉的 GitHub 存储库。
接下来,我将我的应用程序添加到了 staging。
然后,我转到 测试 选项卡并单击 启用 Heroku CI。
最后,我修改了 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 配置。
在测试日志中挖掘,我发现了这个:
~/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。我只需要剧作家去那里寻找它。
注意:如果您对此处的具体细节不感兴趣,您可以跳过此部分,只需将完整的 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
这让我非常接近。我决定这样做:
~/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.
/* 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" },
我将简要介绍一下测试设置的作用:
考虑到 PLAYWRIGHT_BROWSERS_PATH,使用 playwright install -- dry-run 和 awk 来确定 Playwright 将在其中查找 Chrome 浏览器的根文件夹。将其设置为 CHROMIUM_PATH 变量的值。
在 CHROMIUM_PATH/chrome-linux 中创建一个新文件夹(以及任何必要的父文件夹),这是 Playwright 将在其中查找 chrome 二进制文件的实际文件夹。
在该文件夹中创建一个符号链接,以便 chrome 指向 Chrome 的 Heroku buildpack 安装 (/app/.chrome-for-testing/chrome-linux64/chrome)。
通过我更新的 app.json 文件,Playwright 应该能够使用 buildpack 中的 Chrome 安装。是时候再次运行测试了。
成功!
测试设置脚本按预期运行。
Playwright 能够访问 chrome 二进制文件并运行测试,并且通过了。
我的 Web 应用程序的端到端测试变得不再那么麻烦,因此我越来越优先考虑它。最近几天,这意味着更多地使用剧作家。它灵活且快速。现在我已经完成了工作(对我和你!),在 Heroku CI 中使用 Chrome for Test 构建包启动并运行它,我可以开始构建我的浏览器自动化测试套件了再次。
本演练的代码可在我的 GitHub 存储库中找到。
编码愉快!
以上是Heroku 中的 Playwright 和 Chrome 浏览器测试的详细内容。更多信息请关注PHP中文网其他相关文章!