gauge icon indicating copy to clipboard operation
gauge copied to clipboard

Taiko timeouts when popup is triggered after closing tab

Open mikkopitkaenen opened this issue 2 years ago • 3 comments

Describe the bug Throws an error "There is no handler registered..." when confirm/prompt is triggered after a new tab is closed. Happens only in headless mode.

To Reproduce

  (async () => {
    try {
      await openBrowser({ headless: true });
      await goto('https://google.com');
      await openTab();
      await waitFor(500);
      await closeTab();
      confirm('testing confirm', () => accept('OK'));
      await evaluate(() => confirm('testing confirm'));
    } catch (error) {
      console.error('error', error);
    } finally {
      await closeBrowser();
    }
  })();

Logs

 ✔ Browser opened
>  ✔ Navigated to URL https://google.com
>  ✔ Opened tab with URL about:blank
>  ✔ Closed current tab matching about:blank
> Uncaught:
There is no handler registered for confirm popup displayed on the page https://www.google.com/.
          This might interfere with your test flow. You can use Taiko's confirm API to handle this popup.
          Please visit https://docs.taiko.dev/#confirm for more details

Expected behavior Should not throw an error

Versions:

  • Taiko: Version: 1.3.5 (Chromium: 104.0.5109.0) RELEASE
  • Ubuntu 22.04.1 LTS jammy
  • Node.js: v18.10.0

mikkopitkaenen avatar Dec 19 '22 12:12 mikkopitkaenen

This is mentioned in the docs https://docs.taiko.dev/api/confirm/

Under

// Note: Taiko's `confirm` listener has to be setup before the confirm
// popup displays on the page. For example, if clicking on a button
// shows the confirm popup, the Taiko script is

Happy to re-open this issue if it this still happens after modifying the script to

  (async () => {
    try {
      await openBrowser({ headless: true });
      await goto('https://google.com');

      confirm('testing confirm', () => accept('OK'));
      await evaluate(() => confirm('testing confirm'));

      await openTab();
      await waitFor(500);
      await closeTab();
    } catch (error) {
      console.error('error', error);
    } finally {
      await closeBrowser();
    }
  })();

zabil avatar Dec 20 '22 08:12 zabil

Thank you for your reply.

I think my issue description was a bit too simplified. Let me explain the use case a bit more in detail.

Some background information. We are using gauge to run taiko. When running in gauge, the code doesn't time out, mostly the code completes successfully. It just throws lots of these unhandled popup errors in the logs. But every now and then the run gets stuck and timeouts. Having hundreds of these unconfirmed popup handler error messages in gauge logs could have something to do with the occasional timeout. To simplify the issue report, when running the same directly in Taiko, it times out.

The code example is about boxes. A great deal of our tests is follows the logic: We create a box, we do one or more tests on it, and at the end we delete the box. Everything goes fine if the tests run in the same tab. But the issue occurs when there is a link that opens in new tab. Or to be more specific, after closing the tab and triggering a popup.

We would like to build the tests like this:

Gauge steps
* Create box (has confirmation popup for box creation)
* Test stuff
* Delete box (has confirmation popup for box deletion)

We cannot have this structure if there is a test that contains a popup. Throws the unhandled popup error

Gauge steps
* Create box (has confirmation popup for box creation)
* Tests in a new tab
* Delete box (has confirmation popup for box deletion)

(Ref code snippet Problem case 1)

As you presented, we could include the confirm handler for deletion in advance. In our use case it would mean that step("Create box") would include creation and deletion popup handlers

Gauge steps
* Create box (has confirmation popup for box creation and deletion)
* Tests in a new tab
* Delete box

(Ref code snippet Problem case 2) Taiko will throw an error nevertheless where it is located. We have tests that include opening of links in new tab multiple times in one test, In context of gauge, an unhandled error is thrown for each opened/closed tab and for each confirm/prompt popup that is triggered after tab closing interactions.

Back to the original snippet. If I copied your answer and added a new "test" that triggers a popup after the closeTab, then the problem occurs. The tricky thing is that it doesnt happen every time. I ran the snippet below 10 times, of which it failed 6 times

  (async () => {
    try {
      await openBrowser({ headless: true });
      await goto('https://google.com');

      confirm('testing confirm', () => accept('OK'));
      await evaluate(() => confirm('testing confirm'));

      await openTab();
      await waitFor(500);
      await closeTab();

      confirm('testing confirm after closeTab', () => accept('OK'));
      await evaluate(() => confirm('testing confirm after closeTab'));
    } catch (error) {
      console.error('error', error);
    } finally {
      await closeBrowser();
    }
  })();

Code references:

<!DOCTYPE html>
<html>
  <head>
    <title>Issue description</title>
  </head>
    <input type = "button" value="Create box" onclick = "confirm('Create box?')"><br>
    <input type = "button" value="Delete box" onclick = "confirm('Delete box?')"><br>
    <a href="https://google.com" target="_blank">Sub page that opens in new tab</a>
  </body>
</html>

Problem case 1:

  const beforeSuite = async () => {
    await openBrowser({ headless: true });
    await goto('http://127.0.0.1:8080/');
  };
  const createBox = async () => {
    confirm('Create box?', () => accept('OK'));
    await click('Create box');
  };
  const deleteBox = async () => {
    confirm('Delete box?', () => accept('OK'));
    await click('Delete box');
  };
  const testsInNewTab = async () => {
    await click('Sub page that opens in new tab');
    await waitFor(500);
    await closeTab();
  };
  (async () => {
    try {
      await beforeSuite();
      await createBox();
      await testsInNewTab();
      await deleteBox();
    } catch (error) {
      console.error('error', error);
    } finally {
      await closeBrowser();
    }
  })();

Problem case 2:

  const beforeSuite = async () => {
    await openBrowser({ headless: true });
    await goto('http://127.0.0.1:8080/');
  };
  const createBox = async () => {
    confirm('Create box?', () => accept('OK'));
    confirm('Delete box?', () => accept('OK')); //Moving the handler here will still fail
    await click('Create box');
  };
  const deleteBox = async () => {
    await click('Delete box');
  };
  const testsInNewTab = async () => {
    await click('Sub page that opens in new tab');
    await waitFor(500);
    await closeTab();
  };
  (async () => {
    try {
      await beforeSuite();
      await createBox();
      await testsInNewTab();
      await deleteBox();
    } catch (error) {
      console.error('error', error);
    } finally {
      await closeBrowser();
    }
  })();

mikkopitkaenen avatar Dec 20 '22 15:12 mikkopitkaenen

Thanks for spending time to explain this issue and specify the code samples. Re-opening it

zabil avatar Dec 20 '22 16:12 zabil