你好,QA 爱好者们(可能不仅仅是 QA,也不仅仅是爱好者),
如果你们现在看到这条消息,祝你们圣诞节快乐!如果不是圣诞节期间也没关系,希望你们仍然心情愉快,享受美好的一天。
随着2024年的临近结束,我不禁回顾这一年——一个总结和回顾的时间。虽然最初我打算对这一年做一个大致的总结,但这篇文章的重心自然而然地转向了更具体和更技术化的方面:回顾Playwright中最实用的功能。
这篇文章总结了那些特性——包括我之前写过的,也有一些你可能已经熟悉的,也许还有一些新的发现等你去探索。
如果你是第一次接触 Web UI 自动化测试,你会很高兴地知道 Playwright 不仅仅是测试中的基本点击和输入操作。它还提供了一系列强大的功能和工具,可以大大提升你的自动化技能。
那么,让我们深入了解一下其中一些我认为最有用且值得加入你项目的功能。
Playwright元素选择器Playwright 的一个核心功能是您每天肯定会用到的定位器。利用其内置的自动等待功能,Playwright 确保了可靠的交互体验,使您的自动化测试更加高效和有效,更可靠。最好的部分是,您可以使用熟悉的旧式选择器(如 CSS、XPath 和 ID),还可以使用 Playwright 提供的现代定位器,这些定位器旨在简化并增强您的测试体验,让测试过程更加轻松。
遗产定位器对于那些已经在 Web UI 自动化领域工作了一段时间的人来说,这可能不算新闻。然而,当你应用依赖于复杂的 UI 组件封装时,这仍然可能很有用,这使得采用 Playwright 的现代内置定位器变得比较困难。
export default class ABTestingPage extends BasePage {
readonly pageHeader: Locator;
readonly contentText: Locator;
constructor(page: Page) {
super(page);
this.pageHeader = this.page.locator('h3');
this.contentText = this.page.locator('div.example > p');
}
// 获取页面头部文本
async getPageHeader(): Promise<string> {
return await this.pageHeader.innerText();
}
// 获取内容文本
async getContentText(): Promise<string> {
return await this.contentText.innerText();
}
}
我们这些“老恐龙”可能仍然更喜欢用旧方法。话虽如此,Playwright不仅支持,还大力推广了它自己定位元素的方法——这确实让体验变得非常好。
内置定位器
Playwright的内置定位器
在当前的Playwright实现中,推荐使用内置定位器来查找其他定位器。
//通过角色获取示例
<button>登录</button>
await page.getByRole('button', { name: '登录' }).click();
//通过文本获取
<span>欢迎,约翰</span>
await expect(page.getByText('欢迎,约翰')).toBeVisible();
//找到带有数据测试ID的元素
<button data-testid="directions">找</button>
await page.getByTestId('directions').click();
正如你所见,它更易读,更注重文本,而不是属性。更多详情请参阅官方文档。
这是一个关于Playwright定位器的文档页面。https://playwright.dev/docs/locators
选择一边或是灵活一点吧:)
这里涉及简单的框架和 Shadow-Dom 操作去除了处理帧和影子DOM的复杂性。
隐藏DOMplaywright 并不忽视 Shadow DOM——它通过让其在大多数情况下操作起来更加流畅,来简化开放式 Shadow DOM 的操作。
- 对于封闭的 Shadow DOM,浏览器有一些限制,你需要依赖间接的方法来处理。
- Playwright 的定位器 (
locator
,getByRole
等) 自动处理 Shadow DOM,简化了在许多情况下的手动查询需求。
打开影根示例(如下所示):
<x-details role="button" aria-expanded="true" aria-controls="inner-details">
<div>标题</div>
// shadow-root (open)
<div id="inner-details">详情</div>
</x-details>
await page.getByText('详情').click({force: true});
<my-paragraph>
// shadow-root (open)
<span slot="my-text">让我们有一些不同的内容!</span>
</my-paragraph>
await this.page.locator('my-paragraph span').textContent();
框架部分
在许多测试工具里,处理frames(框架)往往很棘手,但Playwright提供了简洁且强大的API,大大简化了处理过程。
const frame = page.frame({ url: /some-frame-url/ });
await frame.locator('button#submit').click(); // 点击提交按钮
await page.frameLocator('iframe#login-frame').locator('input#username').fill('user123');
await page.frameLocator('iframe#login-frame').locator('input#password').fill('password123');
await page.frameLocator('iframe#login-frame').locator('button#login').click(); // 登录操作
像以前 Selenium 那样,你需要切换并退出框架
// 切换到登录框架并输入用户名
driver.switchTo().frame("login-frame");
driver.findElement(By.id("username")).sendKeys("user123");
为什么在Playwright里更容易呢?
- 无需手动切换上下文——帧的行为与普通页面对象一致。
- 内置支持自动等待,减少了测试出现不稳定的风险。
frameLocator
提供了一个干净、声明式的 API 来处理嵌套的iframe。- 简化了动态和异步帧的处理。
- 提供了强大的调试和错误信息功能,以有效解决问题。
这可能难以置信,但最初 Playwright 并没有断言功能。不过,如今 Playwright 通过 expect
函数自带了内置的测试断言。要进行断言,你可以调用 expect(value)
并选择一个符合你期望的匹配器。
playwright 提供了多种匹配器,例如 toEqual
,toContain
,toBeTruthy
等等,可以用来断言各种情况。
//toHaveText
await expect(page.getByTestId('status')).toHaveText('已提交');
//toContain
expect(pageHeaders).包含(pageHeader);
//toBe与软断言
expect.soft(deleteBtnsAfterDelete.length).toBe(1);
expect.soft(deleteBtns.length).toBe(addBtnCount);
//toEqual
expect.soft(secondParagraphText).等于(expectedSecondParagraphText);
//toBeTruthy
expect.truthy(fs.existsSync(savePath));
请在官方文档中查看更多详情https://playwright.dev/docs/test-assertions
配件最初,测试固定数据被认为是高级主题。今天,它们已经成为了测试中必备的功能之一。几年前,我还专门写过一篇文章来讨论这个话题:自动化故事中的固定数据用处。在这篇文章中,我会简单地谈一下这个话题。
Playwright 中的 Fixtures 是非常强大的工具,让您的测试更高效、可重用且模块化。它们使测试管理更简单,处理常见的设置任务,确保测试隔离,并为复杂的测试场景提供更多灵活性。通过利用 fixtures,您可以编写更清晰、更易于维护且更稳健的测试套件。
你可以用几种不同的方法来使用它,例如初始化页面的封装。
//fixture-extension.ts - 名称无关紧要
import { test as base } from '@playwright/test';
import MainPage from "./pages/_main-page/main-page";
import ABTestingPage from './pages/ab-testing-page/ab-testing-page';
type Pages = {
mainPage: MainPage;
abTestPage: ABTestingPage;
}
export const test = base.extend<Pages>({
mainPage: async ({ page }, use) => {
await use(new MainPage(page));
},
abTestPage: async ({ page }, use) => {
await use(new ABTestingPage(page));
}
});
export { expect } from '@playwright/test';
//用法
test.beforeEach(async ({ mainPage, baseURL }) => {
await allure.suite('A/B 页面测试 - 使用 allure.suite 属性'); // 如果未指定,将使用 describe 块中的套件名称
await mainPage.navigateUrl(new PageDataConstants(baseURL as string).abTestingPage.getUrlPath());
await mainPage.waitForPageLoad();
});
test('检查页面内容', async ({ abTestPage }) => {
//设置
const pageHeaders = ['A/B 测试变体 1', 'A/B 测试对照'];
const pageText = '也就是拆分测试。这是企业测试和学习页面不同版本的一种方式,以确定哪种文本或功能最适合预期结果(例如用户操作,如点击转化)。';
//操作
const [pageHeader, contentText] = await Promise.all([
await abTestPage.getPageHeader(),
await abTestPage.getContentText()
]);
//断言
expect(pageHeaders).包含(pageHeader);
expect(contentText).包含(pageText);
});
你也许还想在页面上添加一些服务
import { test as base } from '@playwright/test';
import MainPage from "./pages/_main-page/main-page";
import ABTestingPage from './pages/ab-testing-page/ab-testing-page';
import { AuthManagegementRequest } from "@service-auth-management-api/facade/auth-management-requests";
import { SqlTables } from "@service-sql/facade/sql-request-tables";
type Services = {
sqlRequest: SqlTables,
authManagementApiRequest: AuthManagegementRequest,
}
export const test = base.extend<Pages & Services>({
// 例如数据库和API这样的服务
authManagementApiRequest: authManagementApiRequest,
sqlRequest: new SqlTables(Config.SqlConnectionString),
// 快速访问的页面初始化
mainPage: async ({page}, use) => {
await use(new MainPage(page)); // 创建并使用MainPage页面
},
abTestPage: async ({page}, use) => {
await use(new ABTestingPage(page)); // 创建并使用ABTestingPage页面
}
})
export { expect} from '@playwright/test';
当然,你可以创建多个 fixture 文件,并根据需要使用它们。你甚至可以添加更多内容,比如设置页面的初始设置。
import { test as base } from '@playwright/test';
import { TodoPage } from './todo-page';
// 声明你的选项以进行类型检查。
export type MyOptions = {
defaultItem: string;
};
type MyFixtures = {
todoPage: TodoPage;
};
// 指定选项和 fixture 类型如下:
export const test = base.extend<MyOptions & MyFixtures>({
// 定义一个选项并提供默认值。
// 我们之后可以在配置文件中覆盖它。
defaultItem: ['Something nice', { option: true }],
// 我们的 'todoPage' fixture 依赖于 'defaultItem' 选项。
todoPage: async ({ page, defaultItem }, use) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await todoPage.addToDo(defaultItem);
await use(todoPage);
await todoPage.removeAll();
},
});
export { expect } from '@playwright/test';
了解更多关于 fixtures 的信息,请参阅官方文档,我建议你使用它。
API接口及请求拦截 REST API接口Playwright 允许您直接从 Node.js 与应用程序的 REST API 进行交互,无需加载页面或在浏览器中运行 JavaScript。这在各种情况下都非常有用,例如:
- 独立于UI测试服务器的API。
- 在导航到应用程序进行测试前,先设置服务器端状态。
- 在执行浏览器操作后,验证服务器端的后置条件。
所有这些功能都是通过 APIRequestContext
方法提供的,这些方法允许你发送请求并与你的服务器进行无间断互动,以确保流畅的交互。
发送 POST 请求的例子:
test('向 Petstore API 发送 POST 请求', async ({ request }) => {
// 准备
const payload = {
id: 0,
username: "testUser",
firstName: "FirstName",
lastName: "LastName",
email: "test@example.com",
password: "password123",
phone: "1234567890",
userStatus: 0
};
// 执行
const response = await request.post('https://petstore.swagger.io/v2/user', {
data: payload,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
// 验证
expect(response.status()).toBe(200); // 验证状态码为 200
const responseBody = await response.json();
console.log('POST 请求的响应:', responseBody);
expect(responseBody.message).toBe(String(payload.id)); // 验证返回的消息是否与 ID 匹配
});
GET请求示例:
test('通过名称获取国家信息', async ({ request }) => {
// 准备
const countryName = 'Ukraine';
// 执行
const response = await request.get(`https://restcountries.com/v3.1/name/${countryName}`);
// 断言验证
expect(response.status()).toBe(200); // 验证状态码为 200
const responseBody = await response.json();
console.log('GET 响应:', responseBody); // 调试时记录响应
expect(responseBody[0]?.name?.common).toBe(countryName); // 验证返回的国家名称与请求的一致
});
正如你所见,它的使用非常简单。我建议把它打包成独立的服务。
请求拦截功能另一个在Playwright中非常有用的特性是拦截和模拟请求的功能。借助这一功能,你可以阻止某个请求的处理,或者返回自定义响应,从而控制测试应用程序的行为。
这尤其有价值,当你希望测试特定的界面行为而无需准备大量测试数据时。
我之前写过一篇文章文章,详细介绍了这种做法。在这里,我将简要介绍一下这个概念。
Web API 通常实现为 HTTP 端点。Playwright 提供了用于模拟和修改 HTTP 和 HTTPS 网络流量的 API。页面上的任何请求,例如 XHRs 和 fetch 请求,都可以被追踪、修改或模拟。
例如拦截并终止请求:
test('拦截 HTTP 请求 - 终止它 - 比萨部分不应该被显示', async ({ page, context }) => {
// 设置
const interceptRoute = '**/pizzas';
await context.route(interceptRoute, route => route.abort());
// 操作
await page.goto(url);
// 验证
await 验证产品和部分标题是否被隐藏(page);
});
关于拦截和响应的示例更新
test('拦截 HTTP 请求并修改响应 - 修改为每个类别返回一个产品', async ({ page, context }) => {
// 准备
const modifiedResponse = [
{
id: 21,
name: "披萨 '卡邦尼'",
category: 1,
price: 330,
weight: 540,
diameterInCentimeters: 30,
}
];
await context.route('**/products', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(modifiedResponse),
});
});
// 执行
await page.goto(url);
// 验证
await expect(page.locator('div.product-list__title:has-text("Pizza")')).toBeVisible();
});
在用户界面上找到边界问题相对来说比较简单。然而,我个人的建议是在较低层级的测试解决这些问题,比如组件级别的测试。不过,最终还是要看你的项目的具体需求和结构。
屏幕截图和视觉对比Playwright 测试具备截图捕获和视觉比较功能。现在你可以更专注于比较屏幕上的特定区域,这使得功能更加精准高效。
这一部分我们要分成几个小节。
截个图如果你想截图一个页面,欢迎
await page.screenshot({ path: 'screenshot.png' });
截取特定区域的截图
也很简单地。只需用一个定位点代替原来的那一页。
我要给这个区域截图。
await page.locator('h4.subheader').screenshot({path: 'login-page-text.png'});
解释:等待页面定位器('h4.subheader')截图,并保存到路径'login-page-text.png'。
截图保存好了。
屏幕截图的比较我们想比较一下。这也挺简单的。
test('静态字段的屏幕比较 - 应通过', async ({ loginPage, page }) => {
// 准备
const firstName = 'Kostiantyn';
// 执行
await loginPage.fillUsernameAndPassword(firstName, 'password');
// 断言
await expect(page).toHaveScreenshot({ maxDiffPixels: 10 }); // 最大差异像素数:10
});
这里只是简单说几点内容:
- 第一次会失败,因为它需要先保存。
- 你可以做类似的测试,使用特定区域的测试,只需使用定位器而不是整个页面。
还有一个选择是配置自带的自动截图设定
只需打开
playwright.config.ts
文件,在全局use
对象或特定项目的use
对象中加入screenshot
字段即可。
配置: {
// 只在失败时截屏
screenshot: '失败时',
},
現在有很多選項可以選擇,所以你可以選定其中幾個
设置如果我们已经调整了配置,我们可以直接使用它。Playwright提供了许多选项来配置您的(或你们的)测试执行方式。
配置文件(config文件)默认情况下,Playwright测试配置保存于“playwright.config.ts”文件。更多细节请参见 官方文档。
随便稍微碰一下也好。
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
// 在与配置文件相同的目录下的 'tests' 文件夹中查找测试文件。
testDir: 'tests',
// 并行执行所有测试。
fullyParallel: true,
// 如果在源代码中不小心使用了 test.only,CI 构建将会失败。
forbidOnly: !!process.env.CI,
// 仅在 CI 上重试。
retries: process.env.CI ? 2 : 0,
// 在 CI 上禁用并行测试功能。
workers: process.env.CI ? 1 : undefined,
// 使用的报告器类型
reporter: 'html',
use: {
// 在执行如 `await page.goto('/')` 等操作时使用的基地址。
baseURL: 'http://127.0.0.1:3000',
// 在重试失败的测试时收集跟踪信息。
trace: 'on-first-retry',
},
// 配置主要浏览器的项目设置。
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
// 在启动测试前运行本地开发服务器以提供测试环境。
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
reuseExistingServer: !process.env.CI,
},
});
在 Playwright 中,你可以定义设置的几个级别:
- 全局层级:适用于所有项目,除非被覆盖。
- 项目层级:仅适用于特定项目,并始终覆盖全局层级配置。
一些最常见的全球设置包括...
**timeout**
默认超时时间(以毫秒为单位),适用于所有测试操作和期望的时间设定。**retries**
失败测试重试的次数。**workers**
并行测试工作的数量。**reporter**
测试结果报告的方式(例如 HTML、JSON、点等)。**testDir**
包含测试文件的目录。**testMatch**
测试文件的匹配模式。**globalSetup**
和**globalTeardown**
在测试套件开始前和结束后执行的脚本。**outputDir**
用于存储截图或视频等工件的目录。
项目特定的
**名**
用于标识项目名称的标签。**用途**
浏览器和测试相关的选项。
常用子选项:
**browserName**
:浏览器类型(chromium
,firefox
,webkit
)。这样棒的一点是,你可以在本地安装的浏览器或Playwright下载的浏览器版本上执行测试。**headless**
:以无头模式运行测试。**viewport**
:浏览器视口的宽度和高度设置。**screenshot**
:截图选项('on'
,'only-on-failure'
,'off'
)已经在前面的章节中提到过。**video**
:录制视频选项('on'
,'retain-on-failure'
,'off'
),这也是一个非常有用的选项。**trace**
:收集调试用的跟踪文件('on'
,'retain-on-failure'
,'off'
),这对于调试非常有用。
被提到感觉很高兴
**timezoneId**
:模拟在特定时区运行的浏览器。示例:'America/New_York'
将浏览器的时区设置为纽约。测试显示与时区相关的内容的应用程序,例如活动日程或基于时间的促销。**geolocation**
:通过指定纬度和经度来模拟特定的地理位置,测试依赖于位置的功能,例如基于位置的搜索结果或地理围栏功能。- 验证特定地区用户的行为。例如:
地理位置: 经度 -74.006, 纬度 40.7128
**权限**
: 为测试环境授予特定的浏览器权限。测试需要权限的应用场景,如位置服务的应用或推送通知。确保应用能够正确处理权限请求及其授权或拒绝状态。 示例:
权限要求: ['地理位置访问', '通知推送']
和DotEnv合作
这虽然是一个与Playwright无关的话题,但还是提一下比较好。使用DotEnv和Playwright可以通过从.env
文件加载它们来集中和安全地管理环境变量值。这种方法特别适用于跨测试环境管理敏感数据(例如,API密钥和凭证)和其他配置选项。
首先,你需要安装这个
dotenv
包。
npm install dotenv
在项目根目录添加一个 .env
文件。在这里定义你的环境变量。
基础URL=https://example.com # 基础URL是环境变量或配置设置
无头浏览器=true # 无头浏览器是环境变量或配置设置
API密钥=12345abcd # API密钥是环境变量或配置设置
用 dotenv
加载 .env
变量,然后修改你的 playwright
配置文件。
import { defineConfig } from '@playwright/test';
import * as dotenv from 'dotenv';
// 从 `.env` 文件加载环境设置
dotenv.config();
export default defineConfig({
use: {
// 从 process.env 获取变量
baseURL: process.env.BASE_URL,
headless: process.env.HEADLESS_BROWSER === 'true', // 无头模式:process.env.HEADLESS_BROWSER === 'true',
},
projects: [
{
name: 'Chromium', // 名称: 'Chromium', 浏览器名称
use: { browserName: 'chromium' },
},
{
name: 'Firefox', // 名称: 'Firefox', 浏览器名称
use: { browserName: 'firefox' },
},
],
});
或者你也可以直接在测试里用它
import { test } from '@playwright/test';
test('访问基本 URL', async ({ page }) => {
const baseURL = process.env.BASE_URL;
await page.goto(baseURL);
await page.waitForSelector('h1'); // 示例断言,等待 h1 元素出现
});
更高的抽象层次
这个还算简单。我们试着读取一次,并确保可以从任何地方访问。我们的目标是读取一次环境配置,并确保在整个测试过程中都能访问。
让我们从安装验证用的 joi 库开始
npm install joi
运行此命令来安装joi包
让我们创建一个
_config.ts
文件吧。文件名在这里并不重要,随便起个名字就行了。
import * as dotenv from 'dotenv';
import * as path from 'path';
import Joi from 'joi';
// 从 .env 文件中读取环境变量
dotenv.config({ path: path.resolve(__dirname, '.env') });
// 定义配置校验的 Joi 架构
const envSchema = Joi.object({
HEADLESS_BROWSER: Joi.boolean().required(),
BASE_URL: Joi.string().uri().required(),
API_KEY: Joi.string().required(),
}).unknown(true);
const envVars = envSchema.validate(process.env, { allowUnknown: true, abortEarly: false });
if (envVars.error) {
throw new Error(`配置无效: ${envVars.error.message}`);
}
export class Config {
static readonly HEADLESS_BROWSER: boolean = envVars.value.HEADLESS_BROWSER;
static readonly BASE_URL: string = envVars.value.BASE_URL;
static readonly API_KEY: string = envVars.value.API_KEY;
}
最后我们可以在 Playwright 配置里用它
import { defineConfig } from '@playwright/test';
import { Config } from './path-to-config';
export default defineConfig({
use: {
// 使用简化配置
baseURL: Config.BASE_URL,
headless: Config.HEADLESS_BROWSER,
},
projects: [
{
name: 'Chromium',
use: { browserName: 'chromium' },
},
{
name: 'Firefox',
use: { browserName: 'firefox' },
},
],
});
在测试中或在测试里面
import { test } from '@playwright/test';
import { Config } from './path-to-config';
test('访问基础URL并检查API密钥的使用', async ({ page }) => {
// 使用Config中的baseURL和API_KEY
await page.goto(Config.BASE_URL);
// 模拟API密钥使用(例如)
const apiKey = Config.API_KEY;
console.log(`正在使用的API密钥是:${apiKey}`);
// 验证页面标题(例如)
await expect(page).toHaveTitle(/Example/);
});
注意:我也鼓励使用公司的密钥管理解决方案,例如 KeyVault ,在执行测试前安全地访问密钥及配置。
界面模式UI 模式提供了一个强大的界面来浏览、运行和调试测试,其中包含独特的时间旅行功能和监视模式。所有测试文件都会显示在测试侧边栏中,允许你展开每个文件和块,单独运行、查看、观察和调试特定的测试。你可以通过文本、@标签或它们的状态(通过、失败或跳过)来过滤测试,还可以根据你在 playwright.config
文件中定义的项目进行过滤。借助完整的跟踪视图,你可以深入了解测试,逐步浏览每个操作。此外,你还可以在新窗口中打开 DOM 快照,以提升调试体验。
在我之前写的一篇文章中,详细描述过这个功能。尽管它有所改进,基本原则依然保持不变。
要开启此模式,你需要在标准的 Playwright 测试命令后加上 ‘—ui’ 参数
npx playwright test --ui
运行 Playwright 测试并启用用户界面模式
它应该弹出以下窗口。
这种模式是一个极其强大的工具,拥有许多优点,绝对值得一试:
- 交互式测试探索
UI 模式提供了一个直观的界面来探索测试文件及其结构,使理解和管理测试用例变得更加容易。 - 时间旅行调试
体验带有时间旅行功能的逐步地调试,可以重放操作,检查每一步,并精确地识别问题。 - 观察模式
在检测到更改时自动重新运行测试,简化了开发和调试流程。 - 测试筛选
轻松通过文本、标签(@tag
)、状态(已通过、失败、跳过)或playwright.config
文件中配置的项目来筛选测试,悬停查看每个操作,实现有针对性的调试。 - 详细跟踪视图
访问测试运行的完整跟踪,可以悬停查看每个操作,理解发生了什么,并深入了解失败原因。 - DOM 快照
在单独的窗口中弹出 DOM 快照,增强并提供详细的调试体验。 - 轻松测试管理
测试侧边栏会整理所有的测试文件、描述块及单个测试,允许快速和有针对性的运行或调试。 - 跨项目可见性
无缝切换项目或配置,对于涉及多个环境的复杂设置特别有用。 - 增强生产力
通过将可视化反馈与高级筛选和调试工具相结合,UI 模式加速了开发人员和测试人员的工作效率。 - 新手友好型
UI 模式的直观设计使其易于新手使用,同时为经验丰富的测试人员提供了强大的功能。
我鼓励你去试试。
跟踪器默认情况下,playwright.config
文件配置为为每个测试生成一个 trace.zip
文件。跟踪数据仅在测试失败后的第一次重试时记录。此外,重试配置设置为在 CI 运行时为 2,在本地运行时为 0。因此,跟踪数据仅在测试失败后的第一次重试时记录,而不会在初始运行或后续重试中记录。
建议在持续集成(CI)环境中运行跟踪,因为在本地可以利用UI模式进行测试开发和调试。然而,你可以通过手动设置--trace on
标志来启用跟踪,在本地不使用UI模式的情况下运行跟踪。
好的,我们来了——现在我们来谈谈一个专为初学者设计的杀手级功能。我必须承认,我仍然不太喜欢这样的方法,因为有时代码会显得杂乱无章,就像意大利面一样缠在一起。然而,我不会否认在需要调试或懒得手动定位元素时,也有几次我自己也采用了这种方法。但对于初学者来说,这是快速开始Web UI自动化的好方法。
利用Playwright,你可以采取多种方法来录制测试过程。
适用于 Vs Code 的 Playwright 插件请确认您已安装了 “Playwright Test for VS Code” 扩展。
要录制一个测试,请点击测试面板中的“新建测试”按钮。这会生成一个
test-1.spec.ts
文件,并打开浏览器窗口。
访问你想要测试的那个网址后,开始点击以记录操作。
Playwright将开始记录你的操作。例如,你可以点击,这一操作将立即被保存。
import { test, expect } from '@playwright/test';
test('测试用例', async ({ page }) => {
// 点击A/B测试链接
await page.goto('https://the-internet.herokuapp.com/');
await page.getByRole('link', { name: 'A/B测试' }).click();
});
你或许还想说点什么。
你的断言步骤也被保存了
import { test, expect } from '@playwright/test';
test('示例测试', async ({ page }) => {
await page.goto('https://the-internet.herokuapp.com/');
await page.getByRole('link', { name: 'A/B 测试' }).click();
await expect(page.getByRole('heading')).toContainText('A/B 测试变体一');
});
点击“录音”按钮来完成测试录音。
好了。你的测试准备好了,可以开始了。
命令行界面另一种执行录制的方法是运行命令。
npx playwright codegen
运行 playwright 代码生成器
下一步你应该知道……
总之今年的最后一篇文章到这里就结束了!也许你已经熟悉这里讨论的一些功能,或者你在这里发现了新的东西。我的目标是以简洁的方式突出和整理一些最重要的方面。Playwright 有很多精彩的功能等着你去探索,所以我鼓励你深入研究并分享你的发现。如果你觉得我漏掉了什么有趣的东西,随时告诉我!
感谢您花时间读到这里。祝愿您能找到最合适的解决方案。圣诞快乐,新年快乐,祝所有正在阅读这篇文章的朋友们圣诞新年快乐!
共同学习,写下你的评论
评论加载中...
作者其他优质文章