From fa7f162a417eea3e8f82bdd5a5408424dd8f9b5a Mon Sep 17 00:00:00 2001 From: JAYA DILEEP Date: Sat, 5 Sep 2026 08:05:23 +0000 Subject: [PATCH] feat: add hasAttribute(name) for attribute presence assertions Add LocatorAssertions.hasAttribute(String name) and options overload so users can assert attribute presence/absence, matching Node's presence-only toHaveAttribute(name). Uses expect expression "to.have.attribute" with expressionArg set to the attribute name. Signed-off-by: JAYA DILEEP --- .../assertions/LocatorAssertions.java | 30 +++++++++++++++++++ .../impl/LocatorAssertionsImpl.java | 12 ++++++++ .../playwright/TestLocatorAssertions.java | 21 +++++++++++++ 3 files changed, 63 insertions(+) diff --git a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java index 780b87751..2c4db2a5b 100644 --- a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java +++ b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java @@ -1565,6 +1565,36 @@ default void hasAttribute(String name, Pattern value) { * @since v1.20 */ void hasAttribute(String name, Pattern value, HasAttributeOptions options); + /** + * Ensures the {@code Locator} points to an element with given attribute. When only the attribute name is provided, the + * method asserts attribute presence. + * + *

Usage + *

{@code
+   * assertThat(page.locator("input")).hasAttribute("disabled");
+   * assertThat(page.locator("input")).not().hasAttribute("open");
+   * }
+ * + * @param name Attribute name. + * @since v1.62 + */ + default void hasAttribute(String name) { + hasAttribute(name, (HasAttributeOptions) null); + } + /** + * Ensures the {@code Locator} points to an element with given attribute. When only the attribute name is provided, the + * method asserts attribute presence. + * + *

Usage + *

{@code
+   * assertThat(page.locator("input")).hasAttribute("disabled");
+   * assertThat(page.locator("input")).not().hasAttribute("open");
+   * }
+ * + * @param name Attribute name. + * @since v1.62 + */ + void hasAttribute(String name, HasAttributeOptions options); /** * Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match * the element's {@code class} attribute. To match individual classes use {@link diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java index 088910c98..4e107d00a 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java @@ -190,6 +190,18 @@ private void hasAttribute(String name, ExpectedTextValue expectedText, Object ex expectImpl("to.have.attribute.value", expectedText, expectedValue, message, commonOptions, "Assert \"hasAttribute\""); } + @Override + public void hasAttribute(String name, HasAttributeOptions options) { + if (options == null) { + options = new HasAttributeOptions(); + } + FrameExpectOptions commonOptions = convertType(options, FrameExpectOptions.class); + commonOptions.expressionArg = name; + String message = "Locator expected to have attribute '" + name + "'"; + List expectedText = null; + expectImpl("to.have.attribute", expectedText, null, message, commonOptions, "Assert \"hasAttribute\""); + } + @Override public void hasClass(String text, HasClassOptions options) { ExpectedTextValue expected = new ExpectedTextValue(); diff --git a/playwright/src/test/java/com/microsoft/playwright/TestLocatorAssertions.java b/playwright/src/test/java/com/microsoft/playwright/TestLocatorAssertions.java index 27fa7dc2f..a82195e28 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestLocatorAssertions.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestLocatorAssertions.java @@ -294,6 +294,27 @@ void hasAttributeRegExpFail() { assertTrue(e.getMessage().contains("Locator expected to have attribute 'id' matching regex\nExpected: .Nod..\nReceived: node"), e.getMessage()); } + @Test + void hasAttributeNamePass() { + page.setContent("
Text content
"); + Locator locator = page.locator("#node"); + assertThat(locator).hasAttribute("id"); + assertThat(locator).hasAttribute("checked"); + assertThat(locator).not().hasAttribute("open"); + } + + @Test + void hasAttributeNameFail() { + page.setContent("
Text content
"); + Locator locator = page.locator("#node"); + AssertionFailedError e = assertThrows(AssertionFailedError.class, + () -> assertThat(locator).hasAttribute("disabled", new LocatorAssertions.HasAttributeOptions().setTimeout(1000))); + assertTrue(e.getMessage().contains("Locator expected to have attribute 'disabled'"), e.getMessage()); + e = assertThrows(AssertionFailedError.class, + () -> assertThat(locator).not().hasAttribute("checked", new LocatorAssertions.HasAttributeOptions().setTimeout(1000))); + assertTrue(e.getMessage().contains("Locator expected not to have attribute 'checked'"), e.getMessage()); + } + @Test void hasClassTextPass() { page.setContent("
");