探秘UI自动化测试工具Playwright工作原理

news2024/12/17 10:17:40

相关文章:playwright系列教程

Playwright简介

微软出品的强大工具

Playwright是由微软推出的一款开源自动化测试工具,专门为Web测试和自动化场景而设计。在现代Web开发的快节奏环境下,其凭借出色的性能和丰富的功能,成为众多开发者进行自动化测试的得力助手,无论是前端开发者进行功能验证,还是测试人员构建全面的测试套件,Playwright都能很好地满足其需求。

Playwright的核心优势

跨浏览器支持特性

Playwright支持Chromium、Firefox和WebKit三大主流浏览器,并且为开发者提供了统一的API接口。这意味着无论你是针对Chrome进行测试,还是需要在Firefox或者Safari(基于WebKit)上验证功能,都可以使用相同的代码逻辑。例如,在测试一个电商网站的购物流程时,你可以轻松地在不同浏览器上运行相同的测试脚本,确保网站在各种浏览器环境下都能正常工作,为用户提供一致的体验。这种跨浏览器支持特性极大地提高了测试的效率和覆盖范围,减少了因浏览器差异而导致的兼容性问题。

自动等待与无闪测试机制

Playwright采用了先进的自动等待机制。在执行操作(如点击按钮、输入文本等)前,它会自动检查元素是否已处于可操作状态。例如,当一个页面加载后,某个按钮可能需要一定时间才会完全加载并可被点击,Playwright会等待该按钮具备可点击条件后再执行点击操作,而不是立即尝试点击导致测试失败。这种机制大大减少了测试中的不稳定因素,提高了测试的可靠性。同时,Playwright支持无闪测试,能够避免因页面元素闪烁或未完全加载而引起的误判,进一步提升了测试的准确性和稳定性,确保测试结果真实反映页面的实际状态。

丰富强大的工具链

Playwright配备了一系列丰富且实用的工具。其中,代码生成器可以帮助开发者快速生成测试脚本的基础代码,通过简单地操作页面,它就能自动记录并生成相应的代码片段,大大提高了开发效率。检查器则允许开发者在运行时查看页面元素的属性和状态,方便定位问题和调试测试脚本。追踪查看器能够记录测试过程中的各种事件和操作,为排查问题提供详细的信息。例如,在测试一个复杂的Web应用时,如果遇到某个操作未按预期执行的情况,开发者可以利用追踪查看器回溯整个操作过程,找出问题所在,从而快速修复问题,推动测试工作顺利进行。

多上下文管理能力

在现代Web应用中,常常会涉及多标签、多源甚至多用户的复杂测试场景,Playwright的多上下文管理能力使其能够轻松应对这些情况。例如,在测试一个社交媒体平台时,可能需要同时模拟多个用户在不同标签页中进行操作,如一个用户在一个标签页发布内容,另一个用户在另一个标签页进行评论和点赞。Playwright可以通过创建多个上下文,分别管理不同的页面实例和用户会话,确保各个操作之间相互独立且不受干扰,准确地模拟出真实世界中的复杂用户行为,为全面测试Web应用的功能和性能提供了有力支持。

Playwright的基本概念

Browser(浏览器实例)

Browser是Playwright中的一个重要概念,它代表着一个可以启动新浏览器窗口的实例。通过Browser,我们可以创建多个Page实例,实现多页面的同时操作和管理。例如,在进行一些需要同时打开多个页面并在不同页面间切换操作的测试场景中,首先需要创建Browser实例,然后基于该实例创建相应的Page实例,如下代码所示:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    // 后续可以在这个browser实例上进行更多操作,如创建Page实例
    await browser.close();
})();

这里,chromium.launch()方法创建了一个Chromium浏览器实例,我们可以根据实际测试需求对这个实例进行进一步的配置和操作,如设置浏览器窗口大小、是否为无头模式等,然后在完成所有操作后,使用browser.close()方法关闭浏览器实例,释放资源。

Page(页面实例)

