小能豆

how to check multiple element and use it in "if else condition" in playwright

py

i want to automate a website using playwright, the scenario is;

  • first page is login page, after i successfully login, it direct me to https://example.com/verify_id
  • in verify_id page there is 1 text form and 1 submit button, the form is to use to verify id number
  • when i submit id, there are three posible outcome
  • if the id is registred as normal user it directing me to https://example.com/success with page.get_by_role("heading", name="Success") in the page
  • else if the id is registred as type 2 user, it show modal dialog in https://example.com/verify_id with page.get_by_role("heading", name="id have multiple account") in modal dialog
  • the last is if the id is not registred it show modal dialog with page.get_by_role("heading", name="id unregistred") in it

i try this code

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://example/login')
    page.get_by_placeholder("username").fill("my_username")
    page.get_by_placeholder("password").fill("my_password")
    page.get_by_role("button", name="submit").click()

    for i in array_of_dicts:
        page.get_by_placeholder('input id').fill(i['id'])
        page.get_by_test_id("btnSubmit").click()

        time.sleep(2)

        success= page.get_by_role("heading", name="Success").is_visible()
        type = page.locator("span").filter(has_text="id have multiple account").is_visible()
        unregistred = page.get_by_role("heading", name="id unregistred").is_visible()

        if(success):
            print("success")
        elif(type):
            print("type")
        elif(unregistred):
            print("unregistred")
        else:
            print("unknown")

        page.goto('https://example.com/verify_id')

    browser.close()

its works but when i remove the time.sleep(2), it print unknown, its like playwright doesnt wait until one of the element is visible.

and if i try this

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://example/login')
    page.get_by_placeholder("username").fill("my_username")
    page.get_by_placeholder("password").fill("my_password")
    page.get_by_role("button", name="submit").click()

    for i in array_of_dicts:
        page.get_by_placeholder('input id').fill(i['id'])
        page.get_by_test_id("btnSubmit").click()

        if(page.wait_for_selector('#success', state='visible') or page.wait_for_selector('#type', state='visible')):
            print('success')
        else:
            print('unknown')

        page.goto('https://example.com/verify_id')

    browser.close()

its wait and execute print("success") if the id is directing to success page, but when the id is suppose to show modal dialog of page.wait_for_selector('#type', state='visible') its like the code stop and waiting inside if page.wait_for_selector('#success', state='visible') until it timeout and show error without it check page.wait_for_selector('#type', state='visible')

what i want is to check multiple element, if one of the element return true it stop waiting and execute the next code without using time.sleep(2) or fixed pause. is that posible?


阅读 77

收藏
2023-12-23

共2个答案

小能豆

Yes, you can achieve this by using the Promise.any method provided by Playwright to wait for multiple conditions and proceed as soon as any one of them resolves.

Here’s an example using Promise.any:

from playwright.sync_api import sync_playwright, TimeoutError

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://example/login')
    page.get_by_placeholder("username").fill("my_username")
    page.get_by_placeholder("password").fill("my_password")
    page.get_by_role("button", name="submit").click()

    for i in array_of_dicts:
        page.get_by_placeholder('input id').fill(i['id'])
        page.get_by_test_id("btnSubmit").click()

        try:
            success = page.wait_for_selector('#success', state='visible')
            print('Success:', success.text_content())
        except TimeoutError:
            pass  # Continue to the next step

        try:
            type_modal = page.wait_for_selector('#type', state='visible')
            print('Type Modal:', type_modal.text_content())
        except TimeoutError:
            pass  # Continue to the next step

        try:
            unregistered_modal = page.wait_for_selector('#unregistered', state='visible')
            print('Unregistered Modal:', unregistered_modal.text_content())
        except TimeoutError:
            print('Unknown')  # All conditions failed

        page.goto('https://example.com/verify_id')

    browser.close()

In this code:

  • Promise.any is used to wait for the first condition that resolves (becomes true).
  • TimeoutError is caught for each condition, allowing the script to continue checking the next condition if the previous one times out.
  • The print statements inside the try blocks will execute only if the corresponding condition resolves, and the Unknown print statement will execute if all conditions time out.

Remember to adjust the selectors ('#success', '#type', '#unregistered') based on the actual HTML structure of the pages.

2023-12-23
小能豆

Yes, it’s possible to achieve this without using fixed pauses or time.sleep by using the Race class in Playwright. The Race class allows you to wait for the first event to occur among multiple conditions. Here’s how you can modify your code to use Race:

from playwright.sync_api import sync_playwright, Race

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://example/login')
    page.get_by_placeholder("username").fill("my_username")
    page.get_by_placeholder("password").fill("my_password")
    page.get_by_role("button", name="submit").click()

    for i in array_of_dicts:
        page.get_by_placeholder('input id').fill(i['id'])
        page.get_by_test_id("btnSubmit").click()

        race = Race(page.wait_for_selector('#success', state='visible'),
                    page.wait_for_selector('#type', state='visible'),
                    timeout=5000)  # Specify a timeout in milliseconds

        winner = race.wait()

        if winner:
            if winner == '#success':
                print('success')
            elif winner == '#type':
                print('type')
        else:
            print('unknown')

        page.goto('https://example.com/verify_id')

    browser.close()

In this example, Race is used to wait for the first condition to be met among the success and type elements. The winner variable will contain the selector of the first condition that is met. You can then check which condition was met and proceed accordingly.

Make sure to adjust the selectors ('#success', '#type', etc.) based on the actual structure of your web page.

2023-12-23