Playwright page.wait_for_event function how to access the page and other variables from inside the callable?

Question:

I’m trying to use the playwright page.wait_for_event function. One of the kwargs accepts a Callable. I’m trying to use a helper function that would take two arguments: the event that I’m waiting to fire, and a global variable. But I can’t seem to figure out how to find and/or use a variable for the event to pass into the helper function. Most examples I see that use the wait_for_event function use a lambda function for the predicate argument which works great, but I need to perform an action before I return a boolean value which I also don’t know how to do with a lambda function.

My apologies if my terminology is incorrect.

The function I’m trying to use as an argument:

def test(event, global_variable):
    page.locator('//*[@id="n-currentevents"]/a').click() # Action before boolean
    if event.url == 'https://en.wikipedia.org/':
        return True

The variations of the page.wait_for_event function I tried:

# Doesn't work
r = page.wait_for_event('request', test('request', global_variable))
r = page.wait_for_event('request', test(event, global_variable))
r = page.wait_for_event(event='request', test(event, global_variable))
r = page.wait_for_event(event:'request', test(event, global_variable))

# Lambda works, but I need to click an element before returning the truth value
r = page.wait_for_event(event='request', lambda req : req.url == 
'https://en.wikipedia.org/')

The wait_for_event function:

    def wait_for_event(
    self, event: str, predicate: typing.Callable = None, *, timeout: float = None
) -> typing.Any:
    """Page.wait_for_event

    > NOTE: In most cases, you should use `page.expect_event()`.

    Waits for given `event` to fire. If predicate is provided, it passes event's value into the `predicate` function and
    waits for `predicate(event)` to return a truthy value. Will throw an error if the page is closed before the `event` is
    fired.

    Parameters
    ----------
    event : str
        Event name, same one typically passed into `*.on(event)`.
    predicate : Union[Callable, NoneType]
        Receives the event data and resolves to truthy value when the waiting should resolve.
    timeout : Union[float, NoneType]
        Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default
        value can be changed by using the `browser_context.set_default_timeout()`.

    Returns
    -------
    Any
    """

    return mapping.from_maybe_impl(
        self._sync(
            self._impl_obj.wait_for_event(
                event=event,
                predicate=self._wrap_handler(predicate),
                timeout=timeout,
            )
        )
    )

Update: I was able to accomplish my task with a more appropriate method.

URL = "https://en.wikipedia.org"
with page.expect_response(lambda response: response.url == URL as response_info:
    page.locator('//xpath').click()
response = response_info.value
Asked By: kennethkovacs

||

Answers:

You can use a factory function here to pass the page, and the global_variable. Keep in mind that navigating away from the page from inside the callable will lead to an error. So make sure whatever you are clicking does not change the current URL of the page.

def wrapper(page, global_variable):
    def test(event):
        page.locator('//*[@id="n-currentevents"]/a').click()  # Action before boolean
        if event.url == 'https://en.wikipedia.org/':
            return True
    return test

Then, you can register the above function using page.wait_for_event like this:

page.wait_for_event('request', wrapper(page, global_variable))

Remember: You need to pass functions/callables (not their return values) to page.wait_for_event

Answered By: Charchit
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.