I have this Playwright piece of code that selects options for a multi-select element

I use the expect() function with regular expressions in order to assert the presence of "xx-oranges" in the selected options

But I need to provide a regex for each list element.

def test_list_regex(page: Page):
    page.goto("https://example.cypress.io/commands/actions")

    select2 = page.locator(".action-select-multiple")
    select2.select_option(['fr-apples', 'fr-oranges', 'fr-bananas'])
    expect(select2).to_have_values(['fr-apples', 'fr-oranges', 'fr-bananas'])
    # Don't know how to verify 'fr-oranges' is part of selected options in an elegant way with expect()
    expect(select2).to_have_values([re.compile(".*"), re.compile(".*oranges"), re.compile(".*")])

I would like to have an statement that can check for the regex ".*oranges" independently of the size of the list and the position of the element within the list

I would like to have an expression that can work against lists like this:

['fr-oranges']
['fr-apples', 'fr-oranges']
['fr-apples', 'fr-oranges', 'fr-bananas', 'en-tomatos']
['en-oranges', 'fr-bananas', 'fr-apples', 'en-tomatos']

Any ideas on how to write such regex that can be passed to expect(select2).to_have_values() ?

2

There are 2 best solutions below

0
On

Good question. Since the Playwright Python assertion API is pretty limited at the time of writing, one option is to do most of the work in CSS:

from playwright.sync_api import expect, Page, sync_playwright  # 1.37.0


def test_list_regex(page: Page):
    page.goto("https://example.cypress.io/commands/actions")

    select = page.locator(".action-select-multiple")
    select.select_option(["fr-apples", "fr-oranges", "fr-bananas"])

    sel = '.action-select-multiple option[value$="oranges"]:checked'
    expect(page.locator(sel)).to_be_visible()


if __name__ == "__main__":
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        test_list_regex(page)

Another option, assuming you don't need to auto-wait (a reasonable assumption, since selecting options is always synchronous as far as I've seen), here is an immediate assertion you can use that is agnostic of ordering:

# ...
values = select.evaluate("""
    el => [...el.querySelectorAll('option:checked')].map(e => e.value)
""")
assert any(x.endswith("oranges") for x in values)

This website happens to have jQuery running, so you could use that:

# ...
value = select.evaluate("""
    el => $(el).find("option:selected:contains(oranges)").val()
""")
assert value.endswith("oranges")

If you need to retry this, you can toss in a loop and a timer and write your own function wrapper on that code for reusability, since Python Playwright doesn't have custom matchers or poll or toPass methods like Node Playwright does.

If I find anything better, I'll update (and feel free to comment if you find a better answer--I'd love to see it).

See also Python playwright: wait for arbitrary DOM state.

0
On

Thanks for the feedback

I was also thinking about this

assert "fr-oranges" in select2.evaluate("elem => $(elem).val()")

Or to make a loop if I want to assert a regex against each list element.

But I really don't know if this code will always execute synchronous or not, due to the asynchronous nature of JavaScript.