From e9f48366cc4a751c22d15e00c4823eb90f2a6ccc Mon Sep 17 00:00:00 2001 From: gololdf1sh Date: Mon, 18 May 2026 20:34:08 +0300 Subject: [PATCH] Fix retryFailedStep ignoredSteps exact-name matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wildcard check used `ignored.indexOf('*')` as a boolean. `-1` is truthy in JavaScript (only `0` is falsy), so entries without `*` were matched via `startsWith(slice(0, -1))` instead of exact compare, which also chops the last character — broadening the match further. `ignoredSteps: ['see']` silently ignored `seeElement`, `seeInField`, `selectOption`, `sendPostRequest` — anything starting with `se`. Compare against `-1` explicitly so exact-name entries only match themselves, as the docs describe. --- lib/plugin/retryFailedStep.js | 2 +- test/unit/plugin/retryFailedStep_test.js | 30 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/plugin/retryFailedStep.js b/lib/plugin/retryFailedStep.js index cbe145910..25d7a195d 100644 --- a/lib/plugin/retryFailedStep.js +++ b/lib/plugin/retryFailedStep.js @@ -116,7 +116,7 @@ export default function (config) { if (step.title === ignored) return if (ignored instanceof RegExp) { if (step.title.match(ignored)) return - } else if (ignored.indexOf('*') && step.title.startsWith(ignored.slice(0, -1))) return + } else if (ignored.indexOf('*') !== -1 && step.title.startsWith(ignored.slice(0, -1))) return } enableRetry = true }) diff --git a/test/unit/plugin/retryFailedStep_test.js b/test/unit/plugin/retryFailedStep_test.js index 09cab5b10..d929bcc99 100644 --- a/test/unit/plugin/retryFailedStep_test.js +++ b/test/unit/plugin/retryFailedStep_test.js @@ -157,6 +157,36 @@ describe('retryFailedStep', () => { // expects to retry only once }) + it('should not treat exact-name ignoredSteps entries as wildcard prefixes', async () => { + // Regression: ignored.indexOf('*') was used as truthy check. + // -1 is truthy, so entries without '*' were matched via startsWith(slice(0, -1)). + // ignoredSteps: ['see'] would silently ignore seeElement, seeInField, selectOption, etc. + retryFailedStep({ retries: 2, minTimeout: 1, ignoredSteps: ['see'] }) + event.dispatcher.emit(event.test.before, createTest('test')) + + let counter = 0 + event.dispatcher.emit(event.step.started, { title: 'seeElement' }) + try { + await recorder.add( + () => { + counter++ + if (counter < 3) { + throw new Error() + } + }, + undefined, + undefined, + true, + ) + await recorder.promise() + } catch (e) { + await recorder.catchWithoutStop(err => err) + } + + // seeElement is NOT in ignoredSteps (only 'see' is) — should be retried. + expect(counter).to.be.greaterThan(1) + }) + it('should add custom regexp steps to ignore', async () => { retryFailedStep({ retries: 2, minTimeout: 1, ignoredSteps: [/somethingNew/] }) event.dispatcher.emit(event.test.before, createTest('test'))