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] ClickAsync() on popup window that closes itself causes exception #26900

Open
coderb opened this issue Aug 29, 2023 · 6 comments
Open

[BUG] ClickAsync() on popup window that closes itself causes exception #26900

coderb opened this issue Aug 29, 2023 · 6 comments

Comments

@coderb
Copy link

coderb commented Aug 29, 2023

System info

  • Playwright Version: v1.36
  • Operating System: All
  • Browser: All
  • Other info:

A popup window that includes a button which closes the window sometimes causes an Exception in playwright.

It happens about half the time (probably a race condition that depends on how fast the browser window is closed).

Source code

            var popup = await page.RunAndWaitForPopupAsync(async () => { 
                await buttonThatOpensPopupWindow.ClickAsync();
            });
            await popup.WaitForLoadStateAsync();
            await popup.ClickAsync("#btnOk");

Expected

no exception

Actual

============================================================
Exception: PlaywrightException: Target closed
=========================== logs ===========================
waiting for Locator("#btnOk")
  locator resolved to <a class="button-primary" onclick="Foo…>…</a>
attempting click action
  waiting for element to be visible, enabled and stable
  element is visible, enabled and stable
  scrolling into view if needed
  done scrolling
  performing click action
============================================================
   at Microsoft.Playwright.Transport.Connection.InnerSendMessageToServerAsync[T](String guid, String method, Dictionary`2 dictionary, Boolean keepNulls) in /_/src/Playwright/Transport/Connection.cs:line 192
   at Microsoft.Playwright.Transport.Connection.WrapApiCallAsync[T](Func`1 action, Boolean isInternal)
   at Test.Do(IPage page) in c:\source\Test.cs:line 163
@mxschmitt
Copy link
Member

mxschmitt commented Aug 31, 2023

Can you share a reproducible which demonstrates the issue with actual and expected behavior?

@coderb
Copy link
Author

coderb commented Aug 31, 2023

unfortunately it's with a financial website that requires an account and login.

my code is very basic and the relevant part is above. is there some other way to provide you with any additional info you need to address the issue?

btw- thanks for your hard work, the project is fantastic.

@coderb
Copy link
Author

coderb commented Sep 6, 2023

additional info:
also present in 1.37.1
seems to only happen w/firefox

@mxschmitt
Copy link
Member

Thanks for filing! I can reproduce actually with this code which passes in CR and WK but fails in FF:

using Microsoft.Playwright;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Webkit.LaunchAsync(new BrowserTypeLaunchOptions() { Headless = false });
var context = await browser.NewContextAsync();
var page = await context.NewPageAsync();
await page.GotoAsync("https://example.com");

await context.RouteAsync("**/popup.html", async (route) =>
{
    await route.FulfillAsync(new()
    {
        Status = 200,
        ContentType = "text/html",
        Body = "<button id=btnOk onclick=\"window.close();\">Close Me</button>"
    });
});

await page.SetContentAsync(@"
    <button onclick=""window.open('https://example.com/popup.html')"" id=button>Button</button>
    <script>
        button.addEventListener('click', () => {
            const popup = window.open('https://example.com/popup.html');
            popup.onload = () => {
                popup.document.querySelector('button').click();
            };
        });
    </script>
");

var popup = await page.RunAndWaitForPopupAsync(async () => { 
    await page.GetByRole(AriaRole.Button, new() { Name = "Button" }).ClickAsync();
});
await popup.GetByRole(AriaRole.Button, new() { Name = "Close Me" }).ClickAsync();

No action needed from your side anymore.

@mxschmitt
Copy link
Member

mxschmitt commented Sep 6, 2023

Can also reproduce it in Node.js, moving over to the main repo:

import playwright from 'playwright';

(async () => {
  const browser = await playwright.firefox.launch({ headless: false });
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://example.com');

  await context.route('**/popup.html', async route => {
    await route.fulfill({
      status: 200,
      contentType: 'text/html',
      body: `<button id="btnOk" onclick="window.close();">Close Me</button>`
    });
  });

  const popupPromise = page.waitForEvent('popup');
  await page.evaluate(() => {
    window.open('https://example.com/popup.html');
  });
  const popup = await popupPromise;
  await popup.getByRole('button', { name: 'Close Me' }).click();
  await browser.close();
})();

Expected: Passes
Actual: Last click() throws locator.click: Target closed

@mxschmitt mxschmitt transferred this issue from microsoft/playwright-dotnet Sep 6, 2023
@aslushnikov
Copy link
Collaborator

aslushnikov commented Sep 27, 2023

Investigation notes:

  • When hitting the "close" button in pop-up, Juggler sends a sequence of events: mousemove, mousedown and mouseup
  • These events are dispatched to the pop-up renderer process
  • By the time the mouseup event is dispatched in the renderer, the popup is getting closed; the ACK from the mouseup renderer process is not dispatched to the browser process since the communication channel between the 2 is already terminated.
  • Once the page is closed, the mouseup ack is not received (and will never be received), so juggler in the browser process sends an error to the client

So far there's no easy way to fix this on the Juggler side other than add a hack (i.e. ignore missing ACK from the mouseup event in the browser process). We decided to hold this fix until there are more reports.

As a workaround, folks should try-catch the click method that closes the page.

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

No branches or pull requests

3 participants