playwright-python/tests/async/test_assertions.py

1182 lines
45 KiB
Python

# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import asyncio
import datetime
import re
import pytest
from playwright.async_api import Browser, Error, Page, expect
from tests.server import Server
async def test_assertions_page_to_have_title(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<title>new title</title>")
await expect(page).to_have_title("new title")
await expect(page).to_have_title(re.compile("new title"))
with pytest.raises(AssertionError):
await expect(page).to_have_title("not the current title", timeout=750)
with pytest.raises(AssertionError):
await expect(page).to_have_title(
re.compile("not the current title"), timeout=750
)
with pytest.raises(AssertionError):
await expect(page).not_to_have_title(re.compile("new title"), timeout=750)
with pytest.raises(AssertionError):
await expect(page).not_to_have_title("new title", timeout=750)
await expect(page).not_to_have_title("great title", timeout=750)
await page.evaluate(
"""
setTimeout(() => {
document.title = 'great title';
}, 2000);
"""
)
await expect(page).to_have_title("great title")
await expect(page).to_have_title(re.compile("great title"))
async def test_assertions_page_to_have_url(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await expect(page).to_have_url(server.EMPTY_PAGE)
await expect(page).to_have_url(re.compile(r".*/empty\.html"))
with pytest.raises(AssertionError):
await expect(page).to_have_url("nooooo", timeout=750)
with pytest.raises(AssertionError):
await expect(page).to_have_url(re.compile("not-the-url"), timeout=750)
await page.evaluate(
"""
setTimeout(() => {
window.location = window.location.origin + '/grid.html';
}, 2000);
"""
)
await expect(page).to_have_url(server.PREFIX + "/grid.html")
await expect(page).not_to_have_url(server.EMPTY_PAGE, timeout=750)
with pytest.raises(AssertionError):
await expect(page).not_to_have_url(re.compile(r".*/grid\.html"), timeout=750)
with pytest.raises(AssertionError):
await expect(page).not_to_have_url(server.PREFIX + "/grid.html", timeout=750)
await expect(page).to_have_url(re.compile(r".*/grid\.html"))
await expect(page).not_to_have_url("**/empty.html", timeout=750)
async def test_assertions_page_to_have_url_with_base_url(
browser: Browser, server: Server
) -> None:
page = await browser.new_page(base_url=server.PREFIX)
await page.goto("/empty.html")
await expect(page).to_have_url("/empty.html")
await expect(page).to_have_url(re.compile(r".*/empty\.html"))
await page.close()
async def test_assertions_page_to_have_url_support_ignore_case(page: Page) -> None:
await page.goto("data:text/html,<div>A</div>")
await expect(page).to_have_url("DATA:teXT/HTml,<div>a</div>", ignore_case=True)
async def test_assertions_locator_to_contain_text(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div id=foobar>kek</div>")
await expect(page.locator("div#foobar")).to_contain_text("kek")
await expect(page.locator("div#foobar")).not_to_contain_text("bar", timeout=100)
with pytest.raises(AssertionError):
await expect(page.locator("div#foobar")).to_contain_text("bar", timeout=100)
await page.set_content("<div>Text \n1</div><div>Text2</div><div>Text3</div>")
await expect(page.locator("div")).to_contain_text(["ext 1", re.compile("ext3")])
async def test_assertions_locator_to_contain_text_should_throw_if_arg_is_unsupported_type(
page: Page,
) -> None:
with pytest.raises(Error, match="value must be a string or regular expression"):
await expect(page.locator("div")).to_contain_text(1) # type: ignore
async def test_assertions_locator_to_have_attribute(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div id=foobar>kek</div>")
await expect(page.locator("div#foobar")).to_have_attribute("id", "foobar")
await expect(page.locator("div#foobar")).to_have_attribute(
"id", re.compile("foobar")
)
await expect(page.locator("div#foobar")).not_to_have_attribute(
"id", "kek", timeout=100
)
with pytest.raises(AssertionError):
await expect(page.locator("div#foobar")).to_have_attribute(
"id", "koko", timeout=100
)
async def test_assertions_locator_to_have_attribute_ignore_case(
page: Page, server: Page
) -> None:
await page.set_content("<div id=NoDe>Text content</div>")
locator = page.locator("#NoDe")
await expect(locator).to_have_attribute("id", "node", ignore_case=True)
await expect(locator).not_to_have_attribute("id", "node")
async def test_assertions_locator_to_have_class(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div class=foobar>kek</div>")
await expect(page.locator("div.foobar")).to_have_class("foobar")
await expect(page.locator("div.foobar")).to_have_class(["foobar"])
await expect(page.locator("div.foobar")).to_have_class(re.compile("foobar"))
await expect(page.locator("div.foobar")).to_have_class([re.compile("foobar")])
await expect(page.locator("div.foobar")).not_to_have_class("kekstar", timeout=100)
with pytest.raises(AssertionError):
await expect(page.locator("div.foobar")).to_have_class("oh-no", timeout=100)
async def test_assertions_locator_to_contain_class(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div class='foo bar baz'></div>")
locator = page.locator("div")
await expect(locator).to_contain_class("")
await expect(locator).to_contain_class("bar")
await expect(locator).to_contain_class("baz bar")
await expect(locator).to_contain_class(" bar foo ")
await expect(locator).not_to_contain_class(
" baz not-matching "
) # Strip whitespace and match individual classes
with pytest.raises(AssertionError) as excinfo:
await expect(locator).to_contain_class("does-not-exist", timeout=100)
assert excinfo.match("Locator expected to contain class 'does-not-exist'")
assert excinfo.match("Actual value: foo bar baz")
assert excinfo.match('Expect "to_contain_class" with timeout 100ms')
await page.set_content(
'<div class="foo"></div><div class="hello bar"></div><div class="baz"></div>'
)
await expect(locator).to_contain_class(["foo", "hello", "baz"])
await expect(locator).not_to_contain_class(["not-there", "hello", "baz"])
await expect(locator).not_to_contain_class(["foo", "hello"])
async def test_assertions_locator_to_have_count(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div class=foobar>kek</div><div class=foobar>kek</div>")
await expect(page.locator("div.foobar")).to_have_count(2)
await expect(page.locator("div.foobar")).not_to_have_count(42, timeout=100)
with pytest.raises(AssertionError):
await expect(page.locator("div.foobar")).to_have_count(42, timeout=100)
async def test_assertions_locator_to_have_css(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content(
"<div class=foobar style='color: rgb(234, 74, 90);'>kek</div>"
)
await expect(page.locator("div.foobar")).to_have_css("color", "rgb(234, 74, 90)")
await expect(page.locator("div.foobar")).not_to_have_css(
"color", "rgb(42, 42, 42)", timeout=100
)
with pytest.raises(AssertionError):
await expect(page.locator("div.foobar")).to_have_css(
"color", "rgb(42, 42, 42)", timeout=100
)
async def test_assertions_locator_to_have_id(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div class=foobar id=kek>kek</div>")
await expect(page.locator("div.foobar")).to_have_id("kek")
await expect(page.locator("div.foobar")).not_to_have_id("top", timeout=100)
with pytest.raises(AssertionError):
await expect(page.locator("div.foobar")).to_have_id("top", timeout=100)
async def test_assertions_locator_to_have_js_property(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div></div>")
await page.eval_on_selector(
"div", "e => e.foo = { a: 1, b: 'string', c: new Date(1627503992000) }"
)
await expect(page.locator("div")).to_have_js_property(
"foo",
{
"a": 1,
"b": "string",
"c": datetime.datetime.fromtimestamp(1627503992000 / 1000),
},
)
async def test_to_have_js_property_pass_string(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = 'string'")
locator = page.locator("div")
await expect(locator).to_have_js_property("foo", "string")
async def test_to_have_js_property_fail_string(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = 'string'")
locator = page.locator("div")
with pytest.raises(AssertionError):
await expect(locator).to_have_js_property("foo", "error", timeout=500)
async def test_to_have_js_property_pass_number(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = 2021")
locator = page.locator("div")
await expect(locator).to_have_js_property("foo", 2021)
async def test_to_have_js_property_fail_number(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = 2021")
locator = page.locator("div")
with pytest.raises(AssertionError):
await expect(locator).to_have_js_property("foo", 1, timeout=500)
async def test_to_have_js_property_pass_boolean(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = true")
locator = page.locator("div")
await expect(locator).to_have_js_property("foo", True)
async def test_to_have_js_property_fail_boolean(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = false")
locator = page.locator("div")
with pytest.raises(AssertionError):
await expect(locator).to_have_js_property("foo", True, timeout=500)
async def test_to_have_js_property_pass_boolean_2(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = false")
locator = page.locator("div")
await expect(locator).to_have_js_property("foo", False)
async def test_to_have_js_property_fail_boolean_2(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = false")
locator = page.locator("div")
with pytest.raises(AssertionError):
await expect(locator).to_have_js_property("foo", True, timeout=500)
async def test_to_have_js_property_pass_null(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector("div", "e => e.foo = null")
locator = page.locator("div")
await expect(locator).to_have_js_property("foo", None)
async def test_assertions_locator_to_have_text(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div id=foobar>kek</div>")
await expect(page.locator("div#foobar")).to_have_text("kek")
await expect(page.locator("div#foobar")).not_to_have_text("top", timeout=100)
await page.set_content("<div>Text \n1</div><div>Text 2a</div>")
# Should only normalize whitespace in the first item.
await expect(page.locator("div")).to_have_text(
["Text 1", re.compile(r"Text \d+a")]
)
# Should work with a tuple
await expect(page.locator("div")).to_have_text(
("Text 1", re.compile(r"Text \d+a"))
)
@pytest.mark.parametrize(
"method",
["to_have_text", "to_contain_text"],
)
async def test_ignore_case(page: Page, server: Server, method: str) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div id=target>apple BANANA</div><div>orange</div>")
await getattr(expect(page.locator("div#target")), method)("apple BANANA")
await getattr(expect(page.locator("div#target")), method)(
"apple banana", ignore_case=True
)
# defaults false
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div#target")), method)(
"apple banana", timeout=300
)
expected_error_msg = method.replace("_", " ")
assert expected_error_msg in str(excinfo.value)
# Array Variants
await getattr(expect(page.locator("div")), method)(["apple BANANA", "orange"])
await getattr(expect(page.locator("div")), method)(
["apple banana", "ORANGE"], ignore_case=True
)
# defaults false
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div")), method)(
["apple banana", "ORANGE"], timeout=300
)
assert expected_error_msg in str(excinfo.value)
# not variant
await getattr(expect(page.locator("div#target")), f"not_{method}")("apple banana")
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div#target")), f"not_{method}")(
"apple banana", ignore_case=True, timeout=300
)
assert f"not {expected_error_msg}" in str(excinfo)
@pytest.mark.parametrize(
"method",
["to_have_text", "to_contain_text"],
)
async def test_ignore_case_regex(page: Page, server: Server, method: str) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div id=target>apple BANANA</div><div>orange</div>")
await getattr(expect(page.locator("div#target")), method)(
re.compile("apple BANANA")
)
await getattr(expect(page.locator("div#target")), method)(
re.compile("apple banana"), ignore_case=True
)
# defaults to regex flag
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div#target")), method)(
re.compile("apple banana"), timeout=300
)
expected_error_msg = method.replace("_", " ")
assert expected_error_msg in str(excinfo.value)
# overrides regex flag
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div#target")), method)(
re.compile("apple banana", re.IGNORECASE), ignore_case=False, timeout=300
)
assert expected_error_msg in str(excinfo.value)
# Array Variants
await getattr(expect(page.locator("div")), method)(
[re.compile("apple BANANA"), re.compile("orange")]
)
await getattr(expect(page.locator("div")), method)(
[re.compile("apple banana"), re.compile("ORANGE")], ignore_case=True
)
# defaults regex flag
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div")), method)(
[re.compile("apple banana"), re.compile("ORANGE")], timeout=300
)
assert expected_error_msg in str(excinfo.value)
# overrides regex flag
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div")), method)(
[
re.compile("apple banana", re.IGNORECASE),
re.compile("ORANGE", re.IGNORECASE),
],
ignore_case=False,
timeout=300,
)
assert expected_error_msg in str(excinfo.value)
# not variant
await getattr(expect(page.locator("div#target")), f"not_{method}")(
re.compile("apple banana")
)
with pytest.raises(AssertionError) as excinfo:
await getattr(expect(page.locator("div#target")), f"not_{method}")(
re.compile("apple banana"), ignore_case=True, timeout=300
)
assert f"not {expected_error_msg}" in str(excinfo)
async def test_assertions_locator_to_have_value(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<input type=text id=foo>")
my_input = page.locator("#foo")
await expect(my_input).to_have_value("")
await expect(my_input).not_to_have_value("bar", timeout=100)
await my_input.fill("kektus")
await expect(my_input).to_have_value("kektus")
async def test_to_have_values_works_with_text(page: Page, server: Server) -> None:
await page.set_content(
"""
<select multiple>
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
"""
)
locator = page.locator("select")
await locator.select_option(["R", "G"])
await expect(locator).to_have_values(["R", "G"])
async def test_to_have_values_follows_labels(page: Page, server: Server) -> None:
await page.set_content(
"""
<label for="colors">Pick a Color</label>
<select id="colors" multiple>
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
"""
)
locator = page.locator("text=Pick a Color")
await locator.select_option(["R", "G"])
await expect(locator).to_have_values(["R", "G"])
async def test_to_have_values_exact_match_with_text(page: Page, server: Server) -> None:
await page.set_content(
"""
<select multiple>
<option value="RR">Red</option>
<option value="GG">Green</option>
</select>
"""
)
locator = page.locator("select")
await locator.select_option(["RR", "GG"])
with pytest.raises(AssertionError) as excinfo:
await expect(locator).to_have_values(["R", "G"], timeout=500)
assert "Locator expected to have Values '['R', 'G']'" in str(excinfo.value)
assert "Actual value: ['RR', 'GG']" in str(excinfo.value)
async def test_to_have_values_works_with_regex(page: Page, server: Server) -> None:
await page.set_content(
"""
<select multiple>
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
"""
)
locator = page.locator("select")
await locator.select_option(["R", "G"])
await expect(locator).to_have_values([re.compile("R"), re.compile("G")])
async def test_to_have_values_fails_when_items_not_selected(
page: Page, server: Server
) -> None:
await page.set_content(
"""
<select multiple>
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
"""
)
locator = page.locator("select")
await locator.select_option(["B"])
with pytest.raises(AssertionError) as excinfo:
await expect(locator).to_have_values(["R", "G"], timeout=500)
assert "Locator expected to have Values '['R', 'G']'" in str(excinfo.value)
assert "Actual value: ['B']" in str(excinfo.value)
async def test_to_have_values_fails_when_multiple_not_specified(
page: Page, server: Server
) -> None:
await page.set_content(
"""
<select>
<option value="R">Red</option>
<option value="G">Green</option>
<option value="B">Blue</option>
</select>
"""
)
locator = page.locator("select")
await locator.select_option(["B"])
with pytest.raises(AssertionError) as excinfo:
await expect(locator).to_have_values(["R", "G"], timeout=500)
assert "Error: Not a select element with a multiple attribute" in str(excinfo.value)
async def test_to_have_values_fails_when_not_a_select_element(
page: Page, server: Server
) -> None:
await page.set_content(
"""
<input type="text">
"""
)
locator = page.locator("input")
with pytest.raises(AssertionError) as excinfo:
await expect(locator).to_have_values(["R", "G"], timeout=500)
assert "Error: Not a select element with a multiple attribute" in str(excinfo.value)
async def test_assertions_locator_to_be_checked(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<input type=checkbox>")
my_checkbox = page.locator("input")
await expect(my_checkbox).not_to_be_checked()
with pytest.raises(AssertionError, match="Locator expected to be checked"):
await expect(my_checkbox).to_be_checked(timeout=100)
await expect(my_checkbox).to_be_checked(timeout=100, checked=False)
with pytest.raises(AssertionError):
await expect(my_checkbox).to_be_checked(timeout=100, checked=True)
await my_checkbox.check()
await expect(my_checkbox).to_be_checked(timeout=100, checked=True)
with pytest.raises(AssertionError, match="Locator expected to be unchecked"):
await expect(my_checkbox).to_be_checked(timeout=100, checked=False)
await expect(my_checkbox).to_be_checked()
async def test_assertions_boolean_checked_with_intermediate_true(page: Page) -> None:
await page.set_content("<input type=checkbox></input>")
await page.locator("input").evaluate("e => e.indeterminate = true")
await expect(page.locator("input")).to_be_checked(indeterminate=True)
async def test_assertions_boolean_checked_with_intermediate_true_and_checked(
page: Page,
) -> None:
await page.set_content("<input type=checkbox></input>")
await page.locator("input").evaluate("e => e.indeterminate = true")
with pytest.raises(
AssertionError, match="Can't assert indeterminate and checked at the same time"
):
await expect(page.locator("input")).to_be_checked(
checked=False, indeterminate=True
)
async def test_assertions_boolean_fail_with_indeterminate_true(page: Page) -> None:
await page.set_content("<input type=checkbox></input>")
with pytest.raises(
AssertionError, match='Expect "to_be_checked" with timeout 1000ms'
):
await expect(page.locator("input")).to_be_checked(
indeterminate=True, timeout=1000
)
async def test_assertions_locator_to_be_disabled_enabled(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<input type=checkbox>")
my_checkbox = page.locator("input")
await expect(my_checkbox).not_to_be_disabled()
await expect(my_checkbox).to_be_enabled()
with pytest.raises(AssertionError):
await expect(my_checkbox).to_be_disabled(timeout=100)
await my_checkbox.evaluate("e => e.disabled = true")
await expect(my_checkbox).to_be_disabled()
with pytest.raises(AssertionError, match="Locator expected to be enabled"):
await expect(my_checkbox).to_be_enabled(timeout=100)
async def test_assertions_locator_to_be_enabled_with_true(page: Page) -> None:
await page.set_content("<button>Text</button>")
await expect(page.locator("button")).to_be_enabled(enabled=True)
async def test_assertions_locator_to_be_enabled_with_false_throws_good_exception(
page: Page,
) -> None:
await page.set_content("<button>Text</button>")
with pytest.raises(AssertionError, match="Locator expected to be disabled"):
await expect(page.locator("button")).to_be_enabled(enabled=False)
async def test_assertions_locator_to_be_enabled_with_false(page: Page) -> None:
await page.set_content("<button disabled>Text</button>")
await expect(page.locator("button")).to_be_enabled(enabled=False)
async def test_assertions_locator_to_be_enabled_with_not_and_false(page: Page) -> None:
await page.set_content("<button>Text</button>")
await expect(page.locator("button")).not_to_be_enabled(enabled=False)
async def test_assertions_locator_to_be_enabled_eventually(page: Page) -> None:
await page.set_content("<button disabled>Text</button>")
await page.eval_on_selector(
"button",
"""
button => setTimeout(() => {
button.removeAttribute('disabled');
}, 700);
""",
)
await expect(page.locator("button")).to_be_enabled()
async def test_assertions_locator_to_be_enabled_eventually_with_not(page: Page) -> None:
await page.set_content("<button>Text</button>")
await page.eval_on_selector(
"button",
"""
button => setTimeout(() => {
button.setAttribute('disabled', '');
}, 700);
""",
)
await expect(page.locator("button")).not_to_be_enabled()
async def test_assertions_locator_to_be_editable(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<input></input>")
await expect(page.locator("input")).to_be_editable()
async def test_assertions_locator_to_be_editable_throws(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<button disabled>Text</button>")
with pytest.raises(
AssertionError,
match=r"Element is not an <input>, <textarea>, <select> or \[contenteditable\] and does not have a role allowing \[aria-readonly\]",
):
await expect(page.locator("button")).not_to_be_editable()
async def test_assertions_locator_to_be_editable_with_true(page: Page) -> None:
await page.set_content("<input></input>")
await expect(page.locator("input")).to_be_editable(editable=True)
async def test_assertions_locator_to_be_editable_with_false(page: Page) -> None:
await page.set_content("<input readonly></input>")
await expect(page.locator("input")).to_be_editable(editable=False)
async def test_assertions_locator_to_be_editable_with_false_and_throw_good_exception(
page: Page,
) -> None:
await page.set_content("<input></input>")
with pytest.raises(AssertionError, match="Locator expected to be readonly"):
await expect(page.locator("input")).to_be_editable(editable=False)
async def test_assertions_locator_to_be_editable_with_not_and_false(page: Page) -> None:
await page.set_content("<input></input>")
await expect(page.locator("input")).not_to_be_editable(editable=False)
async def test_assertions_locator_to_be_empty(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content(
"<input value=text name=input1></input><input name=input2></input>"
)
await expect(page.locator("input[name=input1]")).not_to_be_empty()
await expect(page.locator("input[name=input2]")).to_be_empty()
with pytest.raises(AssertionError):
await expect(page.locator("input[name=input1]")).to_be_empty(timeout=100)
async def test_assertions_locator_to_be_focused(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<input type=checkbox>")
my_checkbox = page.locator("input")
with pytest.raises(AssertionError):
await expect(my_checkbox).to_be_focused(timeout=100)
await my_checkbox.focus()
await expect(my_checkbox).to_be_focused()
async def test_assertions_locator_to_be_hidden_visible(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div style='width: 50px; height: 50px;'>Something</div>")
my_checkbox = page.locator("div")
await expect(my_checkbox).to_be_visible()
with pytest.raises(AssertionError):
await expect(my_checkbox).to_be_hidden(timeout=100)
await my_checkbox.evaluate("e => e.style.display = 'none'")
await expect(my_checkbox).to_be_hidden()
with pytest.raises(AssertionError, match="Locator expected to be visible"):
await expect(my_checkbox).to_be_visible(timeout=100)
async def test_assertions_locator_to_be_visible_with_true(page: Page) -> None:
await page.set_content("<button>hello</button>")
await expect(page.locator("button")).to_be_visible(visible=True)
async def test_assertions_locator_to_be_visible_with_false(page: Page) -> None:
await page.set_content("<button hidden>hello</button>")
await expect(page.locator("button")).to_be_visible(visible=False)
async def test_assertions_locator_to_be_visible_with_false_throws_good_exception(
page: Page,
) -> None:
await page.set_content("<button>hello</button>")
with pytest.raises(AssertionError, match="Locator expected to be hidden"):
await expect(page.locator("button")).to_be_visible(visible=False)
async def test_assertions_locator_to_be_visible_with_not_and_false(page: Page) -> None:
await page.set_content("<button>hello</button>")
await expect(page.locator("button")).not_to_be_visible(visible=False)
async def test_assertions_locator_to_be_visible_eventually(page: Page) -> None:
await page.set_content("<div></div>")
await page.eval_on_selector(
"div",
"""
div => setTimeout(() => {
div.innerHTML = '<span>Hello</span>';
}, 700);
""",
)
await expect(page.locator("span")).to_be_visible()
async def test_assertions_locator_to_be_visible_eventually_with_not(page: Page) -> None:
await page.set_content("<div><span>Hello</span></div>")
await page.eval_on_selector(
"span",
"""
span => setTimeout(() => {
span.textContent = '';
}, 700);
""",
)
await expect(page.locator("span")).not_to_be_visible()
async def test_assertions_should_serialize_regexp_correctly(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<div>iGnOrEcAsE</div>")
await expect(page.locator("div")).to_have_text(
re.compile(r"ignorecase", re.IGNORECASE)
)
await page.set_content(
"""<div>start
some
lines
between
end</div>"""
)
await expect(page.locator("div")).to_have_text(re.compile(r"start.*end", re.DOTALL))
await page.set_content(
"""<div>line1
line2
line3</div>"""
)
await expect(page.locator("div")).to_have_text(re.compile(r"^line2$", re.MULTILINE))
async def test_assertions_response_is_ok_pass(page: Page, server: Server) -> None:
response = await page.request.get(server.EMPTY_PAGE)
await expect(response).to_be_ok()
async def test_assertions_response_is_ok_pass_with_not(
page: Page, server: Server
) -> None:
response = await page.request.get(server.PREFIX + "/unknown")
await expect(response).not_to_be_ok()
async def test_assertions_response_is_ok_fail(page: Page, server: Server) -> None:
response = await page.request.get(server.PREFIX + "/unknown")
with pytest.raises(AssertionError) as excinfo:
await expect(response).to_be_ok()
error_message = str(excinfo.value)
assert ("→ GET " + server.PREFIX + "/unknown") in error_message
assert "← 404 Not Found" in error_message
async def test_should_print_response_with_text_content_type_if_to_be_ok_fails(
page: Page, server: Server
) -> None:
server.set_route(
"/text-content-type",
lambda r: (
r.setResponseCode(404),
r.setHeader("content-type", "text/plain"),
r.write(b"Text error"),
r.finish(),
),
)
server.set_route(
"/no-content-type",
lambda r: (
r.setResponseCode(404),
r.write(b"No content type error"),
r.finish(),
),
)
server.set_route(
"/binary-content-type",
lambda r: (
r.setResponseCode(404),
r.setHeader("content-type", "image/bmp"),
r.write(b"Image content type error"),
r.finish(),
),
)
response = await page.request.get(server.PREFIX + "/text-content-type")
with pytest.raises(AssertionError) as excinfo:
await expect(response).to_be_ok()
error_message = str(excinfo.value)
assert ("→ GET " + server.PREFIX + "/text-content-type") in error_message
assert "← 404 Not Found" in error_message
assert "Response Text:" in error_message
assert "Text error" in error_message
response = await page.request.get(server.PREFIX + "/no-content-type")
with pytest.raises(AssertionError) as excinfo:
await expect(response).to_be_ok()
error_message = str(excinfo.value)
assert ("→ GET " + server.PREFIX + "/no-content-type") in error_message
assert "← 404 Not Found" in error_message
assert "Response Text:" not in error_message
assert "No content type error" not in error_message
response = await page.request.get(server.PREFIX + "/binary-content-type")
with pytest.raises(AssertionError) as excinfo:
await expect(response).to_be_ok()
error_message = str(excinfo.value)
assert ("→ GET " + server.PREFIX + "/binary-content-type") in error_message
assert "← 404 Not Found" in error_message
assert "Response Text:" not in error_message
assert "Image content type error" not in error_message
async def test_should_print_users_message_for_page_based_assertion(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<title>new title</title>")
with pytest.raises(AssertionError) as excinfo:
await expect(page, "Title is not new").to_have_title("old title", timeout=100)
assert "Title is not new" in str(excinfo.value)
with pytest.raises(AssertionError) as excinfo:
await expect(page).to_have_title("old title", timeout=100)
assert "Page title expected to be" in str(excinfo.value)
async def test_should_print_expected_value_with_custom_message(
page: Page, server: Server
) -> None:
await page.goto(server.EMPTY_PAGE)
await page.set_content("<title>new title</title>")
with pytest.raises(AssertionError) as excinfo:
await expect(page, "custom-message").to_have_title("old title", timeout=100)
assert "custom-message" in str(excinfo.value)
assert "Expected value: 'old title'" in str(excinfo.value)
with pytest.raises(AssertionError) as excinfo:
await expect(page.get_by_text("hello"), "custom-message").to_be_visible(
timeout=100
)
assert "custom-message" in str(excinfo.value)
assert "Expected value" not in str(excinfo.value)
async def test_should_be_attached_default(page: Page) -> None:
await page.set_content("<input></input>")
locator = page.locator("input")
await expect(locator).to_be_attached()
async def test_should_be_attached_with_hidden_element(page: Page) -> None:
await page.set_content('<button style="display:none">hello</button>')
locator = page.locator("button")
await expect(locator).to_be_attached()
async def test_should_be_attached_with_not(page: Page) -> None:
await page.set_content("<button>hello</button>")
locator = page.locator("input")
await expect(locator).not_to_be_attached()
async def test_should_be_attached_with_attached_true(page: Page) -> None:
await page.set_content("<button>hello</button>")
locator = page.locator("button")
await expect(locator).to_be_attached(attached=True)
async def test_should_be_attached_with_attached_false(page: Page) -> None:
await page.set_content("<button>hello</button>")
locator = page.locator("input")
await expect(locator).to_be_attached(attached=False)
async def test_should_be_attached_with_attached_false_and_throw_good_error(
page: Page,
) -> None:
await page.set_content("<button>hello</button>")
locator = page.locator("button")
with pytest.raises(AssertionError, match="Locator expected to be detached"):
await expect(locator).to_be_attached(attached=False, timeout=1)
async def test_should_be_attached_with_not_and_attached_false(page: Page) -> None:
await page.set_content("<button>hello</button>")
locator = page.locator("button")
await expect(locator).not_to_be_attached(attached=False)
async def test_should_be_attached_eventually(page: Page) -> None:
await page.set_content("<div></div>")
locator = page.locator("span")
await page.locator("div").evaluate(
"(e) => setTimeout(() => e.innerHTML = '<span>hello</span>', 1000)"
)
await expect(locator).to_be_attached()
async def test_should_be_attached_eventually_with_not(page: Page) -> None:
await page.set_content("<div><span>Hello</span></div>")
locator = page.locator("span")
await page.locator("div").evaluate(
"(e) => setTimeout(() => e.textContent = '', 1000)"
)
await expect(locator).not_to_be_attached()
async def test_should_be_attached_fail(page: Page) -> None:
await page.set_content("<button>Hello</button>")
locator = page.locator("input")
with pytest.raises(
AssertionError, match="Locator expected to be attached"
) as exc_info:
await expect(locator).to_be_attached(timeout=1000)
assert "locator resolved to" not in exc_info.value.args[0]
async def test_should_be_attached_fail_with_not(page: Page) -> None:
await page.set_content("<input></input>")
locator = page.locator("input")
with pytest.raises(AssertionError) as exc_info:
await expect(locator).not_to_be_attached(timeout=1000)
assert "locator resolved to <input/>" in exc_info.value.args[0]
async def test_should_be_attached_with_impossible_timeout(page: Page) -> None:
await page.set_content("<div id=node>Text content</div>")
await expect(page.locator("#node")).to_be_attached(timeout=1)
async def test_should_be_attached_with_impossible_timeout_not(page: Page) -> None:
await page.set_content("<div id=node>Text content</div>")
await expect(page.locator("no-such-thing")).not_to_be_attached(timeout=1)
async def test_should_be_attached_with_frame_locator(page: Page) -> None:
await page.set_content("<div></div>")
locator = page.frame_locator("iframe").locator("input")
task = asyncio.create_task(expect(locator).to_be_attached())
await page.wait_for_timeout(1000)
assert not task.done()
await page.set_content('<iframe srcdoc="<input>"></iframe>')
await task
assert task.done()
async def test_should_be_attached_over_navigation(page: Page, server: Server) -> None:
await page.goto(server.EMPTY_PAGE)
task = asyncio.create_task(expect(page.locator("input")).to_be_attached())
await page.wait_for_timeout(1000)
assert not task.done()
await page.goto(server.PREFIX + "/input/checkbox.html")
await task
assert task.done()
async def test_should_be_able_to_set_custom_timeout(page: Page) -> None:
with pytest.raises(AssertionError) as exc_info:
await expect(page.locator("#a1")).to_be_visible(timeout=111)
assert 'Expect "to_be_visible" with timeout 111ms' in str(exc_info.value)
async def test_should_be_able_to_set_custom_global_timeout(page: Page) -> None:
try:
expect.set_options(timeout=111)
with pytest.raises(AssertionError) as exc_info:
await expect(page.locator("#a1")).to_be_visible()
assert 'Expect "to_be_visible" with timeout 111ms' in str(exc_info.value)
finally:
expect.set_options(timeout=None)
async def test_to_have_accessible_name(page: Page) -> None:
await page.set_content('<div role="button" aria-label="Hello"></div>')
locator = page.locator("div")
await expect(locator).to_have_accessible_name("Hello")
await expect(locator).not_to_have_accessible_name("hello")
await expect(locator).to_have_accessible_name("hello", ignore_case=True)
await expect(locator).to_have_accessible_name(re.compile(r"ell\w"))
await expect(locator).not_to_have_accessible_name(re.compile(r"hello"))
await expect(locator).to_have_accessible_name(
re.compile(r"hello"), ignore_case=True
)
await page.set_content("<button>foo&nbsp;bar\nbaz</button>")
await expect(page.locator("button")).to_have_accessible_name("foo bar baz")
async def test_to_have_accessible_error_message(page: Page) -> None:
await page.set_content(
"""
<form>
<input role="textbox" aria-invalid="true" aria-errormessage="error-message" />
<div id="error-message">Hello</div>
<div id="irrelevant-error">This should not be considered.</div>
</form>
"""
)
locator = page.locator('input[role="textbox"]')
await expect(locator).to_have_accessible_error_message("Hello")
await expect(locator).not_to_have_accessible_error_message("hello")
await expect(locator).to_have_accessible_error_message("hello", ignore_case=True)
await expect(locator).to_have_accessible_error_message(re.compile(r"ell\w"))
await expect(locator).not_to_have_accessible_error_message(re.compile(r"hello"))
await expect(locator).to_have_accessible_error_message(
re.compile(r"hello"), ignore_case=True
)
await expect(locator).not_to_have_accessible_error_message(
"This should not be considered."
)
async def test_to_have_accessible_error_message_should_handle_multiple_aria_error_message_references(
page: Page,
) -> None:
await page.set_content(
"""
<form>
<input role="textbox" aria-invalid="true" aria-errormessage="error1 error2" />
<div id="error1">First error message.</div>
<div id="error2">Second error message.</div>
<div id="irrelevant-error">This should not be considered.</div>
</form>
"""
)
locator = page.locator('input[role="textbox"]')
await expect(locator).to_have_accessible_error_message(
"First error message. Second error message."
)
await expect(locator).to_have_accessible_error_message(
re.compile(r"first error message.", re.IGNORECASE)
)
await expect(locator).to_have_accessible_error_message(
re.compile(r"second error message.", re.IGNORECASE)
)
await expect(locator).not_to_have_accessible_error_message(
re.compile(r"This should not be considered.", re.IGNORECASE)
)
async def test_to_have_accessible_description(page: Page) -> None:
await page.set_content('<div role="button" aria-description="Hello"></div>')
locator = page.locator("div")
await expect(locator).to_have_accessible_description("Hello")
await expect(locator).not_to_have_accessible_description("hello")
await expect(locator).to_have_accessible_description("hello", ignore_case=True)
await expect(locator).to_have_accessible_description(re.compile(r"ell\w"))
await expect(locator).not_to_have_accessible_description(re.compile(r"hello"))
await expect(locator).to_have_accessible_description(
re.compile(r"hello"), ignore_case=True
)
await page.set_content(
"""
<div role="button" aria-describedby="desc"></div>
<span id="desc">foo&nbsp;bar\nbaz</span>
"""
)
await expect(page.locator("div")).to_have_accessible_description("foo bar baz")
async def test_to_have_role(page: Page) -> None:
await page.set_content('<div role="button">Button!</div>')
await expect(page.locator("div")).to_have_role("button")
await expect(page.locator("div")).not_to_have_role("checkbox")
with pytest.raises(Error) as excinfo:
await expect(page.locator("div")).to_have_role(re.compile(r"button|checkbox")) # type: ignore
assert '"role" argument in to_have_role must be a string' in str(excinfo.value)
async def test_soft_outside_scope_raises_runtime_error(
page: Page, server: Server
) -> None:
await page.set_content("<div>hello</div>")
with pytest.raises(RuntimeError, match="pytest-playwright"):
await expect.soft(page.locator("div")).to_have_text("nope", timeout=500)
async def test_soft_inside_scope_collects_failures(page: Page, server: Server) -> None:
from playwright._impl._assertions import _soft_scope
await page.goto(server.EMPTY_PAGE)
await page.set_content("<title>actual</title><div>hello</div>")
with _soft_scope() as errors:
# should collect, not raise
await expect.soft(page).to_have_title("expected", timeout=500)
await expect.soft(page.locator("div")).to_have_text("goodbye", timeout=500)
# passing soft should not affect the collector
await expect.soft(page.locator("div")).to_have_text("hello")
# nested .not_ should still be soft
await expect.soft(page.locator("div")).not_to_have_text("hello", timeout=500)
assert len(errors) == 3
assert all(isinstance(e, AssertionError) for e in errors)
async def test_soft_does_not_leak_between_scopes(page: Page, server: Server) -> None:
from playwright._impl._assertions import _soft_scope
await page.goto(server.EMPTY_PAGE)
await page.set_content("<title>actual</title>")
with _soft_scope() as errors_a:
await expect.soft(page).to_have_title("nope", timeout=500)
assert len(errors_a) == 1
with _soft_scope() as errors_b:
pass
assert errors_b == []
# After scope ends, soft assertions raise RuntimeError again.
await page.set_content("<div>hello</div>")
with pytest.raises(RuntimeError, match="pytest-playwright"):
await expect.soft(page.locator("div")).to_have_text("nope", timeout=500)