














一年多前,我写了一篇 e2e 测试工具 Cypress。
当时它的 npm 下载量是 e2e 测试工具里排最高的。
没曾想,短短一年间,它就被 Playwright 完全赶超了😱

Playwright 是谁?怎么这么厉害?
Playwright 大有来头,它是 Microsoft 开源的 e2e 测试工具。
团队是从 Google Puppeteer 过来的大佬。
因此它不仅仅是 e2e 测试工具,也可以向 Puppeteer 那样作为 headless browser 使用。
除此之外,它还支持很多语言,不仅有 JavaScript, TypeScript,后端语言 C#,Java,Python 它也都支持。
不得不说,这么强大,要不火都难啊。
本篇我会延用上一篇 Cypress 的例子,重新用 Playwright 实现一遍,体验一下 Playwright 的强大。
单元测试,我们通常会把测试代码和被测试代码放到一块,under 同一个项目。
而 e2e 测试则不一定,有些人 prefer 分开两个项目管理,有些人则会放到一块。
Playwright 俩都支持,本篇会采用放到一块的方式。
此外,Playwright 支持多平台,想使用 JS / TS 的话,就搭配 Node.js,想使用 C# 就搭配 .NET。
这意味着,我们甚至可以用 C# 写测试代码,然后去测试一个 Angular (非 C#) 的项目。
本篇会采用 JS / TS + Node.js 的方式。
创建一个项目,这里我用 Vite TypeScript,你也可以用其它的。
写一个简单的页面
.html

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + TS</title> </head> <body> <form autocomplete="off"> <input placeholder="First Name"> <input placeholder="Last Name"> <button>Submit</button> <p class="thank-you">Thank you! We have received your enquiry.</p> </form> <script type="module" src="/src/main.ts"></script> </body> </html>
View Code
.scss

* { padding: 0; margin: 0; box-sizing: border-box; &:focus { outline: none; } button { border-width: 0; } } body { height: 100vh; display: flex; justify-content: center; align-items: center; form { min-width: 320px; display: flex; flex-direction: column; gap: 16px; input { border-radius: 4px; border: 1px solid black; padding: 16px; } button { border-radius: 4px; background-color: pink; color: red; padding: 20px; font-size: 20px; text-transform: uppercase; letter-spacing: 1px; } .thank-you { line-height: 1.5; &:not(.shown) { display: none; } } } }
View Code
.ts

import './style.scss' document.querySelector('form')!.addEventListener('submit', e => { e.preventDefault(); document.querySelector('.thank-you')!.classList.add('shown'); });
View Code
执行 command
效果

安装过程中,它会问 3 个问题

第一个是,e2e 测试代码文件要放在哪个 folders,默认是 /tests。
第二个是,要不要搭配 Github,每当 checkin 的时候自动做测试,我没有这个习惯,所以选了 No。
第三个是,要不要安装游览器,我已经安装过了,所以选 No,第一次安装的可以选 Yes,或者之后单独安装也可以
Playwright 主要使用的游览器是 Chromium (Chrome / Edge 底层游览器)、Firefox、WebKit (它不是 Safari 游览器,而是一个搭载 WebKit 渲染引擎和 JavaScriptCore JS 引擎的 Safari 环境模拟器)
通常做 e2e 测试,这三个主流游览器都会一起测试。
安装好后会多出 3 个 files

往后的测试文件通通放入 tests folder 里。
tests-example 只是一个参考例子,可以删掉。
playwright.config.ts 是配置 playwright 的文件。
把我们的测试代码写进 example.spec.ts 里
import { test, expect } from '@playwright/test';
test('test form', async ({ page }) => {
await page.goto('http://localhost:5173'); // 访问我们的程序页面
await expect(page.locator('.thank-you')).toBeHidden(); // 检查 thank you message 必须是 hidden
await page.getByPlaceholder('First Name').fill('Derrick'); // 查找 input 'First Name' 输入 'Derrick'
await page.getByPlaceholder('Last Name').fill('Yam'); // 查找 input 'Last Name' 输入 'Yam'
await page.locator('button').click(); // 点击 submit
await expect(page.locator('.thank-you')).toBeVisible(); // 检查 thank you message 必须是 shown
});
Playwright 的测试代码大致上就是 UI 操作,然后检查 UI 的变化。
当然它也可以发 request 检查资料是否输入到 database 等等。
反正人怎么 test 它就怎么 test 就对了。
执行 command
yarn dev
yarn playwright test
效果

之所以是 3 passed,3 workers 是因为默认启动了 3 个游览器测试。(主:如果觉得 Firefox 没有必要的话,可以去 playwright.config.ts 把它移除)
如果觉得 command 的 result 太单调,可以接着执行这个 command
yarn playwright show-report
它会以页面的方式呈现之前的 result。(注:如果测试 failed,它会自动显示这个 report,如果成功默认不会额外显示这个 report)

另外呢,它还有一个更细节操控的模式,执行 command
yarn playwright test --ui
在执行 test command 时加上一个 --ui

它会打开一个 dialog,我们可以选定要执行的 test,可以看到每一行 expect 的执行过程,非常细,细到可以 debug 了。
不知道大家用过 Excel macro 没有,我依稀记得在还没有学习编程以前,我只会在 Excel 上写点 formula,用 macro 录制生成一些 Visual Basic 代码。
那时厂里有个资深工人会写 Visual Basic,我就觉得他好厉害啊。
好,回忆结束,回来。
Playwright 也有类似 marco 的功能,我们可以录制生成测试代码。
执行 command
yarn playwright codegen http://localhost:5173
它会 popup 2 个窗口

