Repository: pyscript/pyscript
File: pyscriptjs/tests/integration/support.py (Python)

Code before:
        Wait until the given message appear in the console. If the message was
        already printed in the console, return immediately.

        Note: it must be the *exact* string as printed by e.g. console.log.

        timeout is expressed in milliseconds. If it's None, it will use
        playwright's own default value, which is 30 seconds).

        If check_js_errors is True (the default), it also checks that no JS
        errors were raised during the waiting.
        """
        # NOTE: we cannot use playwright's own page.expect_console_message(),
        # because if you call it AFTER the text has already been emitted, it
        # waits forever. Instead, we have to use our own custom logic.
        try:
            t0 = time.time()
            while True:
                elapsed_ms = (time.time() - t0) * 1000
                if elapsed_ms > timeout:
                    raise TimeoutError()
                #
                if text in self.console.all.lines:
                    # found it!
                    return
                #
                self.page.wait_for_timeout(50)
        finally:
            # raise JsError if there were any javascript exception. Note that
            # this might happen also in case of a TimeoutError. In that case,
            # the JsError will shadow the TimeoutError but this is correct,
            # because it's very likely that the console message never appeared
            # precisely because of the exception in JS.
            if check_js_errors:
                self.check_js_errors()

    def wait_for_pyscript(self, *, timeout=None, check_js_errors=True):
        """
        Wait until pyscript has been fully loaded.

        Timeout is expressed in milliseconds. If it's None, it will use
        playwright's own default value, which is 30 seconds).

        If check_js_errors is True (the default), it also checks that no JS
        errors were raised during the waiting.
        """
        # this is printed by interpreter.ts:Interpreter.initialize
        self.wait_for_console(
            "[pyscript/main] PyScript page fully initialized",
            timeout=timeout,
            check_js_errors=check_js_errors,
        )

Review comment (bug):
What about something like:
```
if text in self.console.all.lines:
    return
with self.page.expect_console_message(pred, timeout=timeout):
    pass
```
there would still be a race condition where the message appears between the two checks, but it would be much less likely.

... So probably what you did is better.

Code after:
        Wait until the given message appear in the console. If the message was
        already printed in the console, return immediately.

        Note: it must be the *exact* string as printed by e.g. console.log.

        timeout is expressed in milliseconds. If it's None, it will use
        the same default as playwright, which is 30 seconds.

        If check_js_errors is True (the default), it also checks that no JS
        errors were raised during the waiting.

        Return the elapsed time in ms.
        """
        if timeout is None:
            timeout = 30 * 1000
        # NOTE: we cannot use playwright's own page.expect_console_message(),
        # because if you call it AFTER the text has already been emitted, it
        # waits forever. Instead, we have to use our own custom logic.
        try:
            t0 = time.time()
            while True:
                elapsed_ms = (time.time() - t0) * 1000
                if elapsed_ms > timeout:
                    raise TimeoutError(f"{elapsed_ms:.2f} ms")
                #
                if text in self.console.all.lines:
                    # found it!
                    return elapsed_ms
                #
                self.page.wait_for_timeout(50)
        finally:
            # raise JsError if there were any javascript exception. Note that
            # this might happen also in case of a TimeoutError. In that case,
            # the JsError will shadow the TimeoutError but this is correct,
            # because it's very likely that the console message never appeared
            # precisely because of the exception in JS.
            if check_js_errors:
                self.check_js_errors()

    def wait_for_pyscript(self, *, timeout=None, check_js_errors=True):
        """
        Wait until pyscript has been fully loaded.

        Timeout is expressed in milliseconds. If it's None, it will use
        playwright's own default value, which is 30 seconds).

        If check_js_errors is True (the default), it also checks that no JS
        errors were raised during the waiting.
        """
        # this is printed by interpreter.ts:Interpreter.initialize
        elapsed_ms = self.wait_for_console(