Playwright

Playwright

1. 框架介绍

Playwright Test 是一个适用于现代 Web 应用的端到端测试框架。它打包了测试运行器、断言、隔离、并行化和丰富的工具。

2. 安装playwright

cmd 复制代码
npm init playwright@latest

3. 运行示例测试

安装浏览器(不用电脑上的浏览器)

复制代码
npx playwright install

也可以只下载一个浏览器

cmd 复制代码
npx playwright install chromium # Expecting one of: chromium, chromium-headless-shell, chromium-tip-of-tree-headless-shell, chrome, chrome-beta, msedge, msedge-beta, msedge-dev, bidi-chromium, firefox, webkit, webkit-wsl

运行测试

cmd 复制代码
npx playwright test

运行项目中的命令,可以自动安装浏览器

4. 页面等待

tsx 复制代码
test("页面等待测试", async ({ page }) => {
  await page.goto("https://www.baidu.com/");

  await page.waitForTimeout(5000);

  await expect(page).toHaveTitle(/百度一下/);
});

5. 自动化代码助手

cmd 复制代码
npx playwright codegen

代码助手可以完成一些功能(人对页面的输入操作),但是对于一些断言什么需要自己写

代码助手产生代码时,能使用role定位的,会优先使用后role定位

6. 跟踪功能

playwright有个特色功能: 跟踪

启用跟踪功能后,可以在执行自动化后,通过记录的跟踪数据文件,回看自动化过程中的每个细节。

tsx 复制代码
export default defineConfig({
  use: {
    // 策略选项:
    // - "on" → 始终生成
    // - "off" → 禁用
    // - "on-first-retry" → 首次重试失败时生成(默认)
    // - "retain-on-failure" → 失败时保留(即使后续重试成功)
    trace: "on-first-retry", // 推荐生产环境配置
  },
});

执行完毕后,我们可以看到trace.zip文件

怎么查看这个跟踪文件呢?

  1. 直接访问https://trace.playwright.dev/网站,上传跟踪文件

  2. 执行命令

    cmd 复制代码
    npx playwright show-trace test-results/example--chromium/trace.zip

7. css定位

7.1 验证css选择器

7.2 元素匹配

  1. 如果一个locator匹配多个元素,要获取所有元素的locator对象,如下:

    tsx 复制代码
    test("匹配多个元素", async ({ page }) => {
      await page.goto("https://www.baidu.com/");
    
      const lcs = await page.locator("div").all();
      console.log(lcs);
    
      console.log("--------------------------------------");
    
      const fist = await page.locator("div").first();
      console.log(await fist.innerHTML());
    
      console.log("--------------------------------------");
    
      const last = await page.locator("div").last();
      console.log(await last.innerHTML());
    
      console.log("--------------------------------------");
    
      const nth = await page.locator("div").nth(1);
      console.log(await nth.innerHTML());
    
      await expect(page).toHaveTitle(/百度一下/);
    });

如果只需要数量的话,我们可以使用

tsx 复制代码
 const lcs = await page.locator("div").count();

如果我们只需要第一个或者最后一个元素,可以使用

tsx 复制代码
const first = await page.locator("div").first();
const last = await page.locator("div").last();
  1. 选择直接子元素和后代元素

直接子元素

tsx 复制代码
 const span = await page.locator("div>span").first();

后代元素

tsx 复制代码
const span = await page.locator("div span").first();
  1. 属性选择器

    tsx 复制代码
    const a = await page.locator('[href="http://news.baidu.com"]');

如果属性包含某个字符串的元素

tsx 复制代码
const a1 = await page.locator('[href*="http"]').first();

属性值以http开头的

ts 复制代码
const a2 = await page.locator('[href^="http"]').first();

以什么结尾

tsx 复制代码
const a3 = await page.locator('[href$="top"]').first();
  1. 联合使用

    ts 复制代码
    const a4 = await page
        .locator('div#head a[href="http://news.baidu.com"]')
        .first();

    如果是或的关系,用,隔开

  2. 按次序选择子结点

tsx 复制代码
const a5 = await page.locator("div#s-top-left a:nth-child(2)").first();

奇数结点

tsx 复制代码
  const even = await page.locator("a:nth-child(even)").first();
  1. 兄弟结点

    相邻兄弟结点的选择

    h3 + sapn

    后续所有兄弟结点的选择

    h3 ~ span

8. xptah选择

playwright推荐的是xpath定位,它推荐从用户角度视觉呈现的定位。

