Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions playwright/_impl/_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,20 @@ async def not_to_contain_text(
async def to_have_attribute(
self,
name: str,
value: Union[str, Pattern[str]],
value: Union[Pattern[str], str] = None,
ignoreCase: bool = None,
timeout: float = None,
) -> None:
__tracebackhide__ = True
if value is None:
await self._expect_impl(
"to.have.attribute",
FrameExpectOptions(expressionArg=name, timeout=timeout),
None,
"Locator expected to have attribute",
'Expect "to_have_attribute"',
)
return
expected_text = to_expected_text_values([value], ignoreCase=ignoreCase)
await self._expect_impl(
"to.have.attribute.value",
Expand All @@ -348,7 +357,7 @@ async def to_have_attribute(
async def not_to_have_attribute(
self,
name: str,
value: Union[str, Pattern[str]],
value: Union[Pattern[str], str] = None,
ignoreCase: bool = None,
timeout: float = None,
) -> None:
Expand Down
14 changes: 8 additions & 6 deletions playwright/async_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -21684,7 +21684,7 @@ async def not_to_contain_text(
async def to_have_attribute(
self,
name: str,
value: typing.Union[str, typing.Pattern[str]],
value: typing.Optional[typing.Union[typing.Pattern[str], str]] = None,
*,
ignore_case: typing.Optional[bool] = None,
timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None,
Expand All @@ -21700,14 +21700,16 @@ async def to_have_attribute(

locator = page.locator(\"input\")
await expect(locator).to_have_attribute(\"type\", \"text\")
await expect(locator).to_have_attribute(\"disabled\")
await expect(locator).not_to_have_attribute(\"readonly\")
```

Parameters
----------
name : str
Attribute name.
value : Union[Pattern[str], str]
Expected attribute value.
value : Union[Pattern[str], str, None]
Expected attribute value. If not specified, the assertion verifies that the attribute is present.
ignore_case : Union[bool, None]
Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular
expression flag if specified.
Expand All @@ -21728,7 +21730,7 @@ async def to_have_attribute(
async def not_to_have_attribute(
self,
name: str,
value: typing.Union[str, typing.Pattern[str]],
value: typing.Optional[typing.Union[typing.Pattern[str], str]] = None,
*,
ignore_case: typing.Optional[bool] = None,
timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None,
Expand All @@ -21741,8 +21743,8 @@ async def not_to_have_attribute(
----------
name : str
Attribute name.
value : Union[Pattern[str], str]
Expected attribute value.
value : Union[Pattern[str], str, None]
Expected attribute value. If not specified, the assertion verifies that the attribute is absent.
ignore_case : Union[bool, None]
Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular
expression flag if specified.
Expand Down
14 changes: 8 additions & 6 deletions playwright/sync_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -21758,7 +21758,7 @@ def not_to_contain_text(
def to_have_attribute(
self,
name: str,
value: typing.Union[str, typing.Pattern[str]],
value: typing.Optional[typing.Union[typing.Pattern[str], str]] = None,
*,
ignore_case: typing.Optional[bool] = None,
timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None,
Expand All @@ -21774,14 +21774,16 @@ def to_have_attribute(

locator = page.locator(\"input\")
expect(locator).to_have_attribute(\"type\", \"text\")
expect(locator).to_have_attribute(\"disabled\")
expect(locator).not_to_have_attribute(\"readonly\")
```

Parameters
----------
name : str
Attribute name.
value : Union[Pattern[str], str]
Expected attribute value.
value : Union[Pattern[str], str, None]
Expected attribute value. If not specified, the assertion verifies that the attribute is present.
ignore_case : Union[bool, None]
Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular
expression flag if specified.
Expand All @@ -21804,7 +21806,7 @@ def to_have_attribute(
def not_to_have_attribute(
self,
name: str,
value: typing.Union[str, typing.Pattern[str]],
value: typing.Optional[typing.Union[typing.Pattern[str], str]] = None,
*,
ignore_case: typing.Optional[bool] = None,
timeout: typing.Optional[typing.Union[float, datetime.timedelta]] = None,
Expand All @@ -21817,8 +21819,8 @@ def not_to_have_attribute(
----------
name : str
Attribute name.
value : Union[Pattern[str], str]
Expected attribute value.
value : Union[Pattern[str], str, None]
Expected attribute value. If not specified, the assertion verifies that the attribute is absent.
ignore_case : Union[bool, None]
Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular
expression flag if specified.
Expand Down
2 changes: 2 additions & 0 deletions scripts/generate_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,12 @@ def process_type(value: Any, param: bool = False) -> str:
r"expect_.*\.predicate",
r"evaluate_handle\.arg",
r"frame.*\.name",
r"not_to_have_attribute\.value",
r"register\.script",
r"select_option\.value",
r"send\.params",
r"set_geolocation\.geolocation",
r"to_have_attribute\.value",
r"wait_for_.*\.predicate",
r"wait_for_load_state\.state",
r"unroute\.handler",
Expand Down
23 changes: 12 additions & 11 deletions tests/async/test_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,19 @@ async def test_assertions_locator_to_contain_text_should_throw_if_arg_is_unsuppo

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
)
await page.set_content("<div id=foobar checked>kek</div>")
locator = page.locator("div#foobar")
await expect(locator).to_have_attribute("checked")
await expect(locator).not_to_have_attribute("open", timeout=100)
await expect(locator).to_have_attribute("id", "foobar")
await expect(locator).to_have_attribute("id", re.compile("foobar"))
await expect(locator).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
)
await expect(locator).to_have_attribute("open", timeout=100)
with pytest.raises(AssertionError):
await expect(locator).not_to_have_attribute("checked", timeout=100)
with pytest.raises(AssertionError):
await expect(locator).to_have_attribute("id", "koko", timeout=100)


async def test_assertions_locator_to_have_attribute_ignore_case(
Expand Down
17 changes: 12 additions & 5 deletions tests/sync/test_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,19 @@ def test_assertions_locator_to_contain_text(page: Page, server: Server) -> None:

def test_assertions_locator_to_have_attribute(page: Page, server: Server) -> None:
page.goto(server.EMPTY_PAGE)
page.set_content("<div id=foobar>kek</div>")
expect(page.locator("div#foobar")).to_have_attribute("id", "foobar")
expect(page.locator("div#foobar")).to_have_attribute("id", re.compile("foobar"))
expect(page.locator("div#foobar")).not_to_have_attribute("id", "kek", timeout=100)
page.set_content("<div id=foobar checked>kek</div>")
locator = page.locator("div#foobar")
expect(locator).to_have_attribute("checked")
expect(locator).not_to_have_attribute("open", timeout=100)
expect(locator).to_have_attribute("id", "foobar")
expect(locator).to_have_attribute("id", re.compile("foobar"))
expect(locator).not_to_have_attribute("id", "kek", timeout=100)
with pytest.raises(AssertionError):
expect(locator).to_have_attribute("open", timeout=100)
with pytest.raises(AssertionError):
expect(locator).not_to_have_attribute("checked", timeout=100)
with pytest.raises(AssertionError):
expect(page.locator("div#foobar")).to_have_attribute("id", "koko", timeout=100)
expect(locator).to_have_attribute("id", "koko", timeout=100)


def test_assertions_locator_to_have_attribute_ignore_case(
Expand Down