Page代表着打开的一个标签页,是我们进行各种操作的主要对象。我们可以在Page上执行诸如点击按钮、输入文本、获取元素信息等操作。例如,在测试一个登录页面时,我们可以通过Page实例定位到用户名输入框和密码输入框,并输入相应的账号和密码,然后点击登录按钮,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/login');
    await page.fill('input[name="username"]', 'testuser');
    await page.fill('input[name="password"]', 'testpassword');
    await page.click('button[type="submit"]');
    // 可以继续在这个page上进行后续操作,如验证登录是否成功
    await browser.close();
})();

在上述代码中,browser.newPage()创建了一个新的Page实例,然后通过page.goto()方法打开登录页面,接着使用page.fill()方法向用户名和密码输入框中填充数据,最后使用page.click()方法点击登录按钮,模拟了用户的登录操作流程。

ElementHandle(元素句柄)

ElementHandle代表着页面中的一个元素,通过它我们可以对页面元素进行更细致的操作,如获取元素的属性、文本内容,执行元素的特定方法等。例如,在测试一个列表页面时,我们可以通过ElementHandle获取列表项的数量,并检查特定列表项的文本内容是否符合预期,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/list');
    const listItems = await page.$$('li');
    console.log(`列表项数量: ${listItems.length}`);
    const firstItem = listItems[0];
    const textContent = await firstItem.textContent();
    console.log(`第一个列表项内容: ${textContent}`);
    await browser.close();
})();

在这段代码中,page.$$('li')返回了一个包含所有li元素的ElementHandle数组,我们可以通过这个数组获取列表项的数量,并通过firstItem.textContent()获取第一个列表项的文本内容,从而对页面元素进行详细的检查和验证,确保页面的展示和数据符合预期。

Playwright与浏览器的交互方式

通过底层协议通信

Playwright通过与浏览器的底层协议通信来发送命令并接收结果。它利用浏览器提供的调试协议(如Chrome DevTools Protocol),能够深入地控制浏览器的行为和获取详细的页面信息。与一些传统的自动化测试工具相比,这种方式能够实现更精准、高效的控制。例如,在获取页面性能数据时,Playwright可以通过底层协议直接从浏览器获取诸如页面加载时间、资源加载顺序和时间等详细信息,而不仅仅是表面的页面状态。这使得开发者能够更全面地了解页面的性能表现,发现潜在的性能瓶颈,并进行针对性的优化。同时,在执行复杂的操作(如模拟鼠标移动轨迹、处理复杂的JavaScript事件)时,通过底层协议可以确保操作的准确性和稳定性,提高测试的可靠性和真实性。

API的运用

Playwright提供了丰富的API,涵盖了各种常见和复杂的操作场景。例如,在处理弹出窗口时,它提供了专门的API来监听、接受或拒绝弹出窗口,确保测试流程不会因为意外的弹出窗口而中断。当测试一个网站的文件上传功能时,Playwright的文件上传API可以方便地选择本地文件并模拟上传操作,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/upload');
    const [fileChooser] = await page.waitForEvent('filechooser');
    await fileChooser.setFiles('path/to/local/file.jpg');
    // 继续后续的测试操作,如检查文件是否上传成功
    await browser.close();
})();

在上述代码中,page.waitForEvent('filechooser')等待文件选择器弹出事件,然后通过fileChooser.setFiles()方法选择本地文件进行上传,整个过程简洁明了,且能够准确地模拟用户的实际操作,体现了Playwright API的强大和易用性,使得开发者能够轻松应对各种复杂的测试场景,提高测试的效率和质量。

Playwright的元素定位方法

get_by_XXXXX系列定位

Playwright提供了一系列方便的get_by_XXXXX定位方法,例如get_by_roleget_by_textget_by_placeholder等。get_by_role方法根据元素的角色(如按钮、链接、输入框等)进行定位,这对于遵循无障碍设计原则的页面元素定位非常有效。例如,在测试一个具有良好无障碍设计的表单页面时,如果我们要定位提交按钮,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/form');
    const submitButton = await page.get_by_role('button', { name: '提交' });
    // 对提交按钮进行操作,如点击按钮
    await submitButton.click();
    await browser.close();
})();

在上述代码中,page.get_by_role('button', { name: '提交' })通过按钮的角色和名称准确地定位到了提交按钮,这种定位方式不仅简洁,而且具有较高的可读性和可维护性,即使页面结构发生一定变化,只要元素的角色和关键文本信息不变,定位依然有效。

