playwright-python-tutorial Part 2

Part 2: First steps with Playwright

Part 2 of the tutorial shows how to take your first steps with Playwright calls.
It will explain browsers, contexts, and pages.
It will also cover basic Playwright API calls.

Browsers, contexts, and pages

Before we can automate interactions using Playwright's API, we must first understand how Playwright interacts with browsers.
There are three main layers to automation: browsers, browser contexts, and pages:

  1. A browser
    is a single instance of a web browser.
    Playwright will automatically launch a browser instance specified by code or by inputs.
    Typically, this is either the Chromium, Firefox, or WebKit instance installed via playwright install,
    but it may also be other browsers installed on your local machine.
  2. A browser context
    is an isolated incognito-alike session within a browser instance.
    They are fast and cheap to create.
    One browser may have multiple browser contexts.
    The recommended practice is for all tests to share one browser instance but for each test to have its own browser context.
  3. A page
    is a single tab or window within a browser context.
    A browser context may have multiple pages.
    Typically, an individual test should interact with only one page.

Below is a diagram illustrating how these three pieces work together:

[图片上传失败...(image-568961-1657245798236)]

Typically, we would need the following Playwright calls to set up a browser, browser context, and page:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context()
    page = context.new_page()

However, the pytest-playwright plugin takes care of these things automatically with the following fixtures:

  • The browser fixture provides the browser instance launched by Playwright.
  • The context fixture provides a new browser context for a test.
  • The page fixture provides a new browser page for a test.

All the Playwright calls with pytest-playwright use the synchronous API instead of the async API.
The browser fixture has session scope, meaning all tests will share one browser instance.
The context and page fixtures have function scope, meaning each test gets new ones.
Typically, a test will only need to call the page fixture directly.
These fixtures will also automatically clean up everything after testing is complete.
You do not need to explicitly close the browser.

Playwright supports both synchronous and asynchronous calls for Python.
Synchronous calls are sufficient for almost all test automation needs.
Asynchronous calls could be useful for other types of automation, such as web scraping.

Let's update our test stub to call the page fixture.
In tests/test_search.py, add the following import statement:

from playwright.sync_api import Page

Then, change the test function signature from this:

def test_basic_duckduckgo_search() -> None:

To this:

def test_basic_duckduckgo_search(page: Page) -> None:

Now the test has access to a fresh page in a new browser context.
If we write multiple tests, each test will get its own page and context,
but they will all share the same browser instance.

Navigating to a web page

Now that we have a page, let's do something on it!
Our first test step is, "Given the DuckDuckGo home page is displayed".
Let's navigate to the DuckDuckGo home page like this:

def test_basic_duckduckgo_search(page):
    # Given the DuckDuckGo home page is displayed
    page.goto('https://www.duckduckgo.com')

If you are familiar with Selenium WebDriver, then this command probably looks similar to the driver.get(...) method.
However, Playwright's goto method is more sophisticated:
it waits for the page to fire the load event.
Selenium WebDriver does not automatically wait for any event,
which frequently leads to race conditions that cause flaky tests.

In Playwright, you can also wait for other page events like this:

def test_basic_duckduckgo_search(page):
    # Given the DuckDuckGo home page is displayed
    page.goto('https://www.duckduckgo.com', wait_until='networkidle')

For our test, however, the default load event will suffice.

Let's try running our test to make sure Playwright works.
Launch pytest using the following command:

$ python3 -m pytest tests --headed --slowmo 1000

This invocation has two new arguments.
The first one is --headed.
By default, Playwright runs tests in headless mode, in which the browser is not visibly rendered.
Headless mode is faster than headed mode and thus ideal for "real" testing (like in CI).
However, headed mode is better when developing tests so that you can see what is happening.

