0

I want to fill a two-steps login form with Playwright. The Playwright execution is controlled by a library, so I cannot change the execution context. To fill my form, I can only use some Javascript code that will be executed by evaluate. I have no access to the page object.

In the following example, the first form is correctly loaded, but filling the password field fails. I suppose this is because the code is executed before the page is completely loaded.

How can I make this Javascript code wait for the second page to be completely loaded?

Again, I cannot edit the Playwright context, but if there is a generic solution, I could open a PR upstream.

Here is a schematic snippet of my issue (this is in Python, but that should not be relevant to the actual issue):

from playwright.sync_api import sync_playwright

# this is the only things I can edit:
javascript = """
    document.querySelector('input[name=login]').value = "admin"
    document.querySelector('form').submit()

    # <-- How to wait for the page to be loaded here?

    document.querySelector('input[name=password]').value = "password"
    document.querySelector('form').submit()
"""

# this is the library code I cannot edit
with sync_playwright() as pw:
    browser = pw.firefox.launch()
    context = browser.new_context()
    page = context.new_page()
    page.goto('http://localhost:5000')
    page.evaluate(javascript)
    browser.close()

The playwright error:

playwright._impl._errors.Error: Page.evaluate: document.querySelector(...) is null
@debugger eval code line 234 > eval:4:18
evaluate@debugger eval code:234:30
@debugger eval code:1:44
3
  • 1
    Please provide the page you're automating. Without a minimal reproducible example, answerers can only make random guesses. Generally, do not use sleeps to wait for load. There is no silver bullet that works on all loads, which is mentioned in the PW docs, which means the page you're automating matters. Commented Dec 27, 2024 at 16:51
  • 2
    Why do you need to evaluate the javascript? Everything inside looks like it can be a playwright locator, so await page.locator('input[name=password]') should be all you need, perhaps increasing the timeout. Commented Dec 27, 2024 at 20:33
  • The Playwright execution is controlled by a library, so I cannot change the execution context are you saying you can't alter the test code? Please explain. Commented Dec 27, 2024 at 20:36

1 Answer 1

2

Tried this - works.

import test from "@playwright/test";

test("Example", async ({ page }) => {
  const js = `
     const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
     (async () => {
        const usernameField = document.querySelector("#login_field");
        if (usernameField) {
           usernameField.value = "username"; 
        }
        await wait(5_000)
        const passwordField = document.querySelector("#password");
        if (passwordField) {
           passwordField.value = "password"; 
        }
        document.querySelector("form").submit();
     })();
  `;
  await page.goto("https://github.com/login");
  await page.evaluate(js);
  await page.pause();
});

To check page load, you can use check for document.readyState === 'complete', but it requires writing on Promises like this:

    return new Promise((resolve, reject) => {
      const checkReadyState = () => {
        if (document.readyState === 'complete') {
          resolve('Page is loaded');
        }
      };

      checkReadyState();
    
      const interval = setInterval(() => {
        if (document.readyState === 'complete') {
          clearInterval(interval);
          resolve('Page');
        }
      }, 100); // Check every 100ms

      setTimeout(() => {
        clearInterval(interval);
        reject(new Error('Page not loaded in 10s'));
      }, 10_000);
    });
  }).then((message) => {
    console.log(message);
  }).catch((error) => {
    console.error(error.message);
  });

But it's too complicated and doesn't make sense to use in Playwright. So use wait; it's as bad as using JS code in evaluate instead of native Playwright methods.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.