Assertions
Playwright gives you Web-First Assertions with convenience methods for creating assertions that will wait and retry until the expected condition is met.
Consider the following example:
- Sync
- Async
from playwright.sync_api import Page, expect
def test_status_becomes_submitted(page: Page) -> None:
# ..
page.locator("#submit-button").click()
expect(page.locator(".status")).to_have_text("Submitted")
from playwright.async_api import Page, expect
async def test_status_becomes_submitted(page: Page) -> None:
# ..
await page.locator("#submit-button").click()
await expect(page.locator(".status")).to_have_text("Submitted")
Playwright will be re-testing the node with the selector .status
until fetched Node has the "Submitted"
text. It will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is reached. You can pass this timeout as an option.
By default, the timeout for assertions is set to 5 seconds.
- expect(locator).not_to_be_checked(**kwargs)
- expect(locator).not_to_be_disabled(**kwargs)
- expect(locator).not_to_be_editable(**kwargs)
- expect(locator).not_to_be_empty(**kwargs)
- expect(locator).not_to_be_enabled(**kwargs)
- expect(locator).not_to_be_focused(**kwargs)
- expect(locator).not_to_be_hidden(**kwargs)
- expect(locator).not_to_be_visible(**kwargs)
- expect(locator).not_to_contain_text(expected, **kwargs)
- expect(locator).not_to_have_attribute(name, value, **kwargs)
- expect(locator).not_to_have_class(expected, **kwargs)
- expect(locator).not_to_have_count(count, **kwargs)
- expect(locator).not_to_have_css(name, value, **kwargs)
- expect(locator).not_to_have_id(id, **kwargs)
- expect(locator).not_to_have_js_property(name, value, **kwargs)
- expect(locator).not_to_have_text(expected, **kwargs)
- expect(locator).not_to_have_value(value, **kwargs)
- expect(locator).not_to_have_values(values, **kwargs)
- expect(locator).to_be_checked(**kwargs)
- expect(locator).to_be_disabled(**kwargs)
- expect(locator).to_be_editable(**kwargs)
- expect(locator).to_be_empty(**kwargs)
- expect(locator).to_be_enabled(**kwargs)
- expect(locator).to_be_focused(**kwargs)
- expect(locator).to_be_hidden(**kwargs)
- expect(locator).to_be_visible(**kwargs)
- expect(locator).to_contain_text(expected, **kwargs)
- expect(locator).to_have_attribute(name, value, **kwargs)
- expect(locator).to_have_class(expected, **kwargs)
- expect(locator).to_have_count(count, **kwargs)
- expect(locator).to_have_css(name, value, **kwargs)
- expect(locator).to_have_id(id, **kwargs)
- expect(locator).to_have_js_property(name, value, **kwargs)
- expect(locator).to_have_text(expected, **kwargs)
- expect(locator).to_have_value(value, **kwargs)
- expect(locator).to_have_values(values, **kwargs)
- expect(page).not_to_have_title(title_or_reg_exp, **kwargs)
- expect(page).not_to_have_url(url_or_reg_exp, **kwargs)
- expect(page).to_have_title(title_or_reg_exp, **kwargs)
- expect(page).to_have_url(url_or_reg_exp, **kwargs)
- expect(api_response).not_to_be_ok()
- expect(api_response).to_be_ok()
expect(locator).not_to_be_checked(**kwargs)
Added in: v1.20The opposite of expect(locator).to_be_checked(**kwargs).
expect(locator).not_to_be_disabled(**kwargs)
Added in: v1.20The opposite of expect(locator).to_be_disabled(**kwargs).
expect(locator).not_to_be_editable(**kwargs)
Added in: v1.20editable
<bool> Added in: v1.26#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_be_editable(**kwargs).
expect(locator).not_to_be_empty(**kwargs)
Added in: v1.20The opposite of expect(locator).to_be_empty(**kwargs).
expect(locator).not_to_be_enabled(**kwargs)
Added in: v1.20enabled
<bool> Added in: v1.26#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_be_enabled(**kwargs).
expect(locator).not_to_be_focused(**kwargs)
Added in: v1.20The opposite of expect(locator).to_be_focused(**kwargs).
expect(locator).not_to_be_hidden(**kwargs)
Added in: v1.20The opposite of expect(locator).to_be_hidden(**kwargs).
expect(locator).not_to_be_visible(**kwargs)
Added in: v1.20timeout
<float> Time to retry the assertion for. Added in: v1.18#visible
<bool> Added in: v1.26#- returns:NoneType># <
The opposite of expect(locator).to_be_visible(**kwargs).
expect(locator).not_to_contain_text(expected, **kwargs)
Added in: v1.20expected
<str|Pattern|List[str|Pattern]> Expected substring or RegExp or a list of those. Added in: v1.18#ignore_case
<bool> Whether to perform case-insensitive match.ignore_case
option takes precedence over the corresponding regular expression flag if specified. Added in: v1.23#timeout
<float> Time to retry the assertion for. Added in: v1.18#use_inner_text
<bool> Whether to useelement.innerText
instead ofelement.textContent
when retrieving DOM node text. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_contain_text(expected, **kwargs).
expect(locator).not_to_have_attribute(name, value, **kwargs)
Added in: v1.20name
<str> Attribute name. Added in: v1.18#value
<str|Pattern> Expected attribute value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_attribute(name, value, **kwargs).
expect(locator).not_to_have_class(expected, **kwargs)
Added in: v1.20expected
<str|Pattern|List[str|Pattern]> Expected class or RegExp or a list of those. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_class(expected, **kwargs).
expect(locator).not_to_have_count(count, **kwargs)
Added in: v1.20count
<int> Expected count. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_count(count, **kwargs).
expect(locator).not_to_have_css(name, value, **kwargs)
Added in: v1.20name
<str> CSS property name. Added in: v1.18#value
<str|Pattern> CSS property value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_css(name, value, **kwargs).
expect(locator).not_to_have_id(id, **kwargs)
Added in: v1.20id
<str|Pattern> Element id. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_id(id, **kwargs).
expect(locator).not_to_have_js_property(name, value, **kwargs)
Added in: v1.20name
<str> Property name. Added in: v1.18#value
<Any> Property value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_js_property(name, value, **kwargs).
expect(locator).not_to_have_text(expected, **kwargs)
Added in: v1.20expected
<str|Pattern|List[str|Pattern]> Expected substring or RegExp or a list of those. Added in: v1.18#ignore_case
<bool> Whether to perform case-insensitive match.ignore_case
option takes precedence over the corresponding regular expression flag if specified. Added in: v1.23#timeout
<float> Time to retry the assertion for. Added in: v1.18#use_inner_text
<bool> Whether to useelement.innerText
instead ofelement.textContent
when retrieving DOM node text. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_text(expected, **kwargs).
expect(locator).not_to_have_value(value, **kwargs)
Added in: v1.20value
<str|Pattern> Expected value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(locator).to_have_value(value, **kwargs).
expect(locator).not_to_have_values(values, **kwargs)
Added in: v1.23values
<List[str|Pattern]> Expected options currently selected.#timeout
<float> Time to retry the assertion for.#- returns:NoneType># <
The opposite of expect(locator).to_have_values(values, **kwargs).
expect(locator).to_be_checked(**kwargs)
Added in: v1.20checked
<bool> Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to a checked input.
- Sync
- Async
from playwright.sync_api import expect
locator = page.get_by_label("Subscribe to newsletter")
expect(locator).to_be_checked()
from playwright.async_api import expect
locator = page.get_by_label("Subscribe to newsletter")
await expect(locator).to_be_checked()
expect(locator).to_be_disabled(**kwargs)
Added in: v1.20Ensures the Locator points to a disabled element. Element is disabled if it has "disabled" attribute or is disabled via 'aria-disabled'. Note that only native control elements such as HTML button
, input
, select
, textarea
, option
, optgroup
can be disabled by setting "disabled" attribute. "disabled" attribute on other elements is ignored by the browser.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("button.submit")
expect(locator).to_be_disabled()
from playwright.async_api import expect
locator = page.locator("button.submit")
await expect(locator).to_be_disabled()
expect(locator).to_be_editable(**kwargs)
Added in: v1.20editable
<bool> Added in: v1.26#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an editable element.
- Sync
- Async
from playwright.sync_api import expect
locator = page.get_by_role("textbox")
expect(locator).to_be_editable()
from playwright.async_api import expect
locator = page.get_by_role("textbox")
await expect(locator).to_be_editable()
expect(locator).to_be_empty(**kwargs)
Added in: v1.20Ensures the Locator points to an empty editable element or to a DOM node that has no text.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("div.warning")
expect(locator).to_be_empty()
from playwright.async_api import expect
locator = page.locator("div.warning")
await expect(locator).to_be_empty()
expect(locator).to_be_enabled(**kwargs)
Added in: v1.20enabled
<bool> Added in: v1.26#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an enabled element.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("button.submit")
expect(locator).to_be_enabled()
from playwright.async_api import expect
locator = page.locator("button.submit")
await expect(locator).to_be_enabled()
expect(locator).to_be_focused(**kwargs)
Added in: v1.20Ensures the Locator points to a focused DOM node.
- Sync
- Async
from playwright.sync_api import expect
locator = page.get_by_role("textbox")
expect(locator).to_be_focused()
from playwright.async_api import expect
locator = page.get_by_role("textbox")
await expect(locator).to_be_focused()
expect(locator).to_be_hidden(**kwargs)
Added in: v1.20Ensures that Locator either does not resolve to any DOM node, or resolves to a non-visible one.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator('.my-element')
expect(locator).to_be_hidden()
from playwright.async_api import expect
locator = page.locator('.my-element')
await expect(locator).to_be_hidden()
expect(locator).to_be_visible(**kwargs)
Added in: v1.20timeout
<float> Time to retry the assertion for. Added in: v1.18#visible
<bool> Added in: v1.26#- returns:NoneType># <
Ensures that Locator points to an attached and visible DOM node.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator('.my-element')
expect(locator).to_be_visible()
from playwright.async_api import expect
locator = page.locator('.my-element')
await expect(locator).to_be_visible()
expect(locator).to_contain_text(expected, **kwargs)
Added in: v1.20expected
<str|Pattern|List[str|Pattern]> Expected substring or RegExp or a list of those. Added in: v1.18#ignore_case
<bool> Whether to perform case-insensitive match.ignore_case
option takes precedence over the corresponding regular expression flag if specified. Added in: v1.23#timeout
<float> Time to retry the assertion for. Added in: v1.18#use_inner_text
<bool> Whether to useelement.innerText
instead ofelement.textContent
when retrieving DOM node text. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element that contains the given text. You can use regular expressions for the value as well.
- Sync
- Async
import re
from playwright.sync_api import expect
locator = page.locator('.title')
expect(locator).to_contain_text("substring")
expect(locator).to_contain_text(re.compile(r"\d messages"))
import re
from playwright.async_api import expect
locator = page.locator('.title')
await expect(locator).to_contain_text("substring")
await expect(locator).to_contain_text(re.compile(r"\d messages"))
If you pass an array as an expected value, the expectations are:
- Locator resolves to a list of elements.
- Elements from a subset of this list contain text from the expected array, respectively.
- The matching subset of elements has the same order as the expected array.
- Each text value from the expected array is matched by some element from the list.
For example, consider the following list:
<ul>
<li>Item Text 1</li>
<li>Item Text 2</li>
<li>Item Text 3</li>
</ul>
Let's see how we can use the assertion:
- Sync
- Async
from playwright.sync_api import expect
# ✓ Contains the right items in the right order
expect(page.locator("ul > li")).to_contain_text(["Text 1", "Text 3", "Text 4"])
# ✖ Wrong order
expect(page.locator("ul > li")).to_contain_text(["Text 3", "Text 2"])
# ✖ No item contains this text
expect(page.locator("ul > li")).to_contain_text(["Some 33"])
# ✖ Locator points to the outer list element, not to the list items
expect(page.locator("ul")).to_contain_text(["Text 3"])
from playwright.async_api import expect
# ✓ Contains the right items in the right order
await expect(page.locator("ul > li")).to_contain_text(["Text 1", "Text 3", "Text 4"])
# ✖ Wrong order
await expect(page.locator("ul > li")).to_contain_text(["Text 3", "Text 2"])
# ✖ No item contains this text
await expect(page.locator("ul > li")).to_contain_text(["Some 33"])
# ✖ Locator points to the outer list element, not to the list items
await expect(page.locator("ul")).to_contain_text(["Text 3"])
expect(locator).to_have_attribute(name, value, **kwargs)
Added in: v1.20name
<str> Attribute name. Added in: v1.18#value
<str|Pattern> Expected attribute value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element with given attribute.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("input")
expect(locator).to_have_attribute("type", "text")
from playwright.async_api import expect
locator = page.locator("input")
await expect(locator).to_have_attribute("type", "text")
expect(locator).to_have_class(expected, **kwargs)
Added in: v1.20expected
<str|Pattern|List[str|Pattern]> Expected class or RegExp or a list of those. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element with given CSS classes. This needs to be a full match or using a relaxed regular expression.
<div class='selected row' id='component'></div>
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("#component")
expect(locator).to_have_class(re.compile(r"selected"))
expect(locator).to_have_class("selected row")
from playwright.async_api import expect
locator = page.locator("#component")
await expect(locator).to_have_class(re.compile(r"selected"))
await expect(locator).to_have_class("selected row")
Note that if array is passed as an expected value, entire lists of elements can be asserted:
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("list > .component")
expect(locator).to_have_class(["component", "component selected", "component"])
from playwright.async_api import expect
locator = page.locator("list > .component")
await expect(locator).to_have_class(["component", "component selected", "component"])
expect(locator).to_have_count(count, **kwargs)
Added in: v1.20count
<int> Expected count. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator resolves to an exact number of DOM nodes.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator("list > .component")
expect(locator).to_have_count(3)
from playwright.async_api import expect
locator = page.locator("list > .component")
await expect(locator).to_have_count(3)
expect(locator).to_have_css(name, value, **kwargs)
Added in: v1.20name
<str> CSS property name. Added in: v1.18#value
<str|Pattern> CSS property value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator resolves to an element with the given computed CSS style.
- Sync
- Async
from playwright.sync_api import expect
locator = page.get_by_role("button")
expect(locator).to_have_css("display", "flex")
from playwright.async_api import expect
locator = page.get_by_role("button")
await expect(locator).to_have_css("display", "flex")
expect(locator).to_have_id(id, **kwargs)
Added in: v1.20id
<str|Pattern> Element id. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element with the given DOM Node ID.
- Sync
- Async
from playwright.sync_api import expect
locator = page.get_by_role("textbox")
expect(locator).to_have_id("lastname")
from playwright.async_api import expect
locator = page.get_by_role("textbox")
await expect(locator).to_have_id("lastname")
expect(locator).to_have_js_property(name, value, **kwargs)
Added in: v1.20name
<str> Property name. Added in: v1.18#value
<Any> Property value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element with given JavaScript property. Note that this property can be of a primitive type as well as a plain serializable JavaScript object.
- Sync
- Async
from playwright.sync_api import expect
locator = page.locator(".component")
expect(locator).to_have_js_property("loaded", True)
from playwright.async_api import expect
locator = page.locator(".component")
await expect(locator).to_have_js_property("loaded", True)
expect(locator).to_have_text(expected, **kwargs)
Added in: v1.20expected
<str|Pattern|List[str|Pattern]> Expected substring or RegExp or a list of those. Added in: v1.18#ignore_case
<bool> Whether to perform case-insensitive match.ignore_case
option takes precedence over the corresponding regular expression flag if specified. Added in: v1.23#timeout
<float> Time to retry the assertion for. Added in: v1.18#use_inner_text
<bool> Whether to useelement.innerText
instead ofelement.textContent
when retrieving DOM node text. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element with the given text. You can use regular expressions for the value as well.
- Sync
- Async
import re
from playwright.sync_api import expect
locator = page.locator(".title")
expect(locator).to_have_text(re.compile(r"Welcome, Test User"))
expect(locator).to_have_text(re.compile(r"Welcome, .*"))
import re
from playwright.async_api import expect
locator = page.locator(".title")
await expect(locator).to_have_text(re.compile(r"Welcome, Test User"))
await expect(locator).to_have_text(re.compile(r"Welcome, .*"))
If you pass an array as an expected value, the expectations are:
- Locator resolves to a list of elements.
- The number of elements equals the number of expected values in the array.
- Elements from the list have text matching expected array values, one by one, in order.
For example, consider the following list:
<ul>
<li>Text 1</li>
<li>Text 2</li>
<li>Text 3</li>
</ul>
Let's see how we can use the assertion:
- Sync
- Async
from playwright.sync_api import expect
# ✓ Has the right items in the right order
await expect(page.locator("ul > li")).to_have_text(["Text 1", "Text 2", "Text 3"])
# ✖ Wrong order
await expect(page.locator("ul > li")).to_have_text(["Text 3", "Text 2", "Text 1"])
# ✖ Last item does not match
await expect(page.locator("ul > li")).to_have_text(["Text 1", "Text 2", "Text"])
# ✖ Locator points to the outer list element, not to the list items
await expect(page.locator("ul")).to_have_text(["Text 1", "Text 2", "Text 3"])
from playwright.async_api import expect
# ✓ Has the right items in the right order
await expect(page.locator("ul > li")).to_have_text(["Text 1", "Text 2", "Text 3"])
# ✖ Wrong order
await expect(page.locator("ul > li")).to_have_text(["Text 3", "Text 2", "Text 1"])
# ✖ Last item does not match
await expect(page.locator("ul > li")).to_have_text(["Text 1", "Text 2", "Text"])
# ✖ Locator points to the outer list element, not to the list items
await expect(page.locator("ul")).to_have_text(["Text 1", "Text 2", "Text 3"])
expect(locator).to_have_value(value, **kwargs)
Added in: v1.20value
<str|Pattern> Expected value. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the Locator points to an element with the given input value. You can use regular expressions for the value as well.
- Sync
- Async
import re
from playwright.sync_api import expect
locator = page.locator("input[type=number]")
expect(locator).to_have_value(re.compile(r"[0-9]"))
import re
from playwright.async_api import expect
locator = page.locator("input[type=number]")
await expect(locator).to_have_value(re.compile(r"[0-9]"))
expect(locator).to_have_values(values, **kwargs)
Added in: v1.23values
<List[str|Pattern]> Expected options currently selected.#timeout
<float> Time to retry the assertion for.#- returns:NoneType># <
Ensures the Locator points to multi-select/combobox (i.e. a select
with the multiple
attribute) and the specified values are selected.
For example, given the following element:
<select id="favorite-colors" multiple>
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
- Sync
- Async
import re
from playwright.sync_api import expect
locator = page.locator("id=favorite-colors")
locator.select_option(["R", "G"])
expect(locator).to_have_values([re.compile(r"R"), re.compile(r"G")])
import re
from playwright.async_api import expect
locator = page.locator("id=favorite-colors")
await locator.select_option(["R", "G"])
await expect(locator).to_have_values([re.compile(r"R"), re.compile(r"G")])
expect(page).not_to_have_title(title_or_reg_exp, **kwargs)
Added in: v1.20title_or_reg_exp
<str|Pattern> Expected title or RegExp. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(page).to_have_title(title_or_reg_exp, **kwargs).
expect(page).not_to_have_url(url_or_reg_exp, **kwargs)
Added in: v1.20url_or_reg_exp
<str|Pattern> Expected URL string or RegExp. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
The opposite of expect(page).to_have_url(url_or_reg_exp, **kwargs).
expect(page).to_have_title(title_or_reg_exp, **kwargs)
Added in: v1.20title_or_reg_exp
<str|Pattern> Expected title or RegExp. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the page has the given title.
- Sync
- Async
import re
from playwright.sync_api import expect
# ...
expect(page).to_have_title(re.compile(r".*checkout"))
import re
from playwright.async_api import expect
# ...
await expect(page).to_have_title(re.compile(r".*checkout"))
expect(page).to_have_url(url_or_reg_exp, **kwargs)
Added in: v1.20url_or_reg_exp
<str|Pattern> Expected URL string or RegExp. Added in: v1.18#timeout
<float> Time to retry the assertion for. Added in: v1.18#- returns:NoneType># <
Ensures the page is navigated to the given URL.
- Sync
- Async
import re
from playwright.sync_api import expect
# ...
expect(page).to_have_url(re.compile(".*checkout"))
import re
from playwright.async_api import expect
# ...
await expect(page).to_have_url(re.compile(".*checkout"))
expect(api_response).not_to_be_ok()
Added in: v1.19The opposite of expect(api_response).to_be_ok().
expect(api_response).to_be_ok()
Added in: v1.18Ensures the response status code is within 200..299
range.
- Sync
- Async
import re
from playwright.sync_api import expect
# ...
expect(response).to_be_ok()
from playwright.async_api import expect
# ...
await expect(response).to_be_ok()