Integrate payment-templates-validator for local validation #trivial - #8
Integrate payment-templates-validator for local validation #trivial#8carolkrroo wants to merge 1 commit into
Conversation
Wire the shared validator into CLI, Grunt, /validation.json, and a live checkout-shell banner so partners get the same { ok, errors } output as upload validation.
🛡️ SDD Check — action requiredI couldn't detect an SDD in this PR. Please check one option below (requires write access to the repo):
|
fdaciuk
left a comment
There was a problem hiding this comment.
Alguns pontos bloqueantes: injeção de HTML no banner do host, o servidor de dev morre com preview.config.json inválido (o oposto do que validate:soft promete), displayName fora do formato esperado é ignorado em silêncio e o endpoint novo devolve caminho absoluto na rede. Detalhes nos comentários inline.
| }).join(''); | ||
|
|
||
| validationBanner.className = 'payment-template-validation-banner' + (result.ok ? ' has-warnings' : ''); | ||
| validationBanner.innerHTML = '<strong>' + title + '</strong><ul>' + items + '</ul>'; |
There was a problem hiding this comment.
O innerHTML recebe finding.message e finding.ref.file sem escape. As mensagens do validador embutem trechos do template (tag, classe, valor de atributo) e ref.file é um nome de arquivo do bundle, então markup vindo do template executa aqui — e este banner fica na página do host, fora do sandbox="allow-scripts" que só protege o iframe (linha 228). Mesmo sem má intenção quebra a interface: uma mensagem contendo <script> engole o resto do <ul>.
Escapar &, <, >, " antes de concatenar, ou montar os <li> com textContent.
| if (!iframe) return; | ||
| appliedHeight = 0; | ||
| iframe.src = IFRAME_SRC + '?' + Date.now(); | ||
| } |
There was a problem hiding this comment.
Depois desta recarga o listener de load da linha 239 já se removeu (linha 240), então setLocale() não roda de novo e o iframe reinicia em defaultLocale (lib/wrapper-runtime.js, applyLocale(payload.defaultLocale)). Se o usuário tiver trocado para en-US e editado um arquivo do template, o iframe volta para pt-BR enquanto o rótulo do meio de pagamento continua em en-US.
Reaplicar currentLocale após o reload.
| function applyValidationResult(result, options) { | ||
| options = options || {}; | ||
| var signature = validationSignature(result); | ||
| renderValidationBanner(result); |
There was a problem hiding this comment.
Renderiza o banner em toda verificação, mesmo quando o resultado é idêntico — a comparação de assinatura da linha 88 só controla a recarga do iframe. Como o elemento tem role="alert" (src/index.html:27), o leitor de tela relê a lista inteira a cada 1,5s e a seleção de texto se perde a cada tick.
Renderizar só quando a assinatura mudar, preservando a primeira renderização (options.initial).
| renderValidationBanner(null); | ||
| } | ||
| } else { | ||
| renderValidationBanner(null); |
There was a problem hiding this comment.
Qualquer resposta não-2xx cai em "Validation unavailable — restart the dev server", conselho que não se aplica: o servidor está no ar. O message que o middleware monta (lib/validation-middleware.js:21 e :34) nunca chega à tela — com um ícone renomeado o usuário lê "reinicie o servidor" em vez de "icon.jpg não encontrado".
Ler o corpo da resposta de erro e exibir o message.
| function startValidationPolling() { | ||
| loadValidationResult({ initial: true }, function () {}); | ||
| if (validationTimer) clearInterval(validationTimer); | ||
| validationTimer = setInterval(function () { |
There was a problem hiding this comment.
Sem guarda de requisição em voo e sem clearInterval ao sair da página. Como o servidor revalida o bundle inteiro em cada chamada (lib/validation-middleware.js:25), as requisições se acumulam e disputam o mesmo processo que serve o iframe e o livereload.
Ignorar o tick enquanto houver requisição pendente e limpar o timer no beforeunload.
| .catch(function (error) { | ||
| res.statusCode = 500; | ||
| res.setHeader('Content-Type', 'application/json; charset=utf-8'); | ||
| res.end(JSON.stringify({ ok: false, errors: [], message: error.message })); |
There was a problem hiding this comment.
error.message vai cru para a rede e carrega o caminho absoluto: readFileEntry monta 'File not found: ' + name + ' in ' + dir, onde dir é .../payment-mocker/template/reference sob o home do usuário. Com hostname: '*' no Gruntfile.js:59, qualquer máquina na mesma rede faz GET /validation.json e recebe nome de usuário e diretório.
Devolver mensagem genérica na resposta e deixar o detalhe apenas no terminal. Mesmo caso na linha 21.
| process.exit(result.ok ? 0 : 1); | ||
| } | ||
|
|
||
| main().catch(function (error) { |
There was a problem hiding this comment.
No modo --json este caminho não imprime nada no stdout — só a pilha no stderr. Um passo de CI com npm run validate -- --json > result.json fica com arquivo vazio para parsear. A flag json é lida na linha 8 e não é consultada aqui.
Imprimir { ok: false, errors: [], message } no stdout, como o middleware já faz.
|
|
||
| writePng(path.join(root, 'asset-logo.png'), 120, 60); | ||
| writePng(path.join(root, 'asset-badge.png'), 80, 80); | ||
| writePng( |
There was a problem hiding this comment.
O gerador deixou de criar asset-logo.png e asset-badge.png, mas o bundle de referência continua carregando os dois: template/reference/index.html:3 (src="asset-logo.png") e template/reference/style.css:44,49,54 (url(asset-badge.png)). Nada quebra hoje só porque os dois PNGs estão comitados.
E o icon.png gerado aqui não é usado, porque template/preview.config.json aponta para icon.jpg. Como está, npm run generate:assets não reconstitui o bundle como a descrição do arquivo afirma.
| Failed run: | ||
|
|
||
| ``` | ||
| validate: failed (1 error) |
There was a problem hiding this comment.
A saída documentada não corresponde à real. lib/format-validation-output.js:69 sempre concatena o sufixo no resumo e scripts/validate.js:14 sempre passa um, então a linha é validate: failed (1 error) — template at template/reference (o exemplo de sucesso na linha 102 já traz o sufixo). A linha em branco seguinte também não é impressa.
Além disso o texto Forbidden tag <script> in index.html não parece ser a mensagem que @vtex/payment-templates-validator emite — vale colar a saída de uma execução real.
| "bundleDir": "reference", | ||
| "defaultLocale": "pt-BR", | ||
| "icon": "asset-logo.png", | ||
| "icon": "icon.png", |
There was a problem hiding this comment.
O exemplo documenta "icon": "icon.png", mas o template/preview.config.json entregue no PR usa "icon": "icon.jpg". Alinhar os dois para o parceiro não copiar um valor que não corresponde ao bundle de referência.
Summary
@vtex/payment-templates-validatorinto a shared pipeline (lib/validate-bundle.js) that builds fullValidationInputfrom the local bundle, icon, anddisplayNamenpm run validate(strict),grunt/validate:soft(dev server keeps running),/validation.json, and a live banner in the checkout shell--jsonoutput use the same{ ok, errors }model as upload validation (rule,severity,message,ref)Test plan
npm run validatepasses ontemplate/reference/npm run validate -- --jsonprints raw{ ok, errors }yarn gruntstarts the dev server even when validation fails; terminal and banner show findingscurl http://localhost:8080/validation.jsonreturns validator outputTemplate with error

Template without error

Error on terminal while running the app

Error on terminal
