From 2daaf5d992c5c9fcf999533fa9b0ce99040c47a9 Mon Sep 17 00:00:00 2001 From: Peter Hedenskog Date: Mon, 23 Oct 2023 15:26:27 +0200 Subject: [PATCH] Make sure the timer always is cleared when done (#2005) --- lib/core/seleniumRunner.js | 49 +++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/core/seleniumRunner.js b/lib/core/seleniumRunner.js index 0d2dd504c..7f8c033ea 100644 --- a/lib/core/seleniumRunner.js +++ b/lib/core/seleniumRunner.js @@ -24,25 +24,40 @@ const defaults = { const delay = ms => new Promise(res => setTimeout(res, ms)); /** - * Timeout a promise after ms. Use promise.race to compete - * about the timeout and the promise. - * @param {promise} promise - The promise to wait for - * @param {int} ms - how long in ms to wait for the promise to fininsh - * @param {string} errorMessage - the error message in the Error if we timeouts + * @function timeout + * @description Wraps a promise with a timeout, rejecting the promise with a TimeoutError if it does not settle within the specified time. + * + * @param {Promise} promise - The promise to wrap with a timeout. + * @param {number} ms - The number of milliseconds to wait before timing out. + * @param {string} errorMessage - The error message for the TimeoutError. + * + * @returns {Promise} - A promise that resolves with the value of the input promise if it settles within time, or rejects with a TimeoutError otherwise. */ async function timeout(promise, ms, errorMessage) { - let timer; - - return Promise.race([ - new Promise((resolve, reject) => { - timer = setTimeout(reject, ms, new TimeoutError(errorMessage)); - return timer; - }), - promise.then(value => { - clearTimeout(timer); - return value; - }) - ]); + let timerId; + let finished = false; + + // Create a new promise that rejects after `ms` milliseconds. + const timer = new Promise((_, reject) => { + timerId = setTimeout(() => { + if (!finished) { + // Reject with a TimeoutError if the input promise has not yet settled. + reject(new Error(errorMessage)); + } + }, ms); + }); + + try { + // Race the input promise against the timer. + const result = await Promise.race([promise, timer]); + finished = true; + clearTimeout(timerId); + return result; + } catch (error) { + finished = true; + clearTimeout(timerId); + throw error; + } } /**