You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Levantado durante a revisão do #1055 (PR2 do épico #1053). Pré-existente, mas o #1055 amplia o alcance — detalhado abaixo.
Resolvido pelo #1057. A correção funcional e de acessibilidade foi entregue; a varredura de timers foi medida e deliberadamente adiada — ver o comentário de fechamento.
O problema
O plugin suporta explicitamente vários formulários na mesma página: DynamicFragments tem um ramo dedicado a isso, gerando um desafio distinto por formulário quando count( $form_ids ) > 1 (includes/frontend/class-ffc-dynamic-fragments.php:87-99).
Numa página com dois formulários, uma rejeição em qualquer um deles:
Sobrescreve a pergunta exibida em todos os formulários da página
Atualiza o token oculto apenas do primeiro (#id casa só com o primeiro elemento)
O formulário nº 2 passa a exibir a pergunta nova enquanto carrega o token antigo. O usuário responde o que está na tela e é rejeitado — e a mensagem diz que a resposta matemática está incorreta, o que é literalmente verdade e completamente inútil como diagnóstico.
Compare com o caminho do formulário de certificado, assets/js/ffc-frontend-helpers.js:524-527, que faz certo — escopa tudo em $form.find(...) e casa por name, não por id.
Consequência 2 — acessibilidade
Ids duplicados quebram a associação <label for>: o leitor de tela associa ambos os rótulos ao primeiro input. Como o campo é obrigatório e é um gate de submissão, isso deixa o formulário inacessível a quem depende do rótulo.
Consequência: uma página com [ffc_certificate_form]e o shortcode de agendamento agora tem colisão de #ffc_captcha_hash entre shortcodes diferentes, o que antes não acontecia.
O clobber de rótulo via .ffc-captcha-row .ffc-captcha-label-text já era global e já afetava esse caso — só a colisão de #ffc_captcha_hash é nova.
Direção de correção proposta
Sufixar os ids por instância e escopar o refresh:
O template templates/captcha/math-fields.php recebe um sufixo único por render (contador estático ou o form_id quando houver), emitindo ffc_captcha_ans_<n> / ffc_captcha_hash_<n> e o for correspondente. Os atributos namenão mudam — o servidor lê por name, e mudá-los quebraria os 6 sites de verificação.
ffc-calendar-frontend.js passa a escopar por formulário e a casar por name, como o ffc-frontend-helpers.js já faz. É a mudança que de fato conserta o bug funcional; os ids sufixados sozinhos não bastam, porque $('#ffc_captcha_hash') simplesmente deixaria de casar.
Teste JS cobrindo o cenário: duas instâncias na mesma página, rejeição numa delas, asserção de que a outra mantém pergunta e token coerentes entre si.
Teste PHP de que dois renders na mesma requisição produzem ids distintos.
Achado secundário — timers pendentes sobrevivendo ao teardown do jsdom
O CI do #1055 falhou com ReferenceError: window is not definedcom os 1731 testes passando: um setTimeout de 2000ms em ffc-csv-download-flow.js disparava depois de o jsdom ser destruído. Corrigido naquele PR (cb5eb53), drenando o timer com fake timers.
O que não foi medido é se há outras instâncias da mesma classe. Existem 11 timers de 1500ms a 10000ms em assets/js/ — ffc-pdf-generator.js (6s e 10s), ffc-batched-export.js (4s), ffc-admin-migrations.js (1,5s), entre outros — e vários testes esperam com setTimeout real de poucos milissegundos. Um teste que alcance um desses caminhos sem drenar o timer tem a mesma corrida latente.
Vale uma varredura: para cada timer longo, verificar se algum teste alcança o caminho e, se alcança, se drena. É barato e o sintoma é péssimo de diagnosticar — a suíte falha sem nenhum teste falhando, e só sob a velocidade de execução certa.
Adiado com medição — varrer os timers longos e drenar os que forem alcançados por teste. Ver o comentário de fechamento: o inventário foi levantado (16 timers, não 11), mas nenhum vazamento é observável, e a correção especulativa seria churn.
Sequenciamento
Combinado tratar depois do merge do #1055 e antes do PR3 do épico #1053 — o PR3 (ALTCHA) mexe no mesmo markup e no mesmo caminho de refresh, então entrar com essa base já corrigida evita retrabalho.
Levantado durante a revisão do #1055 (PR2 do épico #1053). Pré-existente, mas o #1055 amplia o alcance — detalhado abaixo.
O problema
O plugin suporta explicitamente vários formulários na mesma página:
DynamicFragmentstem um ramo dedicado a isso, gerando um desafio distinto por formulário quandocount( $form_ids ) > 1(includes/frontend/class-ffc-dynamic-fragments.php:87-99).Só que o markup do captcha usa ids fixos:
<label for="ffc_captcha_ans"> <input ... id="ffc_captcha_ans" ...> <input type="hidden" ... id="ffc_captcha_hash" ...>Com dois formulários na página, esses ids aparecem duas vezes.
Consequência 1 — funcional (a mais séria)
assets/js/ffc-calendar-frontend.js:517-519faz o refresh com seletores globais, não escopados ao formulário:Numa página com dois formulários, uma rejeição em qualquer um deles:
#idcasa só com o primeiro elemento)O formulário nº 2 passa a exibir a pergunta nova enquanto carrega o token antigo. O usuário responde o que está na tela e é rejeitado — e a mensagem diz que a resposta matemática está incorreta, o que é literalmente verdade e completamente inútil como diagnóstico.
Compare com o caminho do formulário de certificado,
assets/js/ffc-frontend-helpers.js:524-527, que faz certo — escopa tudo em$form.find(...)e casa porname, não por id.Consequência 2 — acessibilidade
Ids duplicados quebram a associação
<label for>: o leitor de tela associa ambos os rótulos ao primeiro input. Como o campo é obrigatório e é um gate de submissão, isso deixa o formulário inacessível a quem depende do rótulo.O que o #1055 mudou nisso
Não introduziu o defeito, mas ampliou o alcance:
id; o do agendamento tinha. O refactor(captcha): put the math challenge behind a strategy contract #1055 unificou as duas cópias divergentes e oidsobreviveu — porque offc-calendar-frontend.jsdepende dele.[ffc_certificate_form]e o shortcode de agendamento agora tem colisão de#ffc_captcha_hashentre shortcodes diferentes, o que antes não acontecia.O clobber de rótulo via
.ffc-captcha-row .ffc-captcha-label-textjá era global e já afetava esse caso — só a colisão de#ffc_captcha_hashé nova.Direção de correção proposta
Sufixar os ids por instância e escopar o refresh:
templates/captcha/math-fields.phprecebe um sufixo único por render (contador estático ou oform_idquando houver), emitindoffc_captcha_ans_<n>/ffc_captcha_hash_<n>e oforcorrespondente. Os atributosnamenão mudam — o servidor lê porname, e mudá-los quebraria os 6 sites de verificação.ffc-calendar-frontend.jspassa a escopar por formulário e a casar porname, como offc-frontend-helpers.jsjá faz. É a mudança que de fato conserta o bug funcional; os ids sufixados sozinhos não bastam, porque$('#ffc_captcha_hash')simplesmente deixaria de casar.Achado secundário — timers pendentes sobrevivendo ao teardown do jsdom
O CI do #1055 falhou com
ReferenceError: window is not definedcom os 1731 testes passando: umsetTimeoutde 2000ms emffc-csv-download-flow.jsdisparava depois de o jsdom ser destruído. Corrigido naquele PR (cb5eb53), drenando o timer com fake timers.O que não foi medido é se há outras instâncias da mesma classe. Existem 11 timers de 1500ms a 10000ms em
assets/js/—ffc-pdf-generator.js(6s e 10s),ffc-batched-export.js(4s),ffc-admin-migrations.js(1,5s), entre outros — e vários testes esperam comsetTimeoutreal de poucos milissegundos. Um teste que alcance um desses caminhos sem drenar o timer tem a mesma corrida latente.Vale uma varredura: para cada timer longo, verificar se algum teste alcança o caminho e, se alcança, se drena. É barato e o sintoma é péssimo de diagnosticar — a suíte falha sem nenhum teste falhando, e só sob a velocidade de execução certa.
Sequenciamento
Combinado tratar depois do merge do #1055 e antes do PR3 do épico #1053 — o PR3 (ALTCHA) mexe no mesmo markup e no mesmo caminho de refresh, então entrar com essa base já corrigida evita retrabalho.