因为它觉得用户的角度相对固定,不容易便,而html页面写法容易变化

8.1 根据文本内容定位

tsx 复制代码
 const element1 = await page.getByText("百度一下").first();

8.2 根据role进行定位

  1. 根据元素的角色定位
tsx 复制代码
 const element2 = await page.getByRole("alert");

html元素中,有些特定语义元素被API规范认为自身就包含ARIA role信息,并不需要我们明显的加上ARIA role属性设置。

比如

progress,role为progressbar

再比如type为search的input,role就为searchbox

通常使用代码助手产生的,大家知道意思就行。

  1. ARIA规范除了可以给元素添加ARIA role ,还可以添加其他ARIA属性(如果你根据role,不足以去定位的话,可以添加其他属性),比如
html 复制代码
<div role="heading" aria-level="1">1</div>
<div role="heading" aria-level="2">2</div>

playwright对常见的ARIA属性,有额外的参数对应,比如 aria-checked/aria-disabled/aria-level等等

比如,上述元素中怎么定位

tsx 复制代码
const element3 = await page.getByRole("heading", {
    level: 2
});
  1. 根据name定位

往往根据role和ARIA role属性,往往不能唯一定位元素

role定位最常见的组合是ARIA role和Accessible Name

因为,Accessible Name就像元素的名字一样,往往可以唯一定位

html 复制代码
<a name="xinwen" href="http://news.baidu.com">新闻</a>

定位:

ts 复制代码
const element4 = await page.getByRole("link", {
    name: 'xinwen',
});

9. 缺省等待时间

Playwright中,当我们定位元素(比如,通过locator/get_by_text等方法)后,对元素进行操作(比如click,fill)

如果根据定位条件,找不到这个元素,playwright并不会立即抛出错误,而是缺省等待元素时间为30秒,如果30秒内元素出现了,就立即操作返回成功。

就比如我们点击save时候,根据后台的接口,成功后弹出提示信息。我们定位到这个提示信息后,操作返回成功,但是这个提示信息不是立即点击save后就出现了,是根据后台接口的返回,playwright等待30s

tsx 复制代码
test("缺省等待时间", async ({ page, context }) => {
  await page.goto("https://www.baidu.com/");

  context.setDefaultTimeout(60000);

  const element1 = await page.getByTitle("xxx");
  console.log(await element1.innerHTML());

  await expect(page).toHaveTitle(/百度一下/);
});

10. 元素通用操作

ts 复制代码
test("元素通用操作", async ({ page }) => {
  await page.goto("https://www.baidu.com/");

  await page.getByRole("textbox").click();
  await page.getByRole("textbox").fill("你好");
  console.log(
    await page.getByRole("button", { name: "百度一下" }).getAttribute("id")
  );
  console.log(await page.getByRole("button", { name: "百度一下" }).innerHTML());
  await page.getByRole("button", { name: "百度一下" }).click();

  await page.getByRole("button", { name: "百度一下" }).dblclick(); // 双击
  await page.getByRole("button", { name: "百度一下" }).hover(); // 悬停

  await expect(page).toHaveTitle(/百度一下/);
});

10.1 等待元素可见

前面说过,playwright通过locator对元素进行操作时,缺省就会等待30秒。

但是,有时我们的代码并不是要操作这个元素,而是要等待这个元素出现后,进行别的操作

这时,可以使用Locator对象的waitFor方法

ts 复制代码
await page.getByRole("button", { name: "百度一下" }).waitFor({
    timeout: 500000
});

10.2 判断元素是否可见

ts 复制代码
await page.getByRole("button", { name: "百度一下" }).isVisible();

10.3 文本框

文本框输入

单行文本框input或者多行文本框textarea都可以使用Locator的fill方法进行输入

文本框清空

单行文本框input或者多行文本框textarea都可以使用Locator的clear方法进行清除

获取输入框的内容

通过inputValue方法

文件输入框

ts 复制代码
const lc = await page.locator('input[type="file"]');
await lc.setInputFiles(["d:/1.png"]);

10.4 radio单选/checkbox多选

常见的选择框包括: radio框、checkbox框、select框

如果要点选radio框,可以使用Locator的check方法

如果要取消选择radio框,可以使用Locator对象的uncheck方法

如果我们要判断radio框是否选中,可以使用Locator对象的isChecked方法

checkbox和radio一样

10.5 select元素

要选择选项,可以使用select 元素对应的Locator对象的select_option方法

