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

[BUG] scrollIntoView does not work when covered by sticky header in Chromium #3105

Closed
DJ-Glock opened this issue Jul 23, 2020 · 8 comments · Fixed by #4641
Closed

[BUG] scrollIntoView does not work when covered by sticky header in Chromium #3105

DJ-Glock opened this issue Jul 23, 2020 · 8 comments · Fixed by #4641
Assignees
Labels
browser-chromium upstream This is a bug in something playwright depends on, like a browser.

Comments

@DJ-Glock
Copy link

DJ-Glock commented Jul 23, 2020

Context:

  • Playwright Version: 1.2.1
  • Operating System: Ubuntu Bionic (docker image)
  • Node version: 12.18.0 (ubuntu) / 12.16.2 (win)
  • Browser: HeadlessChrome/85.0.4182.0 (ubuntu)

Hello, guys.
I am working on puppeteer -> playwright migration and faced an issue that did not happen with puppeteer, but happens with playwright for some reason.

I have a list of items, one of them is partially visible. Header overlaps it. I pointed my mouse over it and it's highlighted at the moment:
image

I use simple click with the only one parameter click count = 1. No other flags are set.

According to this doc:
position A point to click relative to the top-left corner of element padding box. If not specified, clicks to some visible point of the element.

PW should click to some visible point of the element. But it does not happen:

Timeout 30000ms exceeded during page.click.
===================== page.click logs =====================
[api] waiting for selector "[data-test-id^="Nav.Country.222"]"
[api]   selector resolved to visible <div tabindex="0" role="button" aria-disabled="false"…>…</div>
[api] attempting page.click action
[api]   waiting for element to be visible, enabled and not moving
[api]   element is visible, enabled and does not move
[api]   scrolling into view if needed
[api]   done scrolling
[api]   checking that element receives pointer events at (149.5,187)
[api]   element does not receive pointer events
[api] retrying page.click action
[api]   waiting for element to be visible, enabled and not moving
[api]   element is visible, enabled and does not move
[api]   scrolling into view if needed
[api]   done scrolling
[api]   checking that element receives pointer events at (149.5,187)
[api]   element does not receive pointer events
[api] retrying page.click action
[api]   waiting for element to be visible, enabled and not moving
[api]   element is visible, enabled and does not move
[api]   scrolling into view if needed
[api]   done scrolling
[api]   checking that element receives pointer events at (149.5,187)
[api]   element does not receive pointer events
[api] retrying page.click action
[api]   waiting for element to be visible, enabled and not moving
[api]   element is visible, enabled and does not move
[api]   scrolling into view if needed
[api]   done scrolling
[api]   checking that element receives pointer events at (149.5,187)
[api]   element does not receive pointer events
[api] retrying page.click action
[api]   waiting for element to be visible, enabled and not moving
[api]   element is visible, enabled and does not move
[api]   scrolling into view if needed
[api]   done scrolling
[api]   checking that element receives pointer events at (149.5,187)
[api]   element does not receive pointer events
[api] retrying page.click action

I used https://chrome.google.com/webstore/detail/coordinates/bpflbjmbfccblbhlcmlgkajdpoiepmkd to check the coordinates and it seems that PW selects coordinates of invisible part. I am not 100% sure, because I was not able to reproduce the issue on Windows in debug mode, but it happens often with docker tests.
image

I'll be happy to provide some additional info for you, just let me know.

Update:
As a workaround I added one scroll into view for the element to be sure that it's fully visible and ready for clicks.
But it would be nice to have a permanent solution.

@dgozman
Copy link
Contributor

dgozman commented Jul 24, 2020

Thank you for filing the issue, I will look into this. However, sample script or at least a page url would be very much appreciated!

@dgozman dgozman self-assigned this Jul 24, 2020
@dgozman
Copy link
Contributor

dgozman commented Jul 24, 2020

I tried to reproduce something like this, but it works for me locally.

const {chromium} = require('playwright');