get_by_text方法则根据元素包含的文本内容进行定位,这在定位一些具有特定文本标识的元素时非常实用。例如,在测试一个文章列表页面时,如果要定位特定标题的文章链接,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/articles');
    const articleLink = await page.get_by_text('特定文章标题');
    // 可以对文章链接进行点击等操作,查看文章详情
    await articleLink.click();
    await browser.close();
})();

这里,page.get_by_text('特定文章标题')能够快速准确地定位到包含指定文本的元素,方便进行后续的操作和验证。

get_by_placeholder方法根据输入框的占位符文本进行定位,适用于定位那些用户尚未输入内容时具有提示性占位符文本的输入框。例如,在测试一个注册页面时,如果要定位用户名输入框,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/register');
    const usernameInput = await page.get_by_placeholder('请输入用户名');
    // 对用户名输入框进行操作,如输入用户名
    await usernameInput.fill('testuser');
    await browser.close();
})();

通过page.get_by_placeholder('请输入用户名'),我们可以精准地定位到用户名输入框,进行后续的输入等操作,提高测试脚本的准确性和稳定性。

locator定位

locator定位是Playwright中一种强大且灵活的定位方式,它可以通过元素的id、css选择器、xpath等多种方式进行定位。当页面元素具有唯一的id属性时,使用locator('#elementId')可以快速定位到该元素,这是一种非常高效且准确的定位方法,因为id在页面中通常是唯一的。例如,在测试一个具有特定id的按钮时,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/specialButton');
    const button = await page.locator('#specialButtonId');
    // 对按钮进行操作,如点击按钮
    await button.click();
    await browser.close();
})();

当页面结构较为复杂,需要使用更灵活的定位方式时,css选择器就派上用场了。例如,如果要定位一个属于特定类名且在某个父元素下的子元素,可以使用locator('parentElement.class > childElement.class')这样的css选择器语法进行定位。例如,在测试一个导航菜单时,如果要定位某个下拉菜单中的特定菜单项,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/navigationMenu');
    const menuItem = await page.locator('.nav-menu >.dropdown-menu > li:nth-child(2)');
    // 对菜单项进行操作,如点击菜单项
    await menuItem.click();
    await browser.close();
})();

这里,page.locator('.nav-menu >.dropdown-menu > li:nth-child(2)')通过css选择器准确地定位到了导航菜单中的第二个下拉菜单项,这种定位方式能够适应各种复杂的页面结构,满足不同的测试需求。

xpath定位方式则适用于那些难以用其他简单方式定位的复杂元素,特别是当页面结构不清晰或者元素没有明显的id、类名等属性时。例如,在测试一个XML格式的页面或者具有复杂嵌套结构的HTML页面时,如果要定位一个深层嵌套的元素,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/xmlPage');
    const element = await page.locator('//div[@class="parent"]/div[@class="child"]/span[@id="targetSpan"]');
    // 对定位到的元素进行操作,如获取元素文本
    const text = await element.textContent();
    console.log(text);
    await browser.close();
})();

通过page.locator('//div[@class="parent"]/div[@class="child"]/span[@id="targetSpan"]')这样的xpath表达式,能够精准地定位到目标元素,获取其文本内容或进行其他操作,为处理复杂页面结构提供了有力的支持。

其他定位辅助方法

除了上述主要的定位方法外,Playwright还提供了一些辅助定位方法,如nth()firstlastfilter()以及链式选择器等,这些方法可以在特定需求下进一步筛选、定位元素。例如,当一个页面上有多个相同类型的元素,而我们只需要定位其中的第二个元素时,可以使用nth(1)方法(索引从0开始),代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/multipleElements');
    const secondElement = await page.locator('li').nth(1);
    // 对第二个元素进行操作,如检查其文本内容
    const text = await secondElement.textContent();
    console.log(text);
    await browser.close();
})();

firstlast方法则分别用于定位一组元素中的第一个和最后一个元素,非常方便快捷。例如,在测试一个列表页面时,如果要验证最后一个列表项的内容是否符合预期,可以使用last方法,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/list');
    const lastListItem = await page.locator('li').last();
    const text = await lastListItem.textContent();
    console.log(text);
    await browser.close();
})();

