playwright介绍

任何浏览器·任何平台·一套 API

  • 跨浏览器: Playwright支持所有现代洁染引擎,包括Chromium、WebKit和Firefox。
  • 跨平台:在Windows、Linux和macOS上测试,本地或CI上测试, headless 或 headed。
  • 跨语言: 在TypeScript、JavaScript、Python、.NET和Java中使用PlaywrightAPI.
  • 测试Mobile Web:为移动端chrome和Safari提供原生移动模拟的。相同的染引警工作在你的桌面和云。

flexible

  • 自动等待:plawright在执行动作之前等待元素可操作。它还有一系列丰富的自省事件(inrospection events),两者的结合消除了人工超时的需要.
  • Web优先断言: Paywright断言是专门为动态web创建的。检查将自动重试,直到满足必更乐件,追踪: 配置测过量试策略,抓获执行过程追踪、视频和截图以所除碎片。

无限制

浏览器在不同的进程中运行输入不同来源的web内容。playwright与现代浏览器架构保持一致,并在进程外运行测试。这使得它可以在任何浏览器中运行,而不会受到浏览器安全限制。

  • 跨多个选项卡、多个来源和多个用户的测试场景。为不同用户创建具有不同上下文的场景,并在一个测试中对服务器运行他们。
  • 可信事件: 悬停元素与动态控件交互,生成可信事件,Playwright使用与真实用户无法区分的真实浏览器输入管道。
  • 测试表单: 穿透DOM的阴影。Playwright选择器穿透阴影DOM并允许无缝输入表单。

完全隔离·快速执行

  • 浏览器上下文:playwright为每个测试创建浏览器上下文,浏览器上下文相当于一个全新的浏览器配置文件。这提供了零开销的完全测试隔高,创建新的浏览器上下文只需要几毫秒。
  • 登录一次:保存上下文的身份验证状态,并在所有测过中重用它。这绕过了每个测试中的重复登录操作,但提供了独立测试的完全隔离.

强大的工具

  • 代码生成器(Codegen)。通过您的操作生成测试,将它们保存为任何语言。
  • Playwright检查(inspector):检查页面,生成选择器,逐步执行测试,查看单击点,刘览执行日志。
  • 跟踪查看器(Trace Viewer):捕获所有信息以调查测试失败,Playwright跟踪包含测试执行屏幕广播、实时DOM快照、动作资源管理路、测试源等等。

Playwright vs Selenium vs Puppeteer vs Cypress

支持语言

  • Playwright: JavaScript, Python, C#, Java
  • Selenium: JavaScript, Python, C#, Java, Ruby, Perl, PHP, Objective-C, Swift, R, Groovy, Scala,
  • Puppeteer: JavaScript
  • Cypress: JavaScript

支持浏览器

  • Playwright: Chromium, Firefox, WebKit
  • Selenium: Chromium, Firefox, WebKit, IE, Edge, Safari
  • Cypress: Chromium, Firefox
  • Puppeteer: Chromium, Firefox

支持多标签 + 表单

  • Playwright: 支持,通过上下文支持
  • Selenium: 支持,通过switch_to切换,但不好用
  • Cypress: 不支持
  • Puppeteer: 支持

测试创建速度

  • Playwright: 基于playwright codegen命令录制脚本
  • Selenium: 基于Selenium IDE录制脚本
  • Cypress: 基于Cypress Recorder录制脚本
  • Puppeteer: 基于Puppeteer Recorder录制脚本

稳定性

主要评估用例编写之后的失败率,不包括真正的发现bug之后的失败

  • Playwright: 最好等待某些元素,但必须手工等待其他元素
  • Selenium:复杂的自动等待机制
  • Cypress: 复杂的机制,并且不能与框架一起工作
  • Puppeteer: 等待某些元素,但必须手工等待其他元素

智能定位

  • Playwright: 支持自定义选择器引擎
  • Selenium: 不支持以多种方式选择元素
  • Cypress: 不支持以多种方式选择元素
  • Puppeteer: 不支持以多种方式选择元素

playwright定位器

playwright提供locator()来实现元素的定位

选择器类型

  • id
  • text
  • css
  • xpath

示例

  • locator('text=foo'):选择文本为foo的元素
  • locator('css=div'):选择第一个div元素
  • locator("[data-test=login-button]"):选择data-test属性值为login-button的元素
  • locator("xpath=//*[@id='kw']"): 选择id为kw的元素

常用API

启动浏览器

1
2
3
browser = await playwright.chromium.launch(headless=False)
browser = await playwright.firefox.launch(headless=False)
browser = await playwright.webkit.launch(headless=False)

创建上下文 & 打开页面

1
2
3
// 通过context可以实现多标签
context = await browser.newContext()
page = await context.newPage()

执行js

1
await page.evaluate('alert("hello world")')

表单

1
username = page.frame_locator('.frame-class').locator('#username')

输入

1
2
3
4
5
await username.fill('admin')
page.locator('#agree').check()
page.locator('#name').press('Enter')
// 点击dialog
page.on('dialog', lambda dialog: dialog.accept())

playwright断言

断言一般是单元测试框架所提供的概念,一般包括assertEqualassertNotEqualassertTrueassertFalseassertInassertNotIn等等,playwright提供了expect来实现断言。这些断言将等待并重试,直到断言成功或超时。

1
2
page.locator('#submit-button').click()
expect(page.locator('#message')).toHaveText('Thank you')

page object模式(一种设计模式)

什么是page object模式

page object模式是一种设计模式,它将页面的每个页面封装为一个类,每个类都有自己的方法,这些方法用于与页面进行交互。这种模式的好处是,如果页面发生变化,我们只需要更新页面对象类,而不需要更新测试用例。也就是将定位元素的过程与操作元素的过程分离开来,这样当页面发生变化时,只需要修改page object类即可,而不需要修改测试用例。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// page
import { expect, type Locator, type Page } from '@playwright/test';

export class PlaywrightDevPage {
readonly page: Page;
readonly getStartedLink: Locator;
readonly gettingStartedHeader: Locator;
readonly pomLink: Locator;
readonly tocList: Locator;

constructor(page: Page) {
this.page = page;
this.getStartedLink = page.locator('a', { hasText: 'Get started' });
this.gettingStartedHeader = page.locator('h1', { hasText: 'Installation' });
this.pomLink = page.locator('li', { hasText: 'Guides' }).locator('a', { hasText: 'Page Object Model' });
this.tocList = page.locator('article div.markdown ul > li > a');
}

async goto() {
await this.page.goto('https://playwright.dev');
}

async getStarted() {
await this.getStartedLink.first().click();
await expect(this.gettingStartedHeader).toBeVisible();
}

async pageObjectModel() {
await this.getStarted();
await this.pomLink.click();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// test
import { test, expect } from '@playwright/test';
import { PlaywrightDevPage } from './playwright-dev-page';

test('getting started should contain table of contents', async ({ page }) => {
const playwrightDev = new PlaywrightDevPage(page);
await playwrightDev.goto();
await playwrightDev.getStarted();
await expect(playwrightDev.tocList).toHaveText([
`How to install Playwright`,
`What's Installed`,
`How to run the example test`,
`How to open the HTML test report`,
`Write tests using web first assertions, page fixtures and locators`,
`Run single test, multiple tests, headed mode`,
`Generate tests with Codegen`,
`See a trace of your tests`
]);
});

test('should show Page Object Model article', async ({ page }) => {
const playwrightDev = new PlaywrightDevPage(page);
await playwrightDev.goto();
await playwrightDev.pageObjectModel();
await expect(page.locator('article')).toContainText('Page Object Model is a common pattern');
});