Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page.click() does not work with an input selector #3347

Closed
mehtaanirudh opened this issue Oct 4, 2018 · 27 comments
Closed

Page.click() does not work with an input selector #3347

mehtaanirudh opened this issue Oct 4, 2018 · 27 comments
Labels
chromium Issues with Puppeteer-Chromium

Comments

@mehtaanirudh
Copy link

mehtaanirudh commented Oct 4, 2018

Steps to reproduce

Tell us about your environment:

  • Puppeteer version: 1.8.0
  • Platform / OS version: Windows 10
  • URLs (if applicable):
  • Node.js version: 8.11.4

What steps will reproduce the problem?

I am trying to use page.click() to go to the username filed in Instagram. If I use the selector input[name='username'] in developer console it works. However, puppeteer keeps throwing an error that no node was found

Please include code that reproduces the issue.

const puppeteer = require('puppeteer');

(async () => {
	 try {
	const Browser = await puppeteer.launch({headless:false,
										defaultViewport:{width:600,height:800},
										waitUntil: ['load','domcontentloaded','networkidle0','networkidle2'],
						                timeout :0
						            	});
	const page=await Browser.newPage();
		
    await page.goto('https://www.instagram.com/accounts/login/?source=auth_switcher');
    
    await page.click('input[name="username"]');

    await page.keyboard.type('NewUser');
	await Browser.close();
	
	console.log("Iam done!");
	

	} catch(e) {console.log('main program error:' + e);
	}
	
})();

What is the expected result?

I should be able to type my username

What happens instead?

Puppeteer can't find the user name field

@russelldmatt
Copy link

I'm running into the same issue. Strangely, if I use page.evaluate, it does work. For example:

let selector = 'input[name="username"]';

// does not work
await page.click(selector); 

// does work
await page.evaluate((selector) => document.querySelector(selector).click(), selector); 

I'd be curious if the same workaround works for you.

@mehtaanirudh
Copy link
Author

I'm running into the same issue. Strangely, if I use page.evaluate, it does work. For example:

let selector = 'input[name="username"]';

// does not work
await page.click(selector); 

// does work
await page.evaluate((selector) => document.querySelector(selector).click(), selector); 

I'd be curious if the same workaround works for you.

Thanks. I think it was something to do with the form not uploading before the click event firing. Which is weird because in my launch function I explicitly asks it to wait until the page has been loaded. Nevertheless, I was able to fix it by adding some random delay:

await page.goto('https://www.instagram.com/accounts/login/?source=auth_switcher');
await utilities.addDelay(6000+Math.random()*832+ Math.floor(Math.random()*2312));
await page.click('input[name="username"]');

Where addDelay is a user defined function to add random delay after 8 seconds. It still feels a bit "hacky" but it does work.

You approach works too but I am still confused as to why the click function is not able to take in the input selector :(

@inevity
Copy link

inevity commented Nov 30, 2018

Maybe you should first waitforselector(), then click.

@aslushnikov aslushnikov added the chromium Issues with Puppeteer-Chromium label Dec 6, 2018
@tarikbellamine
Copy link

Same issue. Using page.evaluate works but page.click does not. I am using waitForSelector(selector) immediately before page.click(selector) and it is not causing a timeout error.

@quarhodron
Copy link

Here the same:
await page.$eval('#link', elem => elem.click()); // works

await page.click('#link'); // doesn't work

const btn= await page.waitForSelector('#link'); await btn.click(); // doesn't work

@pjivers
Copy link

pjivers commented Apr 4, 2019

I'm having the same issue. page.evaluate() works but page.click() doesn't.

@foresthoffman
Copy link

foresthoffman commented Apr 10, 2019

I'm running into this issue (with Page.click) as well, with a <button> selector:

div.msgbox button:last-of-type

Using Page.$eval works though.

Puppeteer version: 1.14.0
Platform / OS version: Ubuntu 18.04.2
Node.js version: 8.15.0

@twigs67
Copy link

twigs67 commented Apr 18, 2019

Page.$eval isn't even working for me.

@foresthoffman
Copy link

I'm running into this issue (with Page.click) as well, with a <button> selector:

div.msgbox button:last-of-type

Using Page.$eval works though.

Puppeteer version: 1.14.0
Platform / OS version: Ubuntu 18.04.2
Node.js version: 8.15.0

Update:
Puppeteer version: 1.14.0
Platform / OS version: Ubuntu 18.10
Node.js version: 10.15.1

Page.click seems to be working again!

@foresthoffman
Copy link

Seems to be an issue on my Debian 9 docker container (node:10.15.1) as well.

@aslushnikov
Copy link
Contributor

@mehtaanirudh: you put "waitUntil" in a wrong place: instead of putting it in puppeteer.launch, you should've put the option in page.goto.

Instead of relying on page loading status, it's better to use page.waitForSelector. You can also use page.type and pass selector as the first argument - to save some lines of code.

The following works just fine for me with pptr v1.14.0:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless:false,
    defaultViewport:{width:600,height:800},
  });
  const page = await browser.newPage();
  await page.goto('https://www.instagram.com/accounts/login/?source=auth_switcher');
  await page.waitFor('input[name="username"]');
  await page.type('input[name="username"]', 'NewUser');
  await browser.close();

  console.log("Iam done!");
})();

