Preencher com botai.preencher
A página inteira
const r = await botai.preencher(page)
Com uma Page, o Botaí percorre todos os frames em paralelo: os da mesma origem, os de outra origem, os srcdoc e as páginas abertas depois do fixture.
Só um elemento
Com um Locator, ele preenche só dentro daquele elemento: um formulário, uma seção ou um campo. Vale também dentro de iframe.
await botai.preencher(page.locator('#entrega'))
await botai.preencher(page.getByLabel('CPF'))
await botai.preencher(page.frameLocator('iframe').locator('#contato'))
Assim você preenche só uma seção e deixa o resto para o teste.
O Locator precisa casar um elemento só:
- se casa mais de um, a chamada quebra com
strict mode violation. Aponte para o contêiner (oform, a seção) ou passe aPage; - se não casa nenhum, a chamada espera até o timeout do teste, sem erro próprio do Botaí.
O resultado
botai.preencher devolve { preenchidos, naoReconhecidos, recusados }. Cada linha é { frame, rotulo, seletor }, e frame é a URL do frame:
{
"frame": "http://sonda.local/amplo",
"rotulo": "Nome completo",
"seletor": "input[name=\"nome\"]"
}
| Lista | O que entra |
|---|---|
preenchidos | os campos que receberam um valor da pessoa |
naoReconhecidos | os campos que o classificador não conhece, sem chute: "Idade", "Observações", "Código de indicação" |
recusados | os reconhecidos que não aceitaram o valor: não cabe no maxlength (o Botaí não corta) ou o <select> não tem a opção da pessoa |
"Telefone" recebe o celular; "Telefone fixo" fica de fora de propósito. Um campo de rua sem campo de número na página recebe "rua, número".
Num cadastro realista, o resultado é 21 preenchidos, 2 não reconhecidos e 0 recusados, no Chromium, no Firefox e no WebKit, também com o pacote do npm.
Guarda de regressão
const r = await botai.preencher(page)
expect(r.naoReconhecidos).toEqual([])
Quando alguém põe no formulário um campo novo sem rótulo reconhecível, o teste avisa.
O que ele aguenta
- React controlado, máscara e validação no blur, sem roubar o foco.
- Shadow root aberta.
- CSP estrita (
default-src 'none'; script-src 'self'). O fixture manda o motor porframe.evaluatecom o texto do IIFE, e nunca poraddScriptTag, que a CSP barra. Detalhes em CSP. - Teste visual: o fixture não pinta contorno nenhum. O
toHaveScreenshotvê só os valores.
A 2ª passada
Ligada por padrão: o Botaí espera cerca de 1 s e regrava o que a página sobrescreveu depois de uma busca de CEP. O custo vale para toda chamada que escreve algo. Para pular:
await botai.preencher(page, { segundaPassada: false })
Medido em 2026-10-08, macOS arm64, Node 22.22.3, numa máquina compartilhada: de 4 a 11 ms sem a 2ª passada e cerca de 1 s com ela. Com o relógio do Playwright parado (page.clock.pauseAt), a 2ª passada não termina: veja relógio e 2ª passada.
O que fica de fora
- Checkbox, radio,
file,range,color,hidden,<select multiple>e combobox sem<select>nativo. O "aceito os termos" fica desmarcado. contenteditable: fica vazio.- Shadow root fechada. A extensão a preenche; o fixture não.
- Campos que só habilitam depois da busca de CEP. A 2ª passada só regrava o que o Botaí já tinha escrito.
- O que já foi digitado: o Botaí sobrescreve. Não há modo "só os vazios".
O motor roda no mundo MAIN da página, o mesmo dos scripts do site. Um site que troca protótipos nativos pode interferir. Isso vem do código; ninguém provocou o caso.
Os limites de todas as portas estão em limites.