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
63.84k stars 3.46k forks source link

[Feature] context.newPage() to open a new tab instead of a new window in Firefox #3696

Open sublimator opened 3 years ago

sublimator commented 3 years ago

Was expecting a new tab I am not sure if I've seen this before when using puppeteer

yury-s commented 3 years ago

Yes, this is the expected behavior. Each page lives in its own window. This changed in v1.3 previously all pages would open as tabs in the same window.

sublimator commented 3 years ago

What's the rationale behind this?

yury-s commented 3 years ago

There is a few, we don't want pages from different contexts to live in the same window, also having pages in same window would make it difficult to screencast all of them in headful mode.

sublimator commented 3 years ago

Is it possible to have an option to launch a page in the same window ? I'm using playwright to test an extension with specific behavior regarding tabs/windows.

vovanluan commented 3 years ago

Is it possible to have an option to launch a page in the same window ? I'm using playwright to test an extension with specific behavior regarding tabs/windows.

+1 to have an option to launch new page in the same window. There are tests I have to use launchPersistentContext which is more convenient when all pages are in the same window

shirshak55 commented 3 years ago

Just for screencast used probably by 1% of playwright user I think its unfair to launch each page as window instead of tab. The tests are behaving so weird now :(.

sublimator commented 3 years ago

Yes, I hope the devs become more responsive

arjunattam commented 3 years ago

Thanks for the feedback, @shirshak55 and @sublimator. We looked at how users were running their tests in headful mode (since this only impacts headful), and noticed that they tend to run single tests, as opposed to the entire suite. Given a single test, our rationale was that this is a minor inconvenience and would only impact multi-tab scenarios. We could have missed something, and I'd love to know a bit more about this so we can find a better solution.

@sublimator: If I understand correctly, your extension tests check for behavior between tabs/windows and mixing the two can get confusing. Did I get this right?

The tests are behaving so weird now :(

@shirshak55: Can you tell me a bit more about this?

shirshak55 commented 3 years ago

Hello I don't think it only impact headful. Headless will consume more cpu, more ram just because of window. I just did a simple benchmark

Without tab

➜  code ps aux | grep firefox
shirshak         19076   1.1  5.7

With Tab

➜  code ps aux | grep firefox
shirshak         19076  21.0  9.3

5.7 for tab and 9.3% usage for window.

It same browser just with tab vs window. Making Multiple window definitely consumes way too much memory at least in headful mode. (It would be great if other can also post some benchmark but currently i am on laptop so can't give accurate benchmark)

By the way my issue is same context is giving tab when i use chrome and when i use Firefox it gives new window. Its inconsistent .

And We use playwright to not test but also automate workflow. So it would be great if we are given ability to choose whether we are going for tab or window is better. At least with context i assumes it should open new tab instead of window when i do newPage?

sublimator commented 3 years ago

@arjunattam

Thank you very much for your question! :)

Ideally we would like to be able to test the extension's reactions to switching tabs inside a single window, which for us is definitely different to 1:1 tab:window scenarios.

On the topic of extension testing, while I have your attention, would it be possible to get some love on this issue: https://github.com/microsoft/playwright/issues/3932

I'm currently sticking to 1.3.x until that issue (loading extensions into Firefox) is resolved.

shirshak55 commented 3 years ago

Plus we run test sometime in vnc server just to know whats happening. In vnc i only notice one window so making multi tab is better there and multi window will be mess.

It would be nice if there was at least a way to revert this behavior. In VNC tests are working like mess window upon window is stacked :( If it was tab i could switch tab easily but switching window is not easy :(

jgoalby commented 3 years ago

In the comment above by @arjunattam it was suggested that headless mode created multiple tabs. I created the below to test this and it shows as many processes as I have iterations in the loop.

When I run firefox by hand from the Playwright folder, and then create multiple tabs, I do not see the same behavior in task manager. In fact I can hold down CTRL-T and create many tabs without a new process being created.

So, I am wondering if there is an option I am missing that would allow each newPage to be a new tab in firefox headless mode?

As for a usecase, I do have one. I need to support multiple separate users interacting with my application. The application uses Playwright to control a downstream web application. As the user count grows (~30) I start to experience resource issues. My hope is that having instances in multiple tabs rather than separate browsers that I can avoid the issues. Each user will have multiple tabs so that multiple requests can be made concurrently. I want to support more users and more concurrent tabs.

Furthermore, when using chromium I see that it uses multiple tabs rather than multiple browser instances. I realize this is not quite apples to apples, but it has helped in my testing so far with that browser.

const playwright = require('playwright');

(async () => {
  const options = {
    headless: true,
    args: [ ]
  };

  const browser = await playwright.firefox.launch(options);
  const context = await browser.newContext();

  const page1 = await context.newPage();

  for (let i = 0; i < 20; i++) {
    await context.newPage();
  }

  await page1.goto('https://example.com');
})();

Playwright 1.8.1 on Windows 10.

pavelfeldman commented 3 years ago

@aslushnikov: do you want to take a look at the comment above? newPage isn't supposed to create a new process, do you know what is happening there?

jgburet commented 3 years ago

Hey, anything we can do to fix this issue?

await context.newPage()

still opens a new browser window while it should open a new tab in the existing context.

HMaker commented 2 years ago

Is there any ETA?

Also, there is no way to use the window opened by playwright.firefox.launch(), when calling context.newPage() later it will end up with 2 windows:

const playwright = require('playwright');

(async () => {
  const options = {
    headless: false,
    args: [ ]
  };
  const browser = await playwright.firefox.launch(options);
  const context = await browser.newContext();
  const page1 = await context.newPage();
  await page1.goto('https://example.com');
})();

Ran against playwright 1.15 on Ubuntu 18.04.

aslushnikov commented 2 years ago

still opens a new browser window while it should open a new tab in the existing context.

@jgburet that's still the same context, it's just rendered as a different window. It shouldn't make any difference for tests though!

jgoalby commented 2 years ago

@aslushnikov while it may be in the same context, is there a reason it cannot be a new tab vs a new window?

As far as doesn’t make any difference, one of the issues I was experiencing was resource consumption and performance slowdown due to multiple windows. There might have been other issues as well, but I would have to revisit to see.

Is there a fundamental difference that means this is difficult with firefox? If it is not difficult, what other reasons would there be to not make the change?

shirshak55 commented 2 years ago

@jgoalby

there is a reason it can't be a new tab and it's mostly due to the screencasting feature afaik. Also putting in a new window means the race condition like when multiple contexts are created, gets solved easily. And there are some issues like firefox will delete rendered pages from inactive tabs etc.?

I think such problems are caused mainly because firefox is not focusing on getting CDP (probably due to lack of resources) And the playwright team already has less time as maintaining their patches for the upstream browser which is generally tedious. I think its better for long run so I am happy with the decision playwright team makes.

HarikrishnanVK commented 1 year ago

Hey guys, I got into same issue and I thought opening a new tab in Firefox using windows keyboard shortcut 'Control + T'. But no luck. Below are the combinations I tried. Let me know if this is possible using Playwright's keyboard APIs or am i missing something here.

(Note: firefoxInstance is my page reference)

//open a new tab await firefoxInstance.keyboard.press("Control+T");

//open a new tab
await firefoxInstance.keyboard.press("Control+KeyT");

//open a new tab
await firefoxInstance.keyboard.down("Control");
await firefoxInstance.keyboard.press("KeyT");
await firefoxInstance.keyboard.up("Control");

//open a new tab
await firefoxInstance.keyboard.down("Control");
await firefoxInstance.keyboard.press("T");
await firefoxInstance.keyboard.up("Control");

//open a new tab
await firefoxInstance.keyboard.down("Control");
await firefoxInstance.keyboard.type("T");
await firefoxInstance.keyboard.up("Control");

//open a new tab
await firefoxInstance.keyboard.down("Control");
await firefoxInstance.keyboard.type("KeyT");
await firefoxInstance.keyboard.up("Control");
hanzhihong9 commented 1 year ago

I find a way to open new tab in firefix

  const [newPage] = await Promise.all([
      context.waitForEvent('page');
      page.evaluate(() => window.open( 'about:blank'))
    ]);
    await newPage.goto('https://google.ca') // newPage is from the new tab
    await newPage.waitForLoadState();
    console.log(await newPage.title()); // is : Google
knoefel commented 11 months ago

Are there any updates on this?

temo214 commented 10 months ago
with context.expect_page() as new:
    page.evaluate("window.open('https://www.google.com')")
    page2 = new.value

page.bring_to_front()
sleep(2)
print(context.pages)
page2.bring_to_front()