Search code examples
pythonplaywright-python

Python Playwright - How can I check that an element does not have an href?


As part of my automated testing I'm trying to validate that an href is correctly removed from an element on the page.

from playwright.sync_api import Page, expect

def test_reset_button(page: Page):
    page.goto("https://www.example.com")
    page.locator("#reset").click()
    expect(page.locator("#download")).not_to_have_attribute("href", value="")

In my example code above it ends up testing that the href attribute on the element is not equal to value="", which means that if value="nonsense" this test will pass.

Based on the not_to_have_attribute documentation it seems that you have to pass a value to it to test that it does not have that specific value. I'd like to test that the "href" attribute does not exist on the element at all.

How can I test for that?


Solution

  • You can use the regex .| to test attribute presence, including both href="something" and href="". The "" case is handled by the empty string on the right of the alternation pipe. You could read the pattern as "match either something or nothing" (i.e. all possible strings).

    import re
    from playwright.sync_api import expect, Page, sync_playwright  # 1.37.0
    
    
    sample_html = """<!DOCTYPE html>
    <button id="reset">reset</button>
    <a id="download" href="nonsense">download</a>
    <script>
    document.querySelector("#reset").addEventListener("click", () => {
      document.querySelector("#download").removeAttribute("href");
    });
    </script>"""
    
    
    def test_reset_button(page: Page):
        page.set_content(sample_html)
        dl = page.locator("#download")
    
        # assert that there is an href present initially
        expect(dl).to_have_attribute("href", re.compile(r".|"))
    
        # trigger an event to remove the href
        page.locator("#reset").click()
    
        # assert that there is no longer an href present after the click
        expect(dl).not_to_have_attribute("href", re.compile(r".|"))
    
    
    
    def main():
        with sync_playwright() as p:
            browser = p.chromium.launch()
            test_reset_button(browser.new_page())
            browser.close()
    
    
    if __name__ == "__main__":
        main()
    

    re.compile is important. Using ".|" or "/.|/" would treat it as a literal string to test equality against.

    Another approach is to query the element, store the exact href in a variable, click the button to remove the href, then assert that the exact href you saved before is no longer present. This would give a false positive if the href changed to something else, but it seems worth mentioning since it may be useful in certain cases.