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在页面有弹出框时,如果发现没有任何注册的处理函数,会自动点击取消

相关推荐
feasibility.2 天前
playwright爬虫采集京东商品主页数据(含xpath定位示例)
爬虫·playwright
喵手9 天前
Python爬虫零基础入门【第九章:实战项目教学·第11节】Playwright 入门实战:渲染后 HTML + 截图定位问题!
爬虫·python·爬虫实战·playwright·python爬虫工程化实战·零基础python爬虫教学·渲染html
喵手12 天前
Python爬虫零基础入门【第七章:动态页面入门(Playwright)·第3节】优先 API:用 Network 找接口,回到 Requests(更稳定)!
爬虫·python·playwright·python爬虫实战·python爬虫工程化实战·python爬虫零基础入门·优先 api
Dxy123931021612 天前
Python使用Playwright入门教程:从环境搭建到实战应用
开发语言·python·playwright
喵手12 天前
Python爬虫零基础入门【第七章:动态页面入门(Playwright)·第1节】Playwright 第一次:打开页面、等待元素、拿到渲染后 HTML!
爬虫·python·爬虫实战·动态页面·playwright·python爬虫工程化实战·零基础python爬虫教学
喵手12 天前
Python爬虫零基础入门【第七章:动态页面入门(Playwright)·第2节】动态列表:滚动加载/点击翻页(通用套路)!
爬虫·python·爬虫实战·playwright·python爬虫工程化实战·零基础python爬虫教学·动态列表
鄭郑13 天前
【Playwright 学习笔记 03】CSS选择器 定位方法
css·笔记·学习·playwright
大飞记Python14 天前
代码级教程|用Playwright实现Web自动化测试:从零到录制生成脚本
自动化测试·python·selenium·playwright
问道飞鱼15 天前
【自动化测试】pytest 语法与核心概念
自动化测试·pytest·playwright