(async () => {
    const browser = await chromium.launch({headless: false, slowMo: 100});
    const context = await browser.newContext();
    const page = await context.newPage();
    await page.setContent(`
      <div style='overflow: scroll; width: 200px; height: 85px; border: 1px solid black;'>
        <div style='height: 20px; width: 150px'>div1</div>
        <div style='height: 20px; width: 150px'>div2</div>
        <div id=target
          style='height: 20px; width: 150px; background: red;'
          onclick='alert("clicked")'>div3</div>
        <div style='height: 20px; width: 150px'>div4</div>
        <div style='height: 20px; width: 150px'>div5</div>
        <div style='height: 20px; width: 150px'>div6</div>
        <div style='height: 20px; width: 150px'>div7</div>
      </div>
    `);
    await page.$eval('div', div => div.scrollTop = 55);
    await page.waitForTimeout(3000);
    await page.click('#target');
    await page.waitForTimeout(3000);
    await browser.close();
})();

Note the red target div - we only see bottom 5 pixels of it when clicking, and it gets scrolled into view.

@dgozman
Copy link
Contributor

dgozman commented Jul 24, 2020

My guess would be that target element [data-test-id^="Nav.Country.222"] is actually covered by some other element that receives the input. If that's the case, pass force to click on the overlay element instead.

await page.click('[data-test-id^="Nav.Country.222"]', { force: true });

If this is not the case, the repro script would be very welcome 😄

@DJ-Glock
Copy link
Author

@dgozman thanks for your code sample. I dived deep into this issue and found the way to reproduce it. Here you are the code sample:

// @ts-check
const playwright = require("playwright-chromium");

(async () => {
  const browser = await playwright.chromium.launch({
    headless: false, 
    slowMo: 100,
    args: [
      '--start-maximized',
      '--window-size=1920,1080',
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
      '--enable-logging',
    ]
  });
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.setContent(`
  <ul style="overflow-y: scroll; width: 300px; height: 75px">
    <div>
      <ul class="sc-pTHAw ciWhmc">
        <h6 class="MuiTypography-root sc-pKMan eTnkFe MuiTypography-subtitle2" style="
          display: flex;
          -webkit-box-align: center;
          align-items: start;
          position: sticky;
          top: 0px;
          color: rgba(0, 0, 0, 0.54);
          z-index: 1;
          background: rgb(38 249 0);
          padding: 0px 4px 4px;
          position: sticky;
          height: 20px;
          margin: auto;
        ">Category 1</h6>
        <div id="div1" style="height: 20px; width: 150px">div1</div>
        <div id="div2" style="height: 20px; width: 150px">div2</div>
        <div id="target" style="height: 20px; width: 150px; background: red;">div3</div>
        <div id="div4" style="height: 20px; width: 150px">div4</div>
        <div id="div5" style="height: 20px; width: 150px">div5</div>
        <div id="div6" style="height: 20px; width: 150px">div6</div>
        <div id="div7" style="height: 20px; width: 150px">div7</div>
      </ul>
    </div>
  </ul>
  `);
  await page.waitForTimeout(2000);

  // click to scroll up
  await page.click('[id="div4"]');
  await page.click('#target').finally(async() => {
    await browser.close();
  })
})();

I suppose that PW is not able to determine if element is visible or not being under the title h6 with sticky position.
image

@dgozman
Copy link
Contributor

dgozman commented Jul 24, 2020

@DJ-Glock Thank you for the snippet! I can repro this in Chromium, but not Firefox or WebKit. It seems like Chromium is unable to scroll the target into view from under the sticky header.

@dgozman dgozman changed the title [BUG] Page click the element that is visible partially [BUG] scrollIntoView does not work when covered by sticky header in Chromium Jul 24, 2020
@dgozman
Copy link
Contributor

dgozman commented Jul 24, 2020

@DJ-Glock One more thing: you said this issue did not happen with puppeteer. Since both puppeteer and playwright use the same Chrome Debugging Protocol under the hood, this sounds interesting. I tried the same snippet with puppeteer (adding onclick=alert('hello') to the target div) and it seems like it does not produce the alert, although the script does not stall. Does that match your experience, or am I missing something?

@DJ-Glock
Copy link
Author

@dgozman I have just double checked our project with puppeteer and it looks like you're right. Puppeteer does not log any error, does not scroll the item under the sticky title, it just clicks with no effect.
The only reason why I did not found it before is that there was no error :-(

@BohdanKhlystov
Copy link

My guess would be that target element [data-test-id^="Nav.Country.222"] is actually covered by some other element that receives the input. If that's the case, pass force to click on the overlay element instead.

await page.click('[data-test-id^="Nav.Country.222"]', { force: true });

If this is not the case, the repro script would be very welcome 😄

{ force: true } works for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
browser-chromium upstream This is a bug in something playwright depends on, like a browser.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants