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

Problem with rounded buttons #109

Open
marcusdiy opened this issue Oct 17, 2023 · 12 comments
Open

Problem with rounded buttons #109

marcusdiy opened this issue Oct 17, 2023 · 12 comments

Comments

@marcusdiy
Copy link

When the button is a circle or has rounded box the click may happen to be outside the button.
There is needed a better solution to handle rounded shapes otherwise clicks wont work.

@captainjackrana
Copy link

Can you share the example from a webpage or component?

@marcusdiy
Copy link
Author

marcusdiy commented Jan 4, 2024

Sure. Just create a round button and try to click it.

    const GhostCursor = require("ghost-cursor");
    const puppeteer = require("puppeteer");
    (async () => {

      const browser = await puppeteer.launch({ headless: false });
      const page = await browser.newPage()
      const cursor = GhostCursor.createCursor(page);
      await GhostCursor.installMouseHelper(page);
      //await page.goto('https://example.com/');
      await page.reload();

      await page.evaluate(() => {
        let h = `
          <div id="missedCount">Missed count: <b>0</b></div>
          <div id="btn">Click me</div>
          <style> #btn {border-radius: 93% 7% 96% 4% / 93% 6% 94% 7%; padding: 30px; background: #ffdcdc} </style>`;
        let s = document.createElement('div'); s.innerHTML = h; document.body.appendChild(s);
      });

      await page.evaluate(() => {
        let h = `
          let missed = 0;
          document.body.addEventListener('click', () => { missed++; updateCount(); });
          document.querySelector('#btn').addEventListener('click', (e) => { e.stopImmediatePropagation(); });
          function updateCount() { document.querySelector('#missedCount b').innerText = missed; }`;
        let s = document.createElement('script'); s.innerHTML = h; document.body.appendChild(s);
      });
      while (true) {
        let $btn = await page.$('#btn');
        await cursor.click($btn).catch(console.error);
      }

    })();

@marcusdiy
Copy link
Author

A solution could be checking if the element hovered is actually our target, and if not retry.
document.elementFromPoint(e.clientX, e.clientY)

@simonadler1
Copy link

also having this issue

@viniciuspatzer
Copy link

same

@manishiitg
Copy link

same issue

@revic1993
Copy link

Any update on this issue? Facing same challenge

@Niek
Copy link
Collaborator

Niek commented May 8, 2024

The problem is that CDP returns a rectangle bouncing box. So while clicking in the middle is usually OK, a random point might be outside of the clickable area in a non-rectangle element. For example:

Screenshot 2024-05-08 at 20 15 11

I'm not sure if there is an easy way to fix this. Maybe add an extra check upon calculating a point to see if it's hoverable?

@captainjackrana
Copy link

captainjackrana commented May 8, 2024

@Niek This is what ChatGPT suggests in a nutshell.. Can this solution be incorporated?

  1. Find border radius property of the button

  2. You can safely click within a rectangle defined by [x + r, y + r] to [x + width - r, y + height - r].
    Ensure to handle cases where r might be large enough to affect more than just the corners (e.g., circular buttons)

async function clickRandomPoint(buttonSelector) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://yourwebsite.com');

    const rect = await page.evaluate(selector => {
        const element = document.querySelector(selector);
        const {x, y, width, height} = element.getBoundingClientRect();
        const style = window.getComputedStyle(element);
        const radius = parseInt(style.borderRadius); // Assuming uniform radius
        return {x, y, width, height, radius};
    }, buttonSelector);

    // Calculate safe area considering border radius
    const safeX = rect.x + rect.radius;
    const safeY = rect.y + rect.radius;
    const safeWidth = rect.width - 2 * rect.radius;
    const safeHeight = rect.height - 2 * rect.radius;

    // Generate random coordinates within the safe area
    const randomX = safeX + Math.random() * safeWidth;
    const randomY = safeY + Math.random() * safeHeight;

    // Click the random point
    await page.mouse.click(randomX, randomY);

    await browser.close();
}

Full prompt + answer here -
https://chat.openai.com/share/2be55fbf-1fa1-429f-8125-7c21b6534ff9

@Niek
Copy link
Collaborator

Niek commented May 8, 2024

That would only work for border-radius styled elements. There are lots of other cases where the clickable object is not a perfect rectangle. I saw it e.g. on SERP links, where links with linebreaks are only clickable on the exact text.
Best would be to have a generalized fix for this issue.

@bvandercar-vt
Copy link
Contributor

One solution is to set paddingPercentage: 99 (or another high value) in your move/click function. This will make the cursor always go near the center.

@rezovax
Copy link

rezovax commented Jun 21, 2024

I just want to voice this crutch - you can change the css of the element before clicking so that style="border-radius: 0 "

OR

await page.addStyleTag({
    content: `* {
                  border-radius: 0 !important;
              }`
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants