microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
66.07k stars 3.61k forks source link

[Feature] Allow inactive tabs to be backgrounded #3570

Open maustin opened 4 years ago

maustin commented 4 years ago

Presently Playwright treats all tabs as active. This can become an issue when a tab we're not currently focusing on is running a lot of work. I'll use the site MakeUseOf.com as an example. When this tab is active, it can consume 25-30% CPU time on my brand new MBPro. Under normal Chromium, when the tab is not the current tab Chromium will throttle timers (and whatever else it may do) and the site will settle around 2% CPU. Under Playwright, this inactive tab will continue to use full resources (25-30% CPU).

I'd like to see a flag or an API call (page.goToBack() was suggested) that would allow inactive tabs to sleep.

Here's a link to the original discussion.

Thanks!

mattsenior commented 4 years ago

Hi @maustin, just adding a use case that’s blocked by the same behaviour:

I’m using Playwright to test a site that uses React Query, and I’m specifically testing the behaviour where reactivating/refocusing a tab causes data to be refetched (I have two tabs open in the test and am switching between them).

When using chromium, my call to await page.bringToFront() brings the tab into view, but doesn't trigger the data refetching (my understanding from your description is that chromium never considered the tab to be 'background', so reactivating it doesn't change anything). In Firefox the refocusing + refetching behaviour works as expected (although it does it with two windows rather than tabs).

I think testing behaviour like this is a great use of Playwright so it would be wonderful to have the option to ask chromium to behave similarly.

PS The React Query code is specifically responding to both 'visibilitychange' and 'focus' events on the window to trigger its refetching.

kblok commented 2 years ago

Bringing my upvote here @dgozman https://www.fox.com/ relies on the visibilitychange event to handle the "TV Provider sign in" :(

chrisb2244 commented 1 year ago

I'd also like to be able to "lose focus" in a tab/page, for reasons similar to @mattsenior - I have an auth call that refreshes when the page gains focus, and a bug in my calling code causes this to refresh forms etc (I can fix the bug, but I want to write a test that catches it in case of future refactoring/sillyness etc). I can't currently reproduce this in Playwright, even though it's easy to see in a real browser (Chrome, Firefox, etc).

Smrtnyk commented 1 year ago

To add our usecase: We are pretty big company that develops RUM script as one of the products we offer. That rum script is running on lots of websites, especially from top 10K. Therefore we added pw testing to our arsenal. We noticed that results coming from our RUM script in background has some unexpected behavior, due to usage of some timers that are throttled and other stuff. Having this feature in playwright would allow us to write tests for scenarios in background and observe the behavior and have tests for it on 3 browsers.

klarstrup commented 1 year ago

Piling on:

We're batching analytics events to dispatch with sendBeacon on blur/hidden/pagehide/beforeunload, and we're having mixed luck testing this with page.close({ runBeforeUnload: true }) or hacks like https://github.com/microsoft/playwright/issues/2286#issuecomment-1442368623

kiran-venugopal-bs commented 1 year ago

Hello, We also have a similar use case where we are injecting init script where we have added visiblitychange event listener, but that does not get called on tab changes. Our use case is simple where we want to call few DOM modification api’s once the tab switches on clicking a link or similar and want to get the event fired in visiblitychange. Is there a way currently to enable this API via playwright with any custom flag or chrome args?

Janpot commented 1 year ago

Not sure it may help you, but I've had some success with react-query and the following function, which is a variant of this hack made to work with react-query.

export async function setPageHidden(page: Page, hidden = true) {
  const setHidden = (html: HTMLElement, value: boolean) => {
    const doc = html.ownerDocument;
    Object.defineProperty(doc, 'visibilityState', {
      value: value ? 'hidden' : 'visible',
      writable: true,
    });
    Object.defineProperty(doc, 'hidden', { value, writable: true });
    doc.dispatchEvent(new Event('visibilitychange', { bubbles: true }));
  };

  await page.locator(':root').evaluate(setHidden, hidden);

  await page.frameLocator('iframe').locator(':root').evaluate(setHidden, hidden);
}
await setHidden(page, true)
// ...
await setHidden(page, false)
kiran-venugopal-bs commented 1 year ago

@Janpot thanks for the response but we don’t need to make this page active in dummy manner and run our test case. Instead we actually want this to happen as in normal browser behaviour.

Is there any specific reason we are not allowing browser to handle this? also is there any way to disable this behaviour using CDP or chrome flags?

gregtws commented 1 year ago

A related feature (happy to open in a separate ticket, it just seemed like everything tab related was being pushed here).

I'd like to be able to check the given visibility state of a tab. In a quick test, document.visibilityState is true whether a tab is in front, or back which doesn't make sense. A simple first class feature like page.isActive() (to pair with the existing page.bringToFront()) would be really helpful.

dnsbty commented 11 months ago

My issue was mentioned above, so you can see more details there ☝️ but I'm adding my usecase inline too for those that don't want to read through the issue.

I manage a service that tokenizes sensitive data so that other applications don't have to handle that data. Those other applications will load an iframe that contains a single form field, and that field will be included in a larger form on the parent page. When the user blurs the frame, it will validate the data, send it to the tokenization backend, and then send the resulting token to the parent window. It's using window.addEventListener('blur', () => {}) to trigger sending data to the backend though. I would love to see the capability to blur the window so that we can properly test that functionality.

seanlaff commented 8 months ago

I have something using the focus event. Without native tab switching in playwright I emulated it like this

await page.evaluate(() =>
  document.dispatchEvent(new Event("focus", { bubbles: true })),
);
vaibhavagrawal2912 commented 6 months ago

Hello team, I have a use case for the same. I am using Playwright to open up the Chrome browser and performing some manual actions on Chrome. Now since the playwright is good in terms of the wrappers it provides on top of CDP it's very easy to understand and capture any event that page fire and write custom logiover the same.

Now my website has logic written in the visibility change event, and I want to run the custom script once the visibility change event is triggered, but I did not find any event provided by the playwright on the page object as the event does not fire if I am opening the chrome via playwright. Now to support the logic that I am working on, the dummy change event will not work.

Please add this support or provide support via playwright if possible.