0

I'm not sure why, but it seems like some fields just don't work for me.

This is working fine for me on one site:

await page.click(USERNAME_SELECTOR);
await page.keyboard.type(CREDS.username);
await page.click(PASSWORD_SELECTOR);
await page.keyboard.type(CREDS.password);
await page.click(LOGIN_BUTTON_SELECTOR);
await page.waitForNavigation();

However, on https://app.member.virginpulse.com/, it doesn't seem to work for me. It should be simple enough as the input fields both have IDs (#username and $password)... however, it just doesn't seem to fill out properly.

const puppeteer = require('puppeteer');
const email = "foo@bar.com";
const password = "foopass";
const emailInputSel = "#username";
const passwordInputSel = "#password";
const signInButtonSel = ".login-submit input";
const homeUrl = "https://app.member.virginpulse.com";

async function run() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(homeUrl, {waitUntil: 'domcontentloaded'});
    //----from here---
    await page.waitFor(emailInputSel);
    await page.$eval(emailInputSel, (e,v) => e.value = v, email);
    await page.$eval(passwordInputSel, (e,v) => e.value = v, password);
    //----to here----- i've tried several things
    await page.screenshot({path: 'screenshot.png'});
    ...

Other things I've tried:

await page.evaluate((sel, val) => {
    const ele = document.querySelector(sel);
    if (!ele) {
        return;
    }
    ele.value = val;
}, sel, val);

await page.evaluate((sel) => {
    const ele = document.querySelector(sel);
    if (!ele) {
        return;
    }
    ele.click(); ele.focus();
}, sel);
await page.keyboard.type(val);

Nothing seems to fill out the data properly. Does anyone know what is happening and how to get this to work?

Smern
  • 18,746
  • 21
  • 72
  • 90
  • hi, could you explain more on `it doesn't seem to work`, any flag or indicator that show it doesn't work` or the reason of its seem doesn't work? – plat123456789 May 24 '19 at 02:42
  • the code at actual fill in part look correct to me, could you try change ```{waitUntil: 'domcontentloaded'}``` part, because sometimes `domcontentloaded` event fired, but the page need some time to load the js file and run the script – plat123456789 May 24 '19 at 02:45
  • other thing I noticed is when I nav to [https://app.member.virginpulse.com/](https://app.member.virginpulse.com/), its redirect to something like [https://iam.virginpulse.com/auth/realms/virginpulse/protocol/openid-connect/auth?...](https://app.member.virginpulse.com/....) to have the actual password input, did you try waitForNavigation or other logic to handle this kind of behavior? – plat123456789 May 24 '19 at 02:50
  • other possible behavior is the browser already set cookie after you login once, when you nav to [https://app.member.virginpulse.com/](https://app.member.virginpulse.com/) again, the cookie show you already login, because of that the browser redirect the other page, therefore there are not email or password input – plat123456789 May 24 '19 at 02:53
  • @plat123456789 - by not working, the screenshots usually show the login fields completely empty... i've had a couple odd cases where part of the input was there and part wasn't. If you plug run this yourself you can see the screenshot will probably just be empty. Other than `domcontentloaded` i have tried `networkidle0` as well.. I've also used the `waitFor` to wait for the selector to be available.. I've also put code in to grab the title of the page and console log it before attempting the inputs... it is "Log in to Virgin Pulse" as I would expect. – Smern May 24 '19 at 12:41

1 Answers1

4

Fix 1: Wait until element is VISIBLE

Just waiting for selector will not work, we must wait till the element is properly visible on the viewport and navigation requests are done.

// wait until all requests are done
await page.goto(homeUrl, { waitUntil: "networkidle0" });

// wait until the email selector is visible on viewport
await page.waitForSelector(emailInputSel, { visible: true }); 

Just adding above changes on your current code gave me this result,

enter image description here

Notice how the result screenshot above does not have any content on the submit button, same happens with your other selectors as well.

Fix 2: Pass the data properly

This is optional in case the first fix does not change anything.

Step 1

Instead of passing two arguments, pass one argument with braces.

await page.evaluate((sel, val) => {
    const ele = document.querySelector(sel);
    if (!ele) {
        return;
    }
    ele.value = val;
}, (sel, val)); // <-- Look here

Step 2

If the above step 1 does not work, then try to trigger the change. So if it's a angular app, it should know that the element has changed, Change the above to this,

await page.evaluate((sel, val) => {
  const ele = document.querySelector(sel);
  if (!ele) {
    return;
  }
  ele.value = val;

  // Trigger the change here
  var event = new Event('input', {
    'bubbles': true,
    'cancelable': true
  });

  ele.dispatchEvent(event);

}, (sel, val));

Optional

If you want to reuse the same thing multiple time, you can rewrite them in this manner,

const fillInput = (sel, val) => {
  await page.waitForSelector(sel, { visible: true });
  await page.evaluate((sel, val)=>{}) // the code from above function should be here
}

then call like this,

await fillInput(emailInputSel, email)
Md. Abu Taher
  • 17,395
  • 5
  • 49
  • 73
  • I also discovered that clicking the submit button wasn't working even with the form filled out (because it thought those fields were not updated)... I found that doing a page.click() on those elements fixed this as well (similar to what you did with input event)... but i can probably use the original `page.click(), page.keyboard.type()` now with your `visible:true`... the `visible:true` on the waitFor appears to be what I really needed (probably true for angular forms in general?) – Smern May 24 '19 at 20:49
  • Yes, this should be true for any similar framework/library. Since react, angular has a different way to detect "change", you should probably let it know that something has changed. Typing directly with keyboard.type "emulates" actual typing, thus angular knows something has changed. :) – Md. Abu Taher May 24 '19 at 21:03