Everybody else on this issue: if some clicking and typing doesn't work for you, please file a separate bug with us! Make sure to include a good reproduction script so that we can debug and see what's going on.

@elpupi
Copy link

elpupi commented Jun 13, 2019

await page.click('#link') works most of the time. But for some mysterious reason, it won't. The worst is that the program is doing exactly the same, but just on a different page with the exactly same layout.

Magically, await page.$eval('#link', elem => elem.click()); works really well.

@Peta5000
Copy link

Peta5000 commented Jul 8, 2019

@milottit same here, it‘s really mysterious. i‘ve got some e2e tests which work most of the time but sometimes, without any change in the ui, page.click is not working. i‘ll give the eval way a try. thx!
@aslushnikov any idea what the root cause could be?

@geminiyellow
Copy link

still not working, i dont know why, i try $eval and evaluate and waitForSelector before click

@aslushnikov
Copy link
Contributor

@aslushnikov any idea what the root cause could be?

@Peta5000 We fixed everything we knew that was not working with clicks. But since things sometimes don't work for you, there might be more!

We can't just "fix" things - we need a good repro to run locally and debug things. Once you have one, please file a new issue! We'd be happy to look into it!

@Peta5000
Copy link

@aslushnikov Problem is that it's really hard to create a demo where it fails all the time or even a demo where it fails sometimes. It happened really very sporadically in some of our applications and since I'm using the page.$eval() way @milottit suggested it didn't appear anymore. Perhaps it would make sense to examine the pptr page.click() function again keeping in mind that the page.$eval() way works and find out what the difference could be.
I'll also have a look into it as soon as I find the time.

@geminiyellow
Copy link

geminiyellow commented Jul 16, 2019

@aslushnikov i try your solution, not working,
but in other issue, somebody tell me, just wait a little time,

Out of curiosity, do you have an click handlers on your [type='submit'], or is it a pure HTML submit? The reason I ask, is because I have seen cases where javascript event handlers don't get initialized before the tests run, which causes the tests to block. I've fixed that in the past with a wait action before the click

-- https://github.com/patheard/cucumber-puppeteer/issues/101#issuecomment-510856187

and it work.

so, what do you think?

@aslushnikov
Copy link
Contributor

so, what do you think?

Sometimes JS listener initialization is deferred - might be the case.

@geminiyellow
Copy link

do you have some puppeteer's way to check it?

@Parahet
Copy link

Parahet commented Nov 13, 2019

I'm able to see that in puppeteer 2.0.0,
await page.$eval('#link', elem => elem.click()); // works
await page.click('#link'); // doesn't work
const btn= await page.waitForSelector('#link'); await btn.click(); // doesn't work
Why this haven't been fixed yet?

@wojtekmaj
Copy link
Contributor

I've had this situation and it became very clear to me after I did a screenshot. In my case, button I was trying to click using page.click was below the fold. So, I added:

+     await page.evaluate(() => document.querySelector('#btn').scrollIntoView());
      await page.click('#btn');

and it started working! It was mentioned before here: #2190 (comment).

@jbdoster
Copy link

Ubuntu 18.04
Puppeteer 2.0.0

I went through this whole page and tried every solution to click a button of type submit and none of these worked for me.
Curiously, most of these suggestions ended up unchecking a checkbox I had clicked that sits right above the target button instead