可以根据索引,或者通过value去选择

11. 网页Page操作

打开网址/刷新/后退,可以分别调用对象的goto/reload/go_back/go_forward方法

获取网页html,可以调用对象的content方法

获取网页的title,可以调用页面的title

设置网页宽度,高度的大小: setViewportSize

ts 复制代码
test("网页Page操作", async ({ page }) => {
  await page.goto("https://www.baidu.com/");

  console.log(await page.context());

  console.log(await page.title());

  await page.setViewportSize({ width: 1920, height: 1280 });
});

12. frame切换

页面嵌入一个iframe的时候,你要获取里面iframe的元素,

要使用Page或者Locator对象的frame_locator方法定位到你要操作的frame

这个方法会产生一个FrameLocator对象,后续的定位,就使用这个对象,在其内部进行定位。

13. 窗口切换

在网页上操作的时候,我们经常遇到过,点击一个链接或按钮,就会打开一个新窗口

ts 复制代码
test("窗口切换", async ({ page, context }) => {
  //...
  const new_page = await context.pages[0];
});

14. 冻结页面

在开发者工具栏console里面执行如下js代码:

ts 复制代码
setTimeout(() => { debugger }, 5000)

15. 截屏

tsx 复制代码
test("截屏", async ({ page }) => {
  await page.goto("https://www.baidu.com/");

  await page.screenshot({
    path: "s1.png",
  });

  // 截屏完整页面,页面内容超过窗口高度时,包括不可见部分
  await page.screenshot({
    path: "s1.png",
    fullPage: true,
  });

  // 也可以对某个元素的显示内容进行截屏
  await page.locator("div").first().screenshot({
    path: "s2.png",
  });
});

16. 弹出框

alert、confirm、prompt

ts 复制代码
test("弹出框", async ({ page }) => {
  await page.goto("https://www.baidu.com/");

  function handleDiglof(dialog) {
    page.waitForTimeout(1000);

    dialog.appect();
    console.log(dialog.message);
  }

  page.on("dialog", handleDiglof);

  page.locator("#alert-button").click();
});

dismiss相当于点击了取消按钮

注册的处理函数中一定要调用accept或者dismiss方法,让对话框消失

否则当对话框弹出时,后续任何代码都不会执行,并且会有超时错误。

Playwright在页面有弹出框时,如果发现没有任何注册的处理函数,会自动点击取消

16. 弹出框

alert、confirm、prompt

ts 复制代码
test("弹出框", async ({ page }) => {
  await page.goto("https://www.baidu.com/");

  function handleDiglof(dialog) {
    page.waitForTimeout(1000);

    dialog.appect();
    console.log(dialog.message);
  }

  page.on("dialog", handleDiglof);

  page.locator("#alert-button").click();
});

dismiss相当于点击了取消按钮

注册的处理函数中一定要调用accept或者dismiss方法,让对话框消失

否则当对话框弹出时,后续任何代码都不会执行,并且会有超时错误。

Playwright在页面有弹出框时,如果发现没有任何注册的处理函数,会自动点击取消

相关推荐
今晚务必早点睡2 天前
Playwright 实战全解析:使用方法、典型场景及与 Selenium 的全面对比
selenium·测试工具·playwright
霍格沃兹测试开发学社测试人社区2 天前
Playwright数据驱动测试:从Excel与JSON获取测试数据指南
excel·playwright
杰瑞不懂代码5 天前
playwright 基础入门教程,更便捷的数据获取
python·网络爬虫·playwright·自动化处理
测试一路到黑6 天前
端到端测试自动化流水线:Playwright + GitHub Actions + Allure Reports 完整实践
软件测试·功能测试·测试开发·playwright·ai测试
Benny的老巢7 天前
基于Playwright TypeScript/JavaScript的API调用爬虫成熟方案
javascript·爬虫·typescript·自动化·agent·playwright
霍格沃兹软件测试开发7 天前
Playwright API 测试:网络请求拦截与模拟的方法
自动化·playwright
霍格沃兹测试开发学社测试人社区7 天前
Playwright测试策略:顺序、并行及分布式执行方案
分布式·自动化·playwright
sandwu12 天前
AI自动化测试(二)—— Playwright-MCP搭建自动化UI测试(browser-use&midscene对比)
人工智能·ui·自动化·playwright
sandwu17 天前
AI自动化测试(一)
人工智能·agent·playwright·ai自动化测试·midscene