左边是我们的录制程序,右边是自动生成出来的测试代码。
用法很简单,当我们 hover 到 'First Name' input 时,它会显示相关的测试代码

点击后会自动生成一行测试代码

我们继续填写资料到 input 上

它会持续添加测试代码

最后

它会生成出

用 recording 的方式 generate 测试代码,虽然可能不太精准,但体验还是挺好的,推荐大家去玩一玩。
去 playwright.config.ts 加上 baseUrl
export default defineConfig({ use: { baseURL: 'http://localhost:5173', }, });
效果
await page.goto('http://localhost:5173'); // before
await page.goto('/'); // after
Playwright 默认测试文件的路径是 tests/**/*.spec.ts
有时候我们更希望把 .spec.ts 和测试页面放到一块
可以这样配置
export default defineConfig({ // testDir: './tests', testMatch: ['/src/**/*.spec.ts', '/tests/**/*.spec.ts'], testIgnore: [], });
把 testDir 改成 testMatch,然后写 Glob Patterns。
要 skip 掉某些 file 或 folder,可以使用 testIgnore。
输入字到 input
await page.locator('input').fill('Derrick');
check 是否可见
await expect(page.locator('.thank-you')).toBeHidden();
等我以后用到了才回来补。
很多年前我写过一篇 Html to PDF。
当时的做法是在 .NET 利用 Javascript.NodeJS 调用 Puppeteer 来 convert HTML to PDF。
非常麻烦的做法。后来 .NET 有了 port to Puppeteer 的 library -- Puppeteer Sharp,至少是少了 Node.js 这个环节。
如今有了 Playwright 连 Puppeteer 都不需要了。
Playwright 支持 .NET,同时它具备 headless browser 的特性 (类似 puppeteer),所以它可以直接 convert HTML to PDF。
invoice.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Invoice</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; } .invoice { max-width: 800px; margin: 20px auto; padding: 20px; background-color: #fff; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .header h1 { margin: 0; } .company-info { text-align: left; } .invoice-info { text-align: right; } .client-info { margin: 20px 0; } .items-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; } .items-table thead { background-color: #f4f4f4; } .items-table th, .items-table td { padding: 10px; border: 1px solid #ddd; text-align: left; } .items-table th { background-color: #e0e0e0; } .text-right { text-align: right; } tfoot td { font-weight: bold; } .footer { text-align: center; margin-top: 20px; font-size: 0.9em; color: #666; } </style> </head> <body> <div class="invoice"> <!-- Header Section --> <div class="header"> <h1>Invoice</h1> <div class="company-info"> <h2>Electronic Instruments Co., Ltd.</h2> <p>123 Tech Avenue, Silicon Valley, CA 94043</p> <p>Email: contact@eico.com | Phone: (123) 456-7890</p> </div> <div class="invoice-info"> <p>Invoice #: 001234</p> <p>Date: 2025-01-14</p> <p>Due Date: 2025-01-31</p> </div> </div> <!-- Client Information --> <div class="client-info"> <h3>Billed To:</h3> <p>Company Name: ABC Tech Solutions</p> <p>Address: 456 Business Road, Tech City, TX 75001</p> <p>Email: billing@abctech.com</p> </div> <!-- Product Items Section --> <table class="items-table"> <thead> <tr> <th>Item</th> <th>Description</th> <th>Quantity</th> <th>Unit Price</th> <th>Total</th> </tr> </thead> <tbody> <tr> <td>001</td> <td>Precision Oscilloscope</td> <td>2</td> <td>$1,200.00</td> <td>$2,400.00</td> </tr> <tr> <td>002</td> <td>Digital Multimeter</td> <td>5</td> <td>$300.00</td> <td>$1,500.00</td> </tr> <tr> <td>003</td> <td>Signal Generator</td> <td>1</td> <td>$1,000.00</td> <td>$1,000.00</td> </tr> </tbody> <tfoot> <tr> <td colspan="4" class="text-right">Subtotal:</td> <td>$4,900.00</td> </tr> <tr> <td colspan="4" class="text-right">Tax (10%):</td> <td>$490.00</td> </tr> <tr> <td colspan="4" class="text-right"><strong>Total:</strong></td> <td><strong>$5,390.00</strong></td> </tr> </tfoot> </table> <!-- Footer Section --> <div class="footer"> <p>Thank you for your business!</p> <p>Please make payment to the above address by the due date.</p> </div> </div> </body> </html>
View Code
这是要 convert to PDF 的 HTML。
安装 Playwright
dotnet add package Microsoft.Playwright
program.cs
using Microsoft.Playwright; var rootPath = Path.Combine(AppContext.BaseDirectory, @"..\..\..\"); string htmlFilePath = Path.Combine(rootPath, "invoice.html"); string pdfFilePath = Path.Combine(rootPath, "invoice.pdf"); string rawHtml = File.ReadAllText(htmlFilePath); using var playwright = await Playwright.CreateAsync(); await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true }); var page = await browser.NewPageAsync(); await page.SetContentAsync(rawHtml); await page.PdfAsync(new PagePdfOptions { Path = pdfFilePath, // Output PDF file path Format = "A4", // PDF format, e.g., A4, Letter PrintBackground = true // To include background colors/images in the PDF });
代码很简单,我就不解释了。
Playwright 真的很强大,不愧是 Microsoft 出品,有那个水准,希望微软未来能多开源这类的项目。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。