From 789cc65084501f10f65764fb34ec10cbab364089 Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sun, 23 Jun 2024 14:29:33 +0200 Subject: [PATCH] Use `waitForEvent` in the `pasteFromClipboard` integration test helper function This code contains the same bug that the previous commit fixed in `waitForEvent`, namely that we don't clear the timeout if the event is triggered. By using the now fixed `waitForEvent` function we not only deduplicate this code but we also fix this issue so that no incorrect timeout logs show up anymore. --- test/integration/test_utils.mjs | 65 +++++++++++++++------------------ 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/test/integration/test_utils.mjs b/test/integration/test_utils.mjs index 92a7a7913a6364..39fe88bd4c1e3c 100644 --- a/test/integration/test_utils.mjs +++ b/test/integration/test_utils.mjs @@ -186,39 +186,54 @@ async function getSpanRectFromText(page, pageNumber, text) { ); } -async function waitForEvent(page, eventName, timeout = 5000) { +async function waitForEvent( + page, + eventName, + selector = null, + validator = null, + timeout = 5000 +) { const handle = await page.evaluateHandle( - (name, timeOut) => { + (name, sel, validate, timeOut) => { let callback = null, timeoutId = null; + const element = sel ? document.querySelector(sel) : document; return [ Promise.race([ new Promise(resolve => { - // add event listener and wait for event to fire before returning - callback = () => { + // The promise is resolved if the event fired in the context of the + // selector and, if a validator is defined, the event data satisfies + // the conditions of the validator function. + callback = e => { if (timeoutId) { clearTimeout(timeoutId); } - resolve(false); + // eslint-disable-next-line no-eval + resolve(validate ? eval(`(${validate})`)(e) : true); }; - document.addEventListener(name, callback, { once: true }); + element.addEventListener(name, callback, { once: true }); }), new Promise(resolve => { timeoutId = setTimeout(() => { - document.removeEventListener(name, callback); - resolve(true); + element.removeEventListener(name, callback); + resolve(null); }, timeOut); }), ]), ]; }, eventName, + selector, + validator ? validator.toString() : null, timeout ); - const hasTimedout = await awaitPromise(handle); - if (hasTimedout === true) { - console.log(`waitForEvent: timeout waiting for ${eventName}`); + const success = await awaitPromise(handle); + if (success === null) { + console.log(`waitForEvent: ${eventName} didn't trigger within the timeout`); + } else if (!success) { + console.log(`waitForEvent: ${eventName} triggered, but validation failed`); } + return success; } async function waitForStorageEntries(page, nEntries) { @@ -291,35 +306,13 @@ async function pasteFromClipboard(page, data, selector, timeout = 100) { await navigator.clipboard.write([new ClipboardItem(items)]); }, data); + const validator = e => e.clipboardData.items.length !== 0; let hasPasteEvent = false; while (!hasPasteEvent) { // We retry to paste if nothing has been pasted before the timeout. - const handle = await page.evaluateHandle( - (sel, timeOut) => { - let callback = null; - const element = sel ? document.querySelector(sel) : document; - return [ - Promise.race([ - new Promise(resolve => { - callback = e => resolve(e.clipboardData.items.length !== 0); - element.addEventListener("paste", callback, { - once: true, - }); - }), - new Promise(resolve => { - setTimeout(() => { - element.removeEventListener("paste", callback); - resolve(false); - }, timeOut); - }), - ]), - ]; - }, - selector, - timeout - ); + const promise = waitForEvent(page, "paste", selector, validator); await kbPaste(page); - hasPasteEvent = await awaitPromise(handle); + hasPasteEvent = await promise; } }