From b6fc5544eb5bde906a96a7fba149133b8b8f7918 Mon Sep 17 00:00:00 2001 From: Stefano Magni Date: Wed, 14 Jun 2023 10:07:39 +0200 Subject: [PATCH] fix: update the timeout logic to consider also the checkFunction duration Before this commit, the number of retries was calculated ignoring the checkFunction duration. As a result, a 5s timeout with a 0.5s interval resulted in 10 retries. If the checkFunction takes 10 seconds, 10 retries mean waiting for 100 seconds, violating the 5s timeout. This commit fixes the problem by checking, after each checkFunction invocation, what is the elapsed time and stops retrying in case the timeout is over. BREAKING CHANGE: The timeout is now respected even if checkFunction takes a long time. As a result, you could face that your checkFunction runs less times. fix #464 --- cypress/e2e/plugin.spec.js | 32 ++++++++++++++++++++++++++++++++ src/index.js | 5 ++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/cypress/e2e/plugin.spec.js b/cypress/e2e/plugin.spec.js index 5d0d27b..6133681 100644 --- a/cypress/e2e/plugin.spec.js +++ b/cypress/e2e/plugin.spec.js @@ -39,6 +39,38 @@ context('Cypress Wait Until', () => { }) }) + it('Should run once if waitUntil timeout is less than checkFunction execution time', () => { + let checks = 0 + const checkFunction = () => { + cy.wait(500).then(() => { + checks++ + return false + }) + } + + cy.once('fail', () => { + expect(checks).to.equal(1) + }) + + cy.waitUntil(checkFunction, { timeout: 400 }) + }) + + it('Should run 3 times if checkFunction + interval is 2s and timeout is 5s', () => { + let checks = 0 + const checkFunction = () => { + cy.wait(1500).then(() => { + checks++ + return false + }) + } + + cy.once('fail', () => { + expect(checks).to.equal(3) + }) + + cy.waitUntil(checkFunction, { timeout: 5000, interval: 500 }) + }) + it('Should apply options correctly', () => { const COOKIE_NAME = 'after-a-while-cookie' const EXPECTED_COOKIE_VALUE = 'Set' diff --git a/src/index.js b/src/index.js index 3270d24..99861df 100644 --- a/src/index.js +++ b/src/index.js @@ -47,7 +47,7 @@ const waitUntil = (subject, checkFunction, originalOptions = {}) => { // filter out a falsy passed "customMessage" value options.customMessage = [options.customMessage, originalOptions].filter(Boolean) - let retries = Math.floor(options.timeout / options.interval) + const endTime = Date.now() + options.timeout logCommand({ options, originalOptions }) @@ -56,13 +56,12 @@ const waitUntil = (subject, checkFunction, originalOptions = {}) => { if (result) { return result } - if (retries < 1) { + if (Date.now() >= endTime) { const msg = options.errorMsg instanceof Function ? options.errorMsg(result, options) : options.errorMsg throw new Error(msg) } cy.wait(options.interval, { log: false }).then(() => { - retries-- return resolveValue() }) }