The second new argument is --slowmo.
By default, Playwright runs interactions as fast as it can.
Again, this is great for "real" testing, but it might be too fast for humans to watch when developing and debugging.
The --slowmo option lets the caller set a hard sleep time after every Playwright call.
For example, --slowmo 1000 will pause execution for 1 second (1000 ms) after each call.
This option is a much better way to slow down tests than to add time.sleep(...) calls everywhere!

When you launch pytest, Chromium should pop up, navigate to the DuckDuckGo home page, and close.
Try running it with and without the --headed and --slowmo options, too.
Verify that Playwright calls work and the test passes before moving on.

Performing a search

Next, let's try to interact with page elements.
Playwright is able to locate any element on the page using selectors.
Out of the box, Playwright supports the following types of selectors:

  • Text
  • CSS
  • XPath
  • N-th element
  • React
  • Vue
  • ID attributes

Text and CSS selectors also pierce the Shadow DOM by default!

In general, you should keep selectors as simple as possible.
Try to stick to text, IDs, or CSS selectors.
Use more complicated selectors only as necessary.

This tutorial will not cover recommended practices for element selectors deeply.
If you want to learn more about selectors,
read the Element selectors page in the Playwright docs,
or take the Web Element Locator Strategies course
from Test Automation University.

The next step in our test case is, "When the user searches for a phrase".
This is actually a compound interaction with two parts:

  1. Entering text into the search input field
  2. Clicking the search button

Let's start with the first part of the interaction: entering text into the search input field.
We need to find a selector for the search input.
One of the best ways to find selectors is to inspect elements through Chrome DevTools.
In Chrome, simply right-click any page and select "Inspect" to open DevTools.

Here's the inspection panel for the search input element:

[图片上传失败...(image-9e0b6b-1657245798237)]

Thankfully, this element has an ID.
We can use the selector #search_form_input_homepage to uniquely identify this element.

To interact with elements with Playwright, we must use locators.
The Locator class
takes in a selector and produces an object that can interact with the target element.

For example, to enter text into this input element, we must use Locator's
fill method.
Append the following line to the test case:

    page.locator('#search_form_input_homepage').fill('panda')

Since search_form_input_homepage is an ID, we could also use Playwright's
ID attribute selector:

page.locator('id=search_form_input_homepage').fill('panda')

Playwright's Page class also provides methods for element interactions like this:

page.fill('#search_form_input_homepage', 'panda')

However, using locators is recommended over direct page calls.
Locators use "strict" mode - a locator raises an exception if its selector finds more than one element.
Locators are also more reusable, especially when using page object classes.

Playwright waits for the target element to be visible and editable before it attempts to enter the text.
We are arbitrarily using the phrase 'panda' as our search phrase because, well, why not?

Let's handle the second part of the interaction: clicking the search button.
Here's the inspection panel for the search button:

[图片上传失败...(image-8ce4a8-1657245798237)]

This element also has an ID: #search_button_homepage. Nice!

To click an element, we must use Playwright's
click method.
Append the following line to the test case:

    page.locator('#search_button_homepage').click()

Again, Playwright is nice and concise.
The click method waits for the target element to be ready to receive clicks, too.

Our test case should now look like this:

from playwright.sync_api import Page

def test_basic_duckduckgo_search(page: Page) -> None:
    # Given the DuckDuckGo home page is displayed
    page.goto('https://www.duckduckgo.com')

    # When the user searches for a phrase
    page.locator('#search_form_input_homepage').fill('panda')
    page.locator('#search_button_homepage').click()

    # Then the search result query is the phrase
    # And the search result links pertain to the phrase
    # And the search result title contains the phrase
    pass

Rerun the test using python3 -m pytest tests --headed --slowmo 1000.
Now, you should see the test actually perform the search!

Navigation, input filling, and clicking are only three of many page interactions you can do with Playwright.
Anything a user can do on a web page, Playwright can do as well.
Check out the Playwright Page
and Locator classes
to see all methods and attributes.
We will use more of these calls in the next tutorial parts.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容