Article directory
- write in front
- 1. Introduction to Playwright
- 2. Start
- 3. Run the test
- 4. Debug debugging
- 5. Script recording Test generator
- 6. Trace viewer Trace viewer
- 7. pytest plug-in support
-
- 7.1 Use
- 7.2 CLI arguments
- 7.3 Fixture
- 7.4 Parallel testing
- 7.5 Example
-
- 7.5.1 Configuring slow mode
- 7.5.2 Skip X Browser Test
- 7.5.3 Specify the browser where the test case runs
- 7.5.4 Specify the browser channel for test case execution
- 7.5.5 Configure base-url/host
- 7.5.6 Ignore HTTPS errors
- 7.5.7 Custom window size
- 7.5.8 Device Simulation
- 7.5.9 Persistent context
- 7.5.10 Compatible with unittest.TestCase
- 7.5.11 Use with pdb
write in front
1. Introduction to Playwright
1.1 Brief introduction
Playwright is an automated testing tool launched by Microsoft that was created specifically to meet end-to-end testing needs. Playwright supports all modern rendering engines, including Chromium, WebKit and Firefox. You can perform local or continuous integration testing on Windows, Linux and macOS, headless or headed, and you can also use Google Chrome to perform local simulation testing on Android and Mobile Safari.
Three automated testing (or crawler) libraries commonly used today:
Library | Selenium | Puppeteer | Playwright |
---|---|---|---|
JavaScript support | Official support | Official support | Official support |
Python asynchronous support | none | Third party, and has a lot of bugs | Official support |
Python synchronization support | Official support | none | Official support |
maintainer | Community | Microsoft | |
Operational browser | Chrome/Firefox/Safari/Edge | Chrome/Firefox | Chrome/Firefox/Safari/Edge |
Simulation operation richness | generally | Excellent | very good |
Cookie support | generally | generally | API is very friendly |
Agent switching support | generally | generally | Excellent |
1.2 Supported platforms
Linux | macOS | Windows | |
---|---|---|---|
Chromium 89.0.4344.0 | support | support | support |
WebKit 14.1 | support | support | support |
Firefox 84.0b9 | support | support | support |
1.3 Supported languages
JavaScript and TypeScript: https://github.com/microsoft/playwright
Java: https://github.com/microsoft/playwright-java
Python: https://github.com/microsoft/playwright-python
C#: https://github.com/microsoft/playwright-sharp
1.4 Official documentation (python)
Documentation: https://playwright.dev/python/docs/intro
API: https://playwright.dev/python/docs/api/class-playwright
2. Start
2.1 Installation requirements
- Python 3.8 or higher.
- Windows 10+, Windows Server 2016+ or Windows Subsystem for Linux (WSL).
- MacOS 12 Monterey or MacOS 13 Ventura.
- Debian 11, Debian 12, Ubuntu 20.04 or Ubuntu 22.04.
2.2 Installation
Install playwright and browser binaries for Chromium, Firefox and WebKit
- pip installation
pip install playwright # 安装playwright
playwright install # 安装浏览器驱动
- conda installation
conda install playwright # 安装playwright
playwright install # 安装浏览器驱动
2.3 Code examples
Currently installed version:
python=3.9.5
playwright=1.37.0
# -*- coding: utf-8 -*-
# @Time : 2023/9/1 10:52
# @Author : chenyinhua
# @File : test_demo.py
# @Software: PyCharm
# @Desc:
import re
from playwright.sync_api import sync_playwright, expect
# 同步API (初学者建议先使用同步API)
with sync_playwright() as playwright:
"""
在使用 with sync_playwright() as playwright: 时,Playwright 会创建一个 Playwright 实例,并将其作为 playwright 变量绑定到 with 代码块中。
在代码块结束时,会自动调用 playwright.close() 方法来关闭所有已创建的页面和浏览器实例。
这样可以确保资源的正常释放和关闭,避免资源泄漏和浪费。因此,使用 with sync_playwright() as playwright: 是一个推荐的方式来管理 Playwright 的实例。
"""
# 默认是无头模式
# browser = playwright.chromium.launch()
# 使用有头模式
browser = playwright.chromium.launch(headless=False, channel="chrome")
"""
通过调用 browser.new_context() 方法,我们可以在当前浏览器实例中创建一个新的上下文。
这个新的上下文将与原始上下文相互隔离,它们不会共享 cookies、缓存等数据。
您可以在同一个浏览器实例中创建多个上下文,每个上下文可以具有自己的页面和状态。
可以理解为浏览器的无痕模式
"""
context = browser.new_context()
"""
一般来说,一个page对应一个浏览器选项卡。而Page对象的作用在于和页面的内容进行交互,以及导航和加载新的页面。
在上下文中创建一个新的页面时,该页面会继承上下文的各种属性和设置,例如 cookies、请求拦截器、代理等。
此外,在同一上下文中创建的页面之间共享网络连接,因此加载速度更快。
"""
page = context.new_page()
# 访问地址
page.goto("https://www.gitlink.org.cn/")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("GitLink"))
# 点击按钮,会新开窗口打开页面
page.locator("//a[text()='开源项目']").click()
# 此处需要更新页面的值
page = page.wait_for_event("popup")
# 断言网页标题=开源项目
expect(page).to_have_title(re.compile("开源项目"))
2.4 Assertions
Playwright provides the expect function, which waits until an expected condition is met.
import re
from playwright.sync_api import expect
expect(page).to_have_title(re.compile("GitLink"))
官方详细说明:https://playwright.dev/python/docs/test-assertions
后续会详细说明断言的具体用法。
2.5 Locators
Locators are a core component of Playwright's automatic wait and retry capabilities. Locators are used to find elements on the page at any moment and are used to perform operations on the elements, such as .click, .fill, etc.
import re
from playwright.sync_api import expect
page.goto("https://www.gitlink.org.cn/")
expect(page).to_have_title(re.compile("GitLink"))
page.locator("//a[text()='开源项目']").click()
官方详细说明:https://playwright.dev/python/docs/locators
后续会详细说明定位的具体用法。
2.6 Test Isolation
The Playwright Pytest plugin is based on the concept of test fixtures, where built-in page fixtures are passed into your tests. Pages are isolated between tests due to the browser context. The browser context is equivalent to a brand new browser profile, in which each test gets a brand new environment, even if multiple tests are running in the same browser.
import re
from playwright.sync_api import Page, expect
def test_gitlink_demo(page: Page):
# 访问地址
page.goto("https://www.gitlink.org.cn/")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("GitLink"))
# 点击按钮,会新开窗口打开页面
page.locator("//a[text()='开源项目']").click()
# 此处需要更新页面的值
page = page.wait_for_event("popup")
# 断言网页标题=开源项目
expect(page).to_have_title(re.compile("开源项目"))
该部分与【pytest插件支持】一节相关。可以跳到该章节详细理解。
2.7 Using Test Hooks
We can use various fixtures to execute code before or after testing and share objects between them. For example, function-scoped firmware with autouse behaves like beforeEach/afterEach, while module-scoped firmware with autouse behaves like beforeAll/afterAll, running before and after all tests.
import pytest
from playwright.sync_api import Page
@pytest.fixture(scope="function", autouse=True)
def before_each_after_each(page: Page):
print("beforeEach")
# Go to the starting url before each test.
page.goto("https://playwright.dev/")
yield
print("afterEach")
def test_main_navigation(page: Page):
# Assertions use the expect API.
expect(page).to_have_url("https://playwright.dev/")
3. Run the test
We can run a single test, a set of tests, or all tests. Tests can be run on one browser or multiple browsers. By default, tests run headless, which means no browser window will be opened while running the test, and the results will be displayed in the terminal. If you prefer, you can run your tests in headed mode using the --headed flag.
- Run tests using Chromium
pytest
- Run a single test file
pytest test_login.py
- Run a set of tests
pytest tests/todo-page/ tests/landing-page/
- Run the specified test method
pytest -k "test_add_a_todo_item"
- Run tests using headless mode
pytest --headed test_login.py
- Specify the browser to run the test
pytest test_login.py --browser webkit
- Specify multiple browsers to run tests
pytest test_login.py --browser webkit --browser firefox
- Parallel testing (usually browsers will test one by one)
Note: installation requiredpytest-xdist
pytest --numprocesses auto
4. Debug debugging
Since Playwright runs in Python, we can debug it using the debugger of your choice, such as using the Python plug-in in Visual Studio Code. Playwright provides the Playwright Inspector tool, which allows you to step through Playwright API calls, view their debug logs and explore locators. Playwright Inspector makes debugging and troubleshooting easier.
- Bash
# 开启调试
PWDEBUG=1
# 关闭调试
PWDEBUG=0
# 运行测试
pytest -s
- PowerShell
# Window可以使用这个
# 开启调试
$env:PWDEBUG=1
# 关闭调试
$env:PWDEBUG=0
# 运行测试
pytest -s
- Batch
# Window可以使用这个
# 开启调试
set PWDEBUG=1
# 关闭调试
set PWDEBUG=0
# 运行测试
pytest -s
5. Script recording Test generator
Playwright comes with test generation out of the box and is a great way to start testing quickly. It opens two windows, a browser window where you can interact with the website you wish to test, and a Playwright Inspector window where you can record tests, copy tests, clear tests, and change the test language. Through Playwright Inspector, you can easily record tests and perform related operations, enabling you to quickly generate and manage test code.
We can first experience the script recording function.
python -m playwright codegen 录制脚本
–help 帮助文档
-o 生成自动化脚本的目录(文件默认生成的地址为你cmd运行命令的地址,也可以在命令中输入需要保存的地址)
–target 脚本语言,包含 JS 和 Python,分别对应值为:python 和 javascript
-b 指定浏览器驱动
Execute the command in cmd: python -m playwright codegen -o "./test_code.py" --target python-pytest
Refer to other commands:python -m playwright codegen --target python -o test.py -b chromium https://www.baidu.com
Note: If you need to stop script recording, just close the browser.
6. Trace viewer Trace viewer
Playwright Trace Viewer is a GUI tool that can trace Playwright tests, which means we can go back and forward through each test operation and visually see what is happening during each operation.
6.1 Start tracking
Can be used browser_context.tracing
for tracking purposes. The code reference is as follows:
import re
from playwright.sync_api import sync_playwright, expect
with sync_playwright() as playwright:
browser = playwright.chromium.launch()
context = browser.new_context()
# 在新开页面之前,开始跟踪记录
context.tracing.start(screenshots=True, snapshots=True, sources=True)
page = context.new_page()
page.goto("https://www.gitlink.org.cn/")
expect(page).to_have_title(re.compile("GitLink"))
page.locator("//a[text()='开源项目']").click()
page = page.wait_for_event("popup")
expect(page).to_have_title(re.compile("开源项目"))
# 停止跟踪记录,并将记录保存到trace.zip(zip文件名可自定义)
context.tracing.stop(path="trace.zip")
6.1 View tracking records
Execute the command in cmd: playwright show-trace trace.zip
.
After we execute the command, the page that opens to view is as follows:
7. pytest plug-in support
Playwright provides a Pytest plugin pytest-playwright
to support end-to-end testing.
Install pytest plugin: pip install pytest-playwright
.
Note: All content in this chapter must be installed pytest-playwright
to take effect.
7.1 Use
Run the test using pytest:pytest --browser webkit --headed
--headed
Indicates running in headless mode.
pytest.ini
We can also configure the running command line parameters in the pytest configuration file , as shown below:
# content of pytest.ini
[pytest]
# Run firefox with UI
addopts = --headed --browser firefox
7.2 CLI arguments
- –headed: Whether to run the test in headless mode or headless mode, the default is headless mode;
- –browser: Run tests in different browsers, you can specify multiple times; the default is chromium;
- –browser-channel: The browser channel to use. Browser channels represent browsers for a specific version and release channel. For example, you can specify a specific Chrome browser version or release channel, such as beta or dev;
- –slowmo: Slow down Playwright operations by the specified number of milliseconds. Can be used to view the progress of the operation (default is 0);
- –device: the device to be simulated;
- –output: directory used to store artifacts generated by tests (default is test-results);
- –tracing: Whether to log tracing information for each test. Optional values: on, off or retain-on-failure (default is off);
- –video: Whether to record a video for each test. Optional values: on, off or retain-on-failure (default is off);
- --screenshot: Whether to automatically capture a screenshot after each test. Optional values: on, off or only-on-failure (default is off);
- --full-page-screenshot: Whether to take a full page screenshot on failure. By default, only the viewport portion is captured. The --screenshot option needs to be enabled (default is off);
7.3 Fixture
pytest is configured with Playwright-specific fixtures. To use these fixtures, pass the fixture name as an argument to the test function.
In the following example, we will page
pass it as a parameter to the Fixture test function.
import re
from playwright.sync_api import Page, expect
def test_gitlink_demo(page: Page):
# 访问地址
page.goto("https://www.gitlink.org.cn/")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("GitLink"))
# 点击按钮,会新开窗口打开页面
page.locator("//a[text()='开源项目']").click()
# 此处需要更新页面的值
page = page.wait_for_event("popup")
# 断言网页标题=开源项目
expect(page).to_have_title(re.compile("开源项目"))
7.3.1 Function scope
These fixtures are created when requested within a test function and destroyed at the end of the test.
- context: New browser context for testing.
- page: A new browser page for testing.
7.3.2 Session scope
These fixtures are created when requested within a test function and destroyed at the end of all tests.
- playwright: Playwright instance.
- browser_type: BrowserType instance of the current browser.
- browser: Browser instance launched by Playwright.
- browser_name: browser name, string type.
- browser_channel: browser channel, string type.
- is_chromium, is_webkit, is_firefox: Boolean values corresponding to browser types respectively.
7.3.3 Custom fixture options
For browser and context fixtures, use the following fixtures to define custom launch options.
- browser_type_launch_args: Override the launch parameters of browser_type.launch(). It should return a dictionary.
- browser_context_args: Override options of browser.new_context(). It should return a dictionary.
Context options (browser.new_context()) can also be overridden for individual tests by using the browser_context_args tag.
import pytest
@pytest.mark.browser_context_args(timezone_id="Europe/Berlin", locale="en-GB")
def test_browser_context_args(page):
assert page.evaluate("window.navigator.userAgent") == "Europe/Berlin"
assert page.evaluate("window.navigator.languages") == ["de-DE"]
7.4 Parallel testing
If the computer's CPU is high enough, we can use it to pytest-xdist
run multiple tests in parallel to speed up the execution time of the entire test suite.
# install dependency
pip install pytest-xdist
# use the --numprocesses flag
# 根据硬件和测试的性质,可以将 numprocesses 设置为从 2 到机器上的 CPU 数量的任意值。
# 如果设置得过高,可能会出现意外行为。
pytest --numprocesses auto
7.5 Example
7.5.1 Configuring slow mode
We can --slowmo
configure slow mode using parameters.
for example:pytest --slowmo 100
Or you can implement the code as follows:
# run.py
import pytest
pytest.main( ['--headed', '--browser=chromium', "--browser-channel=chrome", "--slowmo=10"])
7.5.2 Skip X Browser Test
We can use a decorator @pytest.mark.skip_browser
to skip this test case and skip executing the X browser.
# test_demo.py
import re
from playwright.sync_api import Page, expect
import pytest
@pytest.mark.skip_browser("webkit")
def test_gitlink_demo(page: Page):
# 访问地址
page.goto("https://www.gitlink.org.cn/")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("GitLink"))
7.5.3 Specify the browser where the test case runs
We can use decorators @pytest.mark.only_browser
to specify the browser on which the test case will be executed.
# test_demo.py
import re
from playwright.sync_api import Page, expect
import pytest
@pytest.mark.only_browser("webkit")
def test_gitlink_demo(page: Page):
# 访问地址
page.goto("https://www.gitlink.org.cn/")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("GitLink"))
7.5.4 Specify the browser channel for test case execution
We can use command line parameters --browser-channel
to specify running browser parameters.
for example:pytest --browser-channel chrome
Or you can implement the code as follows:
# run.py
import pytest
pytest.main( ['--headed', '--browser=chromium', "--browser-channel=chrome"])
7.5.5 Configure base-url/host
We can use the command function base-url
to configure the base-url/host of the run.
for example:pytest --base-url https://www.gitlink.org.cn/
# run.py
import pytest
pytest.main( ['--headed', '--browser=chromium', "--browser-channel=chrome", "--base-url=https://www.gitlink.org.cn"])
Then in our test function, we just need to write the relative path. Reference is as follows:
# test_demo.py
def test_gitlink_demo(page: Page):
# 访问地址,这里写的相对地址
page.goto("/expore")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("开源项目"))
7.5.6 Ignore HTTPS errors
# conftest.py
import pytest
@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
return {
**browser_context_args,
"ignore_https_errors": True
}
7.5.7 Custom window size
# conftest.py
import pytest
@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
return {
**browser_context_args,
"viewport": {
"width": 1920,
"height": 1080,
}
}
7.5.8 Device Simulation
# conftest.py
import pytest
@pytest.fixture(scope="session")
def browser_context_args(browser_context_args, playwright):
iphone_11 = playwright.devices['iPhone 11 Pro']
return {
**browser_context_args,
**iphone_11,
}
7.5.9 Persistent context
When using a persistent context, all pages in the test are created from the persistent context.
# conftest.py
import pytest
from playwright.sync_api import BrowserType
from typing import Dict
@pytest.fixture(scope="session")
def context(
browser_type: BrowserType,
browser_type_launch_args: Dict,
browser_context_args: Dict
):
context = browser_type.launch_persistent_context("./foobar", **{
**browser_type_launch_args,
**browser_context_args,
"locale": "de-DE",
})
yield context
context.close()
Then in the test method, we need to use the returned context
one to create a new one page
. The reference is as follows:
# test_demo.py
import re
from playwright.sync_api import Page, expect
import pytest
def test_gitlink_demo2(context):
# 新建一个页面
page = context.new_page()
# 访问地址
page.goto("/explore")
# 断言网页标题=GitLink
expect(page).to_have_title(re.compile("开源项目"))
7.5.10 Compatible with unittest.TestCase
The following is an example compatible with unittest.TestCase. It should be noted that this method has a limitation: only one browser can be specified, and a browser matrix cannot be generated when multiple browsers are specified.
import pytest
import unittest
from playwright.sync_api import Page
class MyTest(unittest.TestCase):
@pytest.fixture(autouse=True)
def setup(self, page: Page):
self.page = page
def test_foobar(self):
self.page.goto("https://microsoft.com")
self.page.locator("#foobar").click()
assert self.page.evaluate("1 + 1") == 2
7.5.11 Use with pdb
Use breakpoint() statements in test code to pause execution and get the pdb REPL (Python debugger) interactive interface.
def test_bing_is_working(page):
page.goto("https://bing.com")
breakpoint()
# ...