npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pilutech/botai-playwright

v0.2.0

Published

Fixture do Playwright que gera uma pessoa brasileira de teste reproduzível e preenche formulários com o motor do Botaí

Readme

@pilutech/botai-playwright

Fixture do Playwright que gera uma pessoa brasileira de teste (nome, CPF, RG, CNPJ, celular, CEP real com rua e cidade certas, cartão de teste) reproduzível, e preenche formulários com o mesmo motor da extensão Botaí.

Instalação

npm install -D @pilutech/botai-playwright
# ou
pnpm add -D @pilutech/botai-playwright

@playwright/test (1.59.1 ou mais novo na linha 1.x) é peer dependency: o seu projeto já o tem. O pacote é só ESM; num projeto CommonJS, use o Node 20.19+ ou 22.12+.

Uso

import { test, expect } from '@pilutech/botai-playwright'

test('cadastro', async ({ page, botai }) => {
  await page.goto('/cadastro')
  const resultado = await botai.preencher(page) // percorre todos os frames
  expect(resultado.naoReconhecidos).toEqual([])
  await expect(page.getByLabel('E-mail')).toHaveValue(
    botai.pessoa.email.endereco,
  )
})

botai.preencher aceita:

  • uma Page: todos os frames, inclusive iframes de outro domínio;
  • um Locator: só aquele elemento (um <form>, uma seção ou um campo só), inclusive dentro de iframe (page.frameLocator('iframe').locator('form')).

A pessoa é a mesma a cada execução

Sem opção nenhuma, a semente é o nome do projeto, o arquivo e os títulos do teste: chromium › cadastro.e2e.ts › cadastro. Retry e worker não entram, então a nova tentativa preenche com a mesma pessoa. O fixture registra no relatório:

  • a anotação botai-semente (a semente) e a botai-hoje (a data usada);
  • quando o teste falha, o anexo botai-pessoa.json, com { formato, motor, semente, hoje, pessoa } (o cartão da pessoa leva o provedor e o cenario).

Para gerar a mesma pessoa fora do teste (Python, Go, banco de dados…):

npx @pilutech/botai-core pessoa --semente "chromium › cadastro.e2e.ts › cadastro" --hoje 2026-10-05

A pessoa de uma semente só muda em versão major do @pilutech/botai-core. Para reproduzir, fixe a versão.

Opções

| Opção | Padrão | O quê | | ------------------- | ---------------------- | ------------------------------------------------------------------------- | | botaiSemente | projeto + título | número ou texto; 42 e '42' dão a mesma pessoa | | botaiHoje | hoje em São Paulo | AAAA-MM-DD; idade, nascimento e validade do cartão contam a partir dela | | botaiUf | sorteada | UF do endereço (e do DDD, do CPF e do título) | | botaiDominioEmail | tuamaeaquelaursa.com | domínio do e-mail | | botaiCartao | stripe, aprovado | { provedor, cenario } do cartão de teste (veja abaixo) |

test.use({ botaiHoje: '2026-10-05', botaiUf: 'PI' })

Ou para o projeto inteiro, no playwright.config.ts: use: { botaiHoje: '2026-10-05' }.

Cartão de teste por cenário

O cartão da pessoa usa só números de teste oficiais, da Stripe ou do simulador da Pagar.me. Escolha o provedor e o cenário com botaiCartao:

test.describe('pagamento recusado', () => {
  test.use({ botaiCartao: { provedor: 'pagarme', cenario: 'recusado' } })

  test('mostra o erro do cartão', async ({ page, botai }) => {
    await page.goto('/checkout')
    await botai.preencher(page) // o número do cartão é 4000 0000 0000 0028
    await page.getByRole('button', { name: 'Pagar' }).click()
    await expect(page.getByText('Pagamento recusado')).toBeVisible()
  })
})

| Provedor | Cenários | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | stripe | aprovado, recusado, pendente (exige 3DS), recusado-saldo, recusado-roubado, recusado-perdido, recusado-expirado, recusado-cvc, erro-processamento | | pagarme | aprovado, recusado, pendente (processa e aprova), pendente-recusado, pendente-cancelado, chargeback |

  • O cenário muda só o cartão: com a mesma semente, o resto da pessoa é igual em qualquer cenário. A semente padrão inclui os títulos do teste, então dois describe geram pessoas diferentes; para comparar cenários com a mesma pessoa, fixe botaiSemente.
  • Cenário que o provedor não tem falha no setup do teste com botaiCartao: cenário desconhecido "…" para o provedor … (use …).
  • Para gerar a mesma pessoa fora do teste: npx @pilutech/botai-core pessoa --semente "<semente>" --hoje <hoje> --cartao pagarme --cenario recusado.

Resultado

interface ResultadoDoPreenchimento {
  preenchidos: { frame: string; rotulo: string; seletor: string }[]
  naoReconhecidos: { frame: string; rotulo: string; seletor: string }[]
  recusados: { frame: string; rotulo: string; seletor: string }[]
}

frame é a URL do frame. recusados são campos reconhecidos que não aceitaram o valor (não cabe no maxlength, a página o desfez, o <select> não tem a opção).

Segunda passada

Sites que buscam o CEP sobrescrevem rua, bairro e complemento logo depois. botai.preencher só termina depois de regravar o que mudou (uma passada, 1 s depois de escrever). Para pular: botai.preencher(page, { segundaPassada: false }).

Junto com outros fixtures

import { mergeTests } from '@playwright/test'
import { test as testBotai } from '@pilutech/botai-playwright'
import { test as testDoProjeto } from './fixtures'

export const test = mergeTests(testDoProjeto, testBotai)

Ou estenda um test que você já tem (playwright-bdd, por exemplo):

import { fixturesBotai, type FixturesBotai } from '@pilutech/botai-playwright'

export const test = base.extend<FixturesBotai>(fixturesBotai())

Como funciona

O motor (@pilutech/botai-core/navegador) é injetado em cada frame por frame.evaluate, que passa pela CSP da página, e cria um único global, __botaiNavegador. Ele escreve pelo setter nativo e dispara focus, input, change e blur sintéticos, sem roubar o foco: React controlado, máscaras e validação no blur enxergam o valor. Não pinta contorno nenhum na página.

Limites

  • Shadow root fechada fica de fora (o Playwright não a alcança). A aberta é preenchida.
  • Checkbox, radio, contenteditable e combobox sem <select> nativo não são preenchidos.
  • O código roda no mundo da página: um site que troca protótipos nativos pode interferir.
  • Com page.clock.install(), o relógio falso segura a segunda passada: use { segundaPassada: false } ou avance o relógio.
  • CPF, CNPJ e celular gerados podem pertencer a gente real; use só em ambiente de teste. A caixa tuamaeaquelaursa.com é pública: para dado sensível, use botaiDominioEmail com um domínio seu.

Licença

MIT © PiluTech