Reputation: 369
The objective is to click an anchor by only moving the mouse to it and issuing a click at the current mouse cursor position (which will hopefully be on the clickable area of the link), together with the Meta key pressed (Command on Mac OS, Ctrl on Windows).
The expected result is that Chrome open a new tab, loading the linked page. This works great on Mac OS. But on Windows, it just loads the page in the current tab, as if no Ctrl were held down during the click.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
executablePath: process.platform === "darwin" ?
"/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
// Location of Chrome for Windows Canary v76.x on my Windows system, yours may vary
: "C:\\Users\\ADMINI~1\\AppData\\Local\\Google\\CHROME~2\\APPLIC~1\\chrome.exe"
});
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: 'networkidle0', timeout: 30000 });
let mySelector = "a";
let myElems = await page.evaluate(function(myThis) {
const domElemA = Array.from(document.querySelectorAll(myThis.selector));
const outElemA = domElemA.reduce(function(acc, cur) {
let r = cur.getBoundingClientRect();
let myObj = { rectLeft: Math.round(r.left), rectTop: Math.round(r.top), rectRight: Math.round(r.right), rectBottom: Math.round(r.bottom) };
// optionally do some filtering here, for objects outside the viewport.
// I know I could use Array.map() here if no filtering desired.
return [...acc, myObj];
}, []);
return outElemA;
}, { selector: mySelector });
console.log(myElems); // output the anchors we found
let e = myElems[0];
// determine the center of the anchor element
let x = Math.round((e.rectRight - e.rectLeft) / 2 + e.rectLeft);
let y = Math.round((e.rectBottom - e.rectTop) / 2 + e.rectTop);
let k = "Meta" // Command on MacOS, Ctrl on Windows
await page.mouse.move(x, y);
await page.waitFor(100);
await page.keyboard.down(k);
await page.waitFor(100);
await page.mouse.down();
await page.waitFor(100);
await page.mouse.up();
await page.waitFor(100);
await page.keyboard.up(k);
// Expected result: Link is opened in new tab due to Meta key held down while clicking
// Actual result on Mac OS: Behaves as expected
// Actual result on Windows: Opens link in the same tab, as if no Meta key were pressed
})();
Puppeteer version:
> npm view puppeteer
[email protected] | Apache-2.0 | deps: 8 | versions: 642
Chrome version on Windows (Canary):
76.0.3803.0 (Official Build) (64-bit)
I understand that there are convenient Puppeteer functions like page.click() that click directly into the center of a given element, but any such shortcut solutions are outside the scope of this question.
It must work without selecting the element directly, by moving the cursor into the likely clickable zone and then issuing a mouse click. I am aware this clickable shape can vary so this approach can fail -- also not the type of advice that I am asking for ("Why would you want to do that!?"). 😂
Also, this is not a duplicate of the often-heard complaint that Meta+A (select all) works fine on Windows but doesn't work as expected on Mac OS.
But I do suspect it is a similar problem, but in reverse, depending on where GUI events are handled, on the DOM model level, on the browser level, on the the OS level.
If the problem is of a non-fixable nature, is there a workaround to open a link in a new tab but 100% based on the current mouse position, and not doing anything "to" the targeted DOM element directly? Page.click() and such do a lot of "stuff" that I don't want my "user" to do.
Upvotes: 1
Views: 1394
Reputation: 222
This is probably because the meta
key would refer to the "Windows" key on Windows.
you can use ctrl
if it's running on windows:
let k = process.platform == "win32" ? "Control" : "Meta";
https://nodejs.org/api/process.html#process_process_platform
Upvotes: 1