diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index 939988c9a..5ea865d99 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -575,7 +575,8 @@ class Playwright extends Helper { // Clear popup state to ensure clean state for each test popupStore.clear() - recorder.retry({ + // Configure retry for this test; will clean up after test completes + this._retryConfig = { retries: test?.opts?.conditionalRetries || 3, when: err => { if (!err || typeof err.message !== 'string') { @@ -584,7 +585,8 @@ class Playwright extends Helper { // ignore context errors return err.message.includes('context') }, - }) + } + recorder.retry(this._retryConfig) // Start browser if needed (initial start or browser restart strategy) if (!this.isRunning && !this.options.manualStart) await this._startBrowser() @@ -689,6 +691,12 @@ class Playwright extends Helper { } async _after() { + // Clean up our retry config to prevent accumulation + if (this._retryConfig) { + recorder.retries = recorder.retries.filter(r => r !== this._retryConfig) + this._retryConfig = null + } + if (!this.isRunning) return // Clear popup state to prevent leakage between tests diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index ff00f6dd8..094b3752c 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -354,7 +354,8 @@ class Puppeteer extends Helper { async _before(test) { this.sessionPages = {} this.currentRunningTest = test - recorder.retry({ + // Configure retry for this test; will clean up after test completes + this._retryConfig = { retries: test?.opts?.conditionalRetries || 3, when: err => { if (!err || typeof err.message !== 'string') { @@ -363,13 +364,20 @@ class Puppeteer extends Helper { // ignore context errors return err.message.includes('context') }, - }) + } + recorder.retry(this._retryConfig) if (this.options.restart && !this.options.manualStart) return this._startBrowser() if (!this.isRunning && !this.options.manualStart) return this._startBrowser() return this.browser } async _after() { + // Clean up our retry config to prevent accumulation + if (this._retryConfig) { + recorder.retries = recorder.retries.filter(r => r !== this._retryConfig) + this._retryConfig = null + } + if (!this.isRunning) return // Clear popup state to prevent leakage between tests diff --git a/lib/plugin/retryFailedStep.js b/lib/plugin/retryFailedStep.js index 394fa4e5c..2ff51fe86 100644 --- a/lib/plugin/retryFailedStep.js +++ b/lib/plugin/retryFailedStep.js @@ -152,7 +152,9 @@ export default function (config) { test.opts.stepRetryPriority = stepRetryPriority debug('applying retries = %d for test %s', config.retries, test.title) - recorder.retry(config) + if (!recorder.retries.find(r => r === config)) { + recorder.retry(config) + } }) event.dispatcher.on(event.test.started, test => { @@ -171,4 +173,8 @@ export default function (config) { test.opts.conditionalRetries = test.opts.conditionalRetries || config.retries } }) + + event.dispatcher.on(event.test.after, () => { + recorder.retries = recorder.retries.filter(r => r !== config) + }) }