1

I'm trying to enter text into an input field using Puppeteer.

async function reddit() {
  const broswer = await puppeteer.launch({
    headless: false
  })
  const page = await broswer.newPage();
  const navPromise = page.waitForNavigation({
    waitUntil: 'domcontentloaded'
  })

  await page.goto('https://www.reddit.com/r/place/?cx=352&cy=522&px=69')
  await navPromise;
  console.log('did i get this far? 1');
  await page.click('a._3Wg53T10KuuPmyWOMWsY2F:nth-child(2)')
  await navPromise;

  console.log('did i get this far?2 ');
  await page.keyboard.type('#loginUsername', 'hjello')

  console.log('did i get this far?3');
}

reddit()

I get all three console logs when it runs. I can see it click on the username log in but it doesn't type anything. I have looked at multiple StackOverflow questions and tried the answers but none of them will type the input in.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Kevin.
  • 78
  • 1
  • 9
  • `page.goto` already waits for navigation ("load" event), so the extra nav promise doesn't make much sense. The second `await` on the nav promise doesn't do anything since the promise is already resolved. Are you waiting to make sure `#loginUsername` is available before typing into it? – ggorlen Apr 03 '22 at 23:09
  • yeah the navPromise was a suggestions i seen in another so post so i tried it , and yes ive had await page.waitForSelector('#loginUsername') but it throws an error waiting for the selector i get const timeoutError = new Errors_js_1.TimeoutError(`waiting for ${options.title} failed: timeout ${options.timeout}ms exceeded`); which i tried overriding with a manual time but nothing. – Kevin. Apr 04 '22 at 05:39
  • so i tried it on another site and it works as intended but not on reddit for some reason, ive tried the id and the css selector i get from Firefox neither work. – Kevin. Apr 04 '22 at 14:51

1 Answers1

1

await page.click('a._3Wg53T10KuuPmyWOMWsY2F:nth-child(2)') triggers a DOM change, but then immediately fires .click() on an element that might not be ready yet, so that looks like a race condition. I suggest using waitForSelector (or waitForNavigation if a navigation is triggered, which doesn't appear to be the case here).

const navPromise = page.waitForNavigation({waitUntil: 'domcontentloaded'}) is in a strange location above a goto which already waits for navigation, then it's awaited twice, which doesn't make sense. Once a promise is resolved, it'll never be resolved again, so the only time you'd want to do this is if you need to access the resolved value again, which doesn't apply here. Waiting for extra navigations can cause a timeout when one isn't triggered.

The main issue, though, appears to be that the selector you're trying to type into is inside an iframe. It's possible to dive into this frame and set the value, but it's much easier to save all the trouble and navigate directly to the login page frame URL, log in, then navigate with a goto to whatever page you're trying to get to.

For example:

const puppeteer = require("puppeteer"); // ^13.5.1

let browser;
(async () => {
  browser = await puppeteer.launch({headless: false});
  const [page] = await browser.pages();
  const url = "https://www.reddit.com/login/";
  await page.goto(url, {waitUntil: "domcontentloaded"});
  await page.waitForSelector("#loginUsername");
  await page.type("#loginUsername", "hjello");
  await page.type("#loginPassword", "foobar");
  await Promise.all([
    page.waitForNavigation(),
    page.click(".AnimatedForm__submitButton"),
  ]);
  // navigate to wherever you want with page.goto
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close())
;

Note that when you're selecting elements in the browser console by hand to prepare your script, document.querySelector and similar functions might appear to work on a frame because the frame becomes active when focused in the console, but this won't be the case from the script's perspective, leading to a good deal of potential confusion.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • so i had waitForSelector before and it just would get hungup waiting for the #login selector and timed its self out. okay thanks i was using the navPromise suggested in another so post because the page was not fully loaded before it was bringing up the login, which i wasnt sure if that had anything to do with it or not. I will try going to the login page directly like you suggested instead of trying to login via the popup modal, thank you for your response – Kevin. Apr 05 '22 at 18:32
  • Yeah, the `waitForSelector` timeout has to do with frame visibility, not loading. Like I said, this can be tricky to discover so you'd have to look at the console to see the frame as a parent of the unselectable element. – ggorlen Apr 05 '22 at 19:01