. . .

@ezy
Copy link

ezy commented Feb 25, 2020

from https://stackoverflow.com/questions/56226990/puppeteers-page-click-is-working-on-some-links-but-not-others/56227068

Try using ignoreHTTPSErrors option set to true:

puppeteer.launch({ ignoreHTTPSErrors: true, headless: false })

@MadProgrammer0
Copy link

I tried to copy the js path from the log in button I wanted to be clicked on and it worked.
await instagram.page.click("#react-root > section > main > article > div.rgFsT > div:nth-child(1) > div > form > div:nth-child(4) > button > div", {delay: 50});

The full function :

login: async (username, password) => {
    await instagram.page.goto(BASE_URL, { waitUntil: 'networkidle2' });
  
    await instagram.page.waitFor(1000);
   
    /* Writing the username and password */

  await instagram.page.type('input[name="username"]', username, {delay: 150});
  await instagram.page.type('input[name="password"]',password, {delay: 150});
  

  /* Click on the login Button */ 

await instagram.page.click("#react-root > section > main > article > div.rgFsT > div:nth-child(1) > div > form > div:nth-child(4) > button > div", {delay: 50});


   
   
  
} 

}

Robbie1977 added a commit to VirtualFlyBrain/geppetto-vfb that referenced this issue May 28, 2020
@pauloacosta
Copy link

pauloacosta commented Oct 1, 2020

The same problem here:

        await youtube.page.goto (BASE_URL, {waituntil: 'networkidle2'});
        await youtube.page.waitForSelector ('a[class~="yt-simple-endpoint"][class~="style-scope"][class~="ytd-button-renderer"]');
        await youtube.page.click('a[class~="yt-simple-endpoint"][class~="style-scope"][class~="ytd-button-renderer"]');

The WaitForSelector could find the selector, but the Click event dont.

The soulution of Matt Russel works for me: "await page.evaluate((selector) => document.querySelector(selector).click(), selector); "

@elpupi
Copy link

elpupi commented Oct 1, 2020

I do not understand why google is not reacting to this issue originating back in 2018.

@ptommasi
Copy link
Contributor

I had the same issue and I went straight for page.evaluate (the website doesn't seem to distinguish between trusted and untrusted events, so no much bother on my side), but out of curiosity I dug a bit in the source code in GitHub.

I got a bit lost in the process, so I'm not sure I'm pointing at the right direction, but maybe it's something in the click method of the Mouse class (at src/common/Input.ts), here the extract:

  async click(
    x: number,
    y: number,
    options: MouseOptions & { delay?: number } = {}
  ): Promise<void> {
    const { delay = null } = options;
    if (delay !== null) {
      await Promise.all([this.move(x, y), this.down(options)]);
      await new Promise((f) => setTimeout(f, delay));
      await this.up(options);
    } else {
      await Promise.all([
        this.move(x, y),
        this.down(options),
        this.up(options),
      ]);
    }
  }

To my understanding, Promise.all returns the promises in order, but it solves them out of order, therefore the two Promise.all should instead look like:

  async click(
    x: number,
    y: number,
    options: MouseOptions & { delay?: number } = {}
  ): Promise<void> {
    const { delay = null } = options;
    if (delay !== null) {
      await this.move(x, y);
      await this.down(options);
      // btw, I've seen this line a few times, might as well call it
      // const sleep = (ms: number) => new Promise((f) => setTimeout(f, ms));
      // somewhere in the code
      await new Promise((f) => setTimeout(f, delay));
      await this.up(options);
    } else {
      await this.move(x, y);
      await this.down(options);
      await this.up(options);
    }
  }

This might explain the randomness in the behaviour. (Or, I'm wrong, and in that case I apologies for the wrong report 🙈 )

mathiasbynens added a commit that referenced this issue Apr 19, 2021
The `Page#click` method relies on `Mouse#click` for execution. `Mouse#click` triggers the `move`, `down`, and `up` methods in parallel waiting for all of them to finish, when they should be called sequentially instead.

Issue: #6462, #3347
Co-authored-by: Mathias Bynens <mathias@qiwi.be>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chromium Issues with Puppeteer-Chromium
Projects
None yet
Development

No branches or pull requests