filter()方法可以根据特定的条件对一组元素进行筛选定位。例如,如果一个页面上有多个按钮,我们只需要定位那些具有特定属性值的按钮,可以使用filter()方法,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/buttons');
    const specificButtons = await page.locator('button').filter({ hasText: '特定文本' });
    // 对筛选出的按钮进行操作,如点击按钮
    await specificButtons.click();
    await browser.close();
})();

链式选择器则允许我们将多个定位操作连接起来,逐步缩小定位范围,提高定位的准确性。例如,在测试一个具有复杂结构的表格时,如果要定位某个单元格,可以先定位到表格,再定位到行,最后定位到列,代码如下:

const { chromium } = require('playwright');
(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com/table');
    const cell = await page.locator('table').locator('tr:nth-child(2)').locator('td:nth-child(3)');
    // 对定位到的单元格进行操作,如获取单元格文本
    const text = await cell.textContent();
    console.log(text);
    await browser.close();
})();

通过这些辅助定位方法的灵活运用,我们可以在各种复杂的页面场景中准确地定位到所需的元素,进行有效的测试操作和验证。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1216作业

思维导图 作业 使用无名信号量实现输出春夏秋冬 #include <myhead.h> sem_t sem1,sem2,sem3,sem4; void *fun1() {while(1){sem_wait(&sem1);sleep(1);printf("春\n");sem_post(&sem2);} }void *fun2() {while(1){sem_wait(&sem2);sleep(1);prin…

学习maven(maven 项目模块化,继承,聚合)

前言 本篇博客的核心&#xff1a;理解maven 项目模块化&#xff0c;继承&#xff0c;聚合 的含义 maven 项目模块化 含义 maven项目模块化&#xff1a;使用maven 构建项目&#xff0c;管理项目的方式&#xff0c;我们可以将maven项目根据内在的关系拆分成很多个小项目【模块】…

【Linux】自定义项目-进度条

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 准备工作&#xff1a;"\r"与"\n"字符 ①&#xff1a;基本含义 在C语言和Linux环境中&#xff0c;\r是回车符&#xff0c;\n是换行符&#xff0c;用于控制文本格式和输出…

OpenLinkSaas 2025年1月开发计划

先来看看OpenLinkSaas的大目标 在OpenLinkSaas的产品目标中&#xff0c;让开发人员更加方便的使用云资源是目标之一。通过各大云厂商的API&#xff0c;来可视化云上基础设施的数据是远远不够的。我们准备在2025年1月份增加方便管理和运营研发场景下服务器的能力。 这部分的功能…

电工电子技术实验:电压比较器及其应用电路

实验目的 1&#xff0e;了解电压比较器与运算放大器的性能区别&#xff1b; 2&#xff0e;掌握电压比较器的结构及特点&#xff1b; 3&#xff0e;掌握电压比较器电压传输特性的测试方法&#xff1b; 4&#xff0e;学习比较器在电路设计中的应用 实验原理 电压比较器是一…

代理 IP 行业现状与未来趋势分析

随着互联网的飞速发展&#xff0c;代理 IP 行业在近年来逐渐兴起并成为网络技术领域中一个备受关注的细分行业。它在数据采集、网络营销、隐私保护等多个方面发挥着重要作用&#xff0c;其行业现状与未来发展趋势值得深入探讨。 目前&#xff0c;代理 IP 行业呈现出以下几个显著…

旅游系统旅游小程序PHP+Uniapp

旅游门票预订系统&#xff0c;支持景点门票、导游产品便捷预订、美食打卡、景点分享、旅游笔记分享等综合系统 更新日志 V1.3.0 1、修复富文本标签 2、新增景点入驻【高级版本】3、新增门票核销【高级版】4、新增门票端口【高级版】

【日常笔记】Spring boot:编写 Content type = ‘text/plain‘ 接口

一、项目场景&#xff1a; 接口&#xff1a;Context-Type&#xff1a;text/plain 方式&#xff1a;POST 项目场景&#xff1a;硬件回调接口 二、实战 PostMapping(value "/xx/xxx", consumes "text/plain" ) 2.1、接口 /*** return String* time 202…

STM32F407+LAN8720A +LWIP +FreeRTOS UDP通讯

