Search code examples
javascriptpythonchromiumplaywrightplaywright-python

Playwright Python : How do I get the warning element that is displayed only when mouse is hovered over another input element?


I have an input field, which when hovered over, shows a warning with a text. Now I want to get this warning element, and eventually perform a test like expect(warning_element).to_have_text("Please enter a valid value.").

Code to Reproduce :

**app.py : **

from flask import Flask

app = Flask(__name__)


@app.route('/')
def serve_html():
    html_content = """
    <!DOCTYPE html>
<html>
<head>
  <style>
    .warning {
      display: block;
      color: red;
      font-size: 14px;
    }
  </style>
</head>
<body>
  <label for="inputField">Text Input:</label>
  <input type="text" id="inputField">

  <script>
    const inputField = document.getElementById('inputField');
    let warningMessage;

    inputField.addEventListener('mouseover', () => {
      if (!warningMessage) {
        warningMessage = document.createElement('p');
        warningMessage.classList.add('warning');
        warningMessage.textContent = 'Please enter a valid value.';
        inputField.insertAdjacentElement('afterend', warningMessage);
      } else {
        warningMessage.style.display = 'block';
      }
    });

    inputField.addEventListener('mouseout', () => {
      if (warningMessage) {
        warningMessage.style.display = 'none';
        warningMessage.remove();
        warningMessage = undefined;
      }
    });
  </script>
</body>
</html>
    """
    return html_content


if __name__ == '__main__':
    app.run()

**test_hover.py : **

from playwright.sync_api import sync_playwright

def test_hover_element():
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto("http://127.0.0.1:5000/")
        # Add code to locate the input field and hover over it
        input_field_selector = 'input#inputField'
        input_field = page.wait_for_selector(input_field_selector)
        input_field.hover()
        page.wait_for_timeout(5000)
        # Add code to wait for the additional text element to appear
        additional_text_selector = '.warning'
        additional_text = page.wait_for_selector(additional_text_selector)

        # Check if the additional text element is displayed
        is_displayed = additional_text.is_visible()
        if is_displayed:
            print("Additional text is displayed on hover!")
        else:
            print("Additional text is not displayed on hover.")

        browser.close()

test_hover_element()

Additional Details : Python 3.11.3 Playwright Version 1.35.0

When I tried to run the above provided code, it gives a playwright._impl._api_types.TimeoutError: Timeout 30000ms exceeded. .

The logs also mention :

waiting for locator(".warning") to be visible

One more thing, I did this in both headless=True and headless=False mode. In headless=False, I can see that the warning is not being displayed. However, when I manually move the mouse over the input, I can see the hover text and in that case, the test run succeeds. However, that defeats the purpose of using playwright for automation.

Also, note that I added page.wait_for_timeout(5000) just to see if warning text is displayed in headless=False mode.

Additionally, instead of using input_field.hover(), I also tried :

1)

box = input_field.bounding_box()
page.mouse.move(box["x"]+box["width"]/2, box["y"]+box["height"]/2)
box = input_field.bounding_box()
page.mouse.click(box["x"]+box["width"]/2, box["y"]+box["height"]/2)

input_field.dispatch_event('hover')


Solution

  • I modified your code to use locator instead of wait_for_selector, which is not necessary as the locator() method automatically waits for the selector to be visible. It seems to run and execute as expected, both headed and headless. I also added an expect to have text.

    from playwright.sync_api import sync_playwright, expect
    
    
    def test_hover_element():
        with sync_playwright() as playwright:
            browser = playwright.chromium.launch(headless=False)
            page = browser.new_page()
            page.goto('http://127.0.0.1:5000/')
    
            input_field = page.locator('input#inputField')
            warning_text = page.locator('.warning')
    
            input_field.hover()
    
            if warning_text.is_visible():
                print('Additional text is displayed on hover!')
                expect(warning_text).to_have_text('Please enter a valid value.')
            else:
                print('Additional text is not displayed on hover.')
    
            browser.close()
    
    
    test_hover_element()