retryFailedStep ignores factor/minTimeout/maxTimeout with the Playwright helper (and applies them nondeterministically under Bun)
Mantenedores costumam responder em até 1 dia
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 68/100
- Tipo de issue
- Bug
- Clareza
- Claramente especificada
- Status de atividade
- Ativa
- Stack de tecnologia
- bun, javascript, node.js, playwright
Direção de pesquisa
Start with lib/helper/Playwright.js and the recorder.add() retry selection described in the issue; inspect how the plugin and Playwright helper configs are pushed and selected. Reproduce the minimal case under Node and Bun with DEBUG=codeceptjs:recorder, then verify that retryFailedStep consistently honors its matched factor, minTimeout, maxTimeout, and retries across runtimes.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
What are you trying to achieve?
Configure the backoff of retryFailedStep (factor, minTimeout, maxTimeout) with the Playwright helper, and get the same retry timing on every run and runtime.
What do you get instead?
With the Playwright helper, the plugin's timing options are:
- ignored under Node: the backoff always uses promise-retry's defaults (
factor: 2); - applied only to some steps under Bun: the backoff alternates between the plugin's options and the defaults, so it depends on how many recorder tasks ran before the failing step.
Only retries is always right.
Minimal repro (a step that fails instantly, so the duration is pure backoff):
// codecept.conf.js
export const config = {
tests: './*_test.js',
output: './output',
helpers: { Playwright: { url: 'about:blank', show: false, browser: 'chromium' } },
plugins: { retryFailedStep: { enabled: true, retries: 4 } }, // default factor 1.5
}
// retry_test.js
Feature('retry')
Scenario('1 pass', ({ I }) => { I.amOnPage('about:blank') })
Scenario('2 fail', ({ I }) => { I.seeElement('#nope') })
Scenario('3 fail', ({ I }) => { I.seeElement('#nope') })
| Runtime | Failed scenario duration | Backoff used |
|---|---|---|
| Node 24 | ~2280 ms | 150+300+600+1200 → factor 2 (plugin's 1.5 ignored) |
| Bun 1.4.2 | ~1250 ms here, but varies per step in a real suite (we saw ×1.5 and ×2 in the same run) | 150+225+338+506 → factor 1.5, or factor 2 |
DEBUG=codeceptjs:recorder shows the Retry opts alternating between the plugin config and {"retries":4} on consecutive tasks under Bun.
Cause
Two retry configs are active in each test:
- the plugin's (
factor: 1.5,minTimeout,maxTimeout, …), pushed intest.before; - the Playwright helper's own, pushed in
_before()(lib/helper/Playwright.js, since 3.7.0):
It copies only the retry count from the plugin, viathis._retryConfig = { retries: test?.opts?.conditionalRetries || 3, when: err => /* only errors containing 'context' */, } recorder.retry(this._retryConfig)conditionalRetries. Withoutfactor/minTimeout/maxTimeoutit falls back to promise-retry's defaults.
recorder.add() picks one config per task:
const retryOpts = this.retries
.sort((r1, r2) => r1.when && !r2.when)
.slice(-1)
.pop()
- The comparator returns a boolean. Per the spec that isn't a consistent comparator, so the order is implementation-defined. V8 keeps the order, so the helper's config (pushed last) always wins. JavaScriptCore (Bun, also Safari/WebKit) swaps the two elements on every call, and
.sort()mutatesthis.retriesin place, so the winner alternates from task to task. WebKit closed the same pattern as not a bug: https://bugs.webkit.org/show_bug.cgi?id=289223 - Even with a deterministic sort, the timing comes from the helper's config, not from the rule whose
whenactually matched the error. For an element-not-found error only the plugin'swhenmatches, yet the helper's defaults set the backoff.
Suggested fix
- Use a numeric comparator, e.g.
(r1.when ? 0 : 1) - (r2.when ? 0 : 1), and avoid sortingthis.retriesin place. - Take the promise-retry options from the retry rule that matched the error, or have the Playwright helper inherit all of the plugin's retry options, not only
retries.
Workaround: set factor: 2 (and leave minTimeout/maxTimeout at their defaults) in the plugin config, so both configs are identical.
Details
- CodeceptJS version: 4.2.0 (same code since 3.7.0)
- NodeJS Version: 24.18.0 / Bun 1.4.2
- Operating System: Linux
- Playwright helper
Created by AI agent (Claude Code)
- Linguagem predominante
- JavaScript
- Estrelas
- 4.2k
- Forks
- 756
- Merge médio
- 1d 8h
- PRs com merge (30d)
- 18
Preparar o ambiente
- Inclui um Dockerfile ou arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de codeceptjs/CodeceptJS
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
codeceptjs/CodeceptJS#5731 ·
Mantenedores costumam responder em até 1 dia
-
`I.waitForFile` (FileSystem helper) fails if directory does not exist (yet)Talvez já em andamento @danielrentz assumiu há 250 dias. Abertastale
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
codeceptjs/CodeceptJS#5420 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
stale
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
codeceptjs/CodeceptJS#5358 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
stale
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
codeceptjs/CodeceptJS#4958 · 10 comentários · 2 reações ·
Mantenedores costumam responder em até 1 dia
-
stale
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 72/100
codeceptjs/CodeceptJS#4778 · 3 comentários ·
Mantenedores costumam responder em até 1 dia
Todas as issues de codeceptjs/CodeceptJS
Issues semelhantes
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 92/100
QuantEcon/lecture-python-programming#642 ·
Mantenedores costumam responder em até 1 dia
-
Missing repro Platform: Android
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
software-mansion/react-native-reanimated#10816 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
-
[Suggestion]: Document that useFormStatus works with a preventDefault-ed onSubmit + startTransitionAbertatype: documentation
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
Mantenedores costumam responder em até 2 dias
-
area:docs bug triage:confirmed
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 74/100
Cotal-AI/Cotal#2875 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
keithamus/css-minify-tests#304 ·
Mantenedores costumam responder em até 1 dia