STM32F407+LAN8720A +LWIP +FreeRTOS ping通 上一篇实现了LWIP ping 通 本篇实现UDP通讯 实现如下功能: 串口1空闲中断+DMA接收,收到数据用UDP发送UDP接收,收到数据用串口1发送STM32CUBEIDE配置和代码 1. 配置UARAT1的空闲中断+DMA接收 UART1接收到数据,释放信号量,在任…

KeyFormer:使用注意力分数压缩KV缓存

Keyformer: KV Cache Reduction through Key Tokens Selection for Efficient Generative Inference 202403&#xff0c;发表在Mlsys Introduction 优化KV cache的策略&#xff0c;主要是集中在系统级别的优化上&#xff0c;比如FlashAttention、PagedAttention&#xff0c;它…

3.9 网际控制报文协议ICMP

欢迎大家订阅【计算机网络】学习专栏&#xff0c;开启你的计算机网络学习之旅&#xff01; 文章目录 前言1 ICMP报文的封装2 ICMP差错报告报文的类型3 不应发送ICMP差错报告报文的情况4 常用的ICMP询问报文类型5 ICMP的应用 前言 网际控制报文协议&#xff08;ICMP&#xff09…

东北大学《2024年839自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《东北大学839自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2024年真题 Part1&#xff1a;2024年完整版真题 2024年真题

百度智能云千帆AppBuilder升级,百度AI搜索组件上线,RAG支持无限容量向量存储!

百度智能云千帆 AppBuilder 发版升级&#xff01; 进一步降低开发门槛&#xff0c;落地大模型到应用的最后一公里。在千帆 AppBuilder 最新升级的 V1.1版本中&#xff0c;企业级 RAG 和 Agent 能力再度提升&#xff0c;同时组件生态与应用集成分发更加优化。 • 企业级 RAG&am…

就业相关(硕士)

一、嵌入式 1.机器人行业 1.1 大致情况 要做机器人行业&#xff0c;主要技术栈是运动控制、深度学习、强化学习、具身智能等&#xff0c;主要求职方向有运动控制算法工程师和机器人算法工程师等等。大致薪资在30w到50w不等&#xff0c;主要看方向&#xff08;双211&#xff…

Selenium操作指南

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 大家好&#xff0c;今天带大家一起系统的学习下模拟浏览器运行库Selenium&#xff0c;它是一个用于Web自动化测试及爬虫应用的重要工具。 Selenium测试直接运行在…

OpenCV相机标定与3D重建(11)用于在图像上绘制世界坐标系的三条轴函数drawFrameAxes()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 从姿态估计绘制世界/物体坐标系的轴。 cv::drawFrameAxes 是 OpenCV 库中的一个函数&#xff0c;用于在图像上绘制世界坐标系的三条轴&#xff0…

spring学习(XML中定义与配置bean(超详细)。IoC与DI入门spring案例)

目录 一、配置文件(XML)中定义与配置bean。 &#xff08;1&#xff09;bean的基础配置。&#xff08;id、class&#xff09; &#xff08;2&#xff09;bean的别名配置。 1、基本介绍。 2、demo测试。 3、NoSuchBeanDefinitionException&#xff01; &#xff08;3&#xff09;…

Docker容器编排与Docker Compose

1. Docker Compose介绍与基础概念 Docker Compose是一个用于定义和运行多容器Docker应用的工具。通过Compose&#xff0c;用户可以用YAML文件来定义多个容器的服务、网络、存储等配置&#xff0c;并通过一个命令来启动、停止和管理这些容器。它简化了多容器应用的管理&#xf…

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现 最后设置首页的推荐模块&#xff0c;参考模板如下图所示。 一、首页热门推荐模块的实现 对于热门推荐模块&#xff0c;先有上面的小标题栏&#xff0c;这里的标题栏也有一个小图标&#xff0c;首先从“百度图库”中…

MySQL八股-MVCC入门

文章目录 当前读&#xff08;加锁&#xff09;快照读&#xff08;不加锁&#xff09;MVCC隐藏字段undo-log版本链A. 第一步B.第二步C. 第三步 readview MVCC原理分析RCA. 先来看第一次快照读具体的读取过程&#xff1a;B. 再来看第二次快照读具体的读取过程: RR隔离级别 当前读…