From 51dcd6a1baad3c5c83b624dd3a7886b49832c6fc Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 23 Jun 2024 14:25:52 +0200 Subject: [PATCH] Fix the timeout logic in the `waitForEvent` integration test helper function Debugging #17931, by printing all parts of the event lifecycle including timestamps, uncovered that some events for which a timeout was logged actually did get triggered correctly in the browser. Going over the code and discovering https://stackoverflow.com/questions/47107465/puppeteer-how-to-listen-to-object-events#comment117661238_65534026 showed what went wrong: if the event we wait for is triggered then `Promise.race` resolves, but that doesn't automatically cancel the timeout. The tests didn't fail on this because `Promise.race` resolved correctly, but slightly later once the timeout was reached we would see spurious log lines about timeouts for the already-triggered events. This commit fixes the issue by canceling the timeout if the event we're waiting for has triggered. --- test/integration/test_utils.mjs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/integration/test_utils.mjs b/test/integration/test_utils.mjs index 65c7f29141ae3..92a7a7913a636 100644 --- a/test/integration/test_utils.mjs +++ b/test/integration/test_utils.mjs @@ -189,16 +189,22 @@ async function getSpanRectFromText(page, pageNumber, text) { async function waitForEvent(page, eventName, timeout = 5000) { const handle = await page.evaluateHandle( (name, timeOut) => { - let callback = null; + let callback = null, + timeoutId = null; return [ Promise.race([ new Promise(resolve => { // add event listener and wait for event to fire before returning - callback = () => resolve(false); + callback = () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + resolve(false); + }; document.addEventListener(name, callback, { once: true }); }), new Promise(resolve => { - setTimeout(() => { + timeoutId = setTimeout(() => { document.removeEventListener(name, callback); resolve(true); }, timeOut);