Resposta rápida
- O sintoma
AttributeErrorantes de abrir a rotina.- O que ele diz
- o script chama algo que a classe instalada não tem.
- Caso 1
- é
Program, nãoSetProgram. - Caso 2
- a chave é
DataDelimiter. - Caso 3
Setupnão recebe usuário nem senha.
Nesta página7 seções
Um teste que falha em AttributeError antes de abrir a rotina ainda não
encontrou um defeito de negócio. Encontrou uma diferença entre o script e a
interface disponível na instalação. Investigar essa diferença rende mais que
aumentar o tempo de espera ou trocar todos os seletores.
O TIR automatiza a interação com o Protheus, mas os exemplos dependem de
versão, configuração e contexto de tela. Este roteiro mostra como conferir
esses elementos antes de concluir que a ferramenta ou a rotina está quebrada.
Os três casos abaixo foram conferidos no código do TIR, no commit 58da2b8
de 05/08/2026 (versão 2.14.5rc1).
Comece pela instalação que executa o teste
É comum haver mais de um Python na máquina, além de ambientes virtuais e checkouts do mesmo projeto. A documentação aberta no navegador pode ser de uma versão diferente da biblioteca que o script importa.
Registre o executável, o caminho do módulo importado e a versão do pacote:
python -c "import tir, sys; print(sys.executable); print(tir.__file__)"
pip show tir-frameworkNum checkout, registre a revisão (git rev-parse --short HEAD). Com isso o
erro fica reproduzível para outra pessoa. “Estou na 2.14” sem dizer qual
Python está rodando é uma falsa certeza logo na primeira linha do diagnóstico.
Caso 1: Program e SetProgram
Na classe Webapp (tir/main.py), o método público é Program:
def Program(self, program_name: str, module: str = ''):Não existe SetProgram nessa classe. Diante de um exemplo que chama o
segundo, o primeiro passo é conferir a origem e a versão para a qual ele foi
escrito.
Program recebe o nome do programa e um módulo opcional, e a descrição do
método delimita o contexto: uso com programa inicial correspondente ao módulo.
Trocar o nome do método mecanicamente elimina o AttributeError, mas não
garante que a chamada faça sentido no estado atual da tela. Resolver a
incompatibilidade de API e resolver a navegação são duas coisas.
Caso 2: nomes de configuração são contratos
No carregador de configuração (tir/technologies/core/config.py), a chave
lida é DataDelimiter, e ela aparece tanto na leitura do valor (com / como
padrão) quanto na lista de chaves reconhecidas. Um rótulo com espaço numa
tabela de documentação não vai para o JSON sem conferir o nome técnico.
Se a mensagem aponta chave inesperada, revise grafia, maiúsculas e estrutura do arquivo. Não contorne removendo a validação: ela está mostrando uma configuração que a biblioteca não reconhece.
Guarde um config.json mínimo válido para a versão usada, sem credencial. O
time compartilha a estrutura sem distribuir senha.
Caso 3: a ordem de Setup importa
A assinatura em Webapp.Setup:
def Setup(self, initial_program, date="", group="99", branch="01", module=""):Programa inicial, data, grupo, filial e módulo. Usuário e senha não estão aí;
vêm do config.json. Um exemplo de outra ferramenta pode parecer plausível e
deslocar todos os valores.
Prefira argumentos nomeados (Setup("SIGAFAT", branch="01")). O nome certo
não valida o conteúdo: a filial precisa existir no ambiente de teste e a data
precisa fazer sentido para o cenário.
Não use a data de hoje em todo teste. Fechamento, vencimento e virada de período pedem data fixa e controlada, com massa de dados compatível.
A biblioteca certa ainda pode receber a tela errada
Alinhada a API, confirme o estado da aplicação antes das ações importantes. Um botão com o mesmo texto existe em dois diálogos. Um campo pode estar em outra aba ou indisponível naquele contexto.
Na falha, capture a tela e a última ação concluída, e compare com o estado que o teste esperava. Espera maior não corrige um caminho que abriu a rotina errada.
Não troque verificação por log. Um comando que tentou preencher um campo não prova que o valor ficou disponível para a aplicação. A evidência inclui o resultado observado e, quando pertinente, a consequência funcional da gravação.
Um teste precisa verificar uma consequência
Um script que abre telas, preenche campos e fecha o navegador pode terminar sem provar nada. Defina o resultado esperado antes das ações: qual registro deve existir, qual mensagem deve aparecer, qual operação deve ser recusada.
O TIR tem CheckResult(field, user_value, ...) para conferir o valor de um
campo, e AssertTrue/AssertFalse para fechar o cenário. Use a mensagem de
script: “esperava o cadastro de demonstração gravado após a confirmação”
orienta o diagnóstico melhor que um booleano.
As assinaturas confirmam o que cada chamada espera, e vale conferi-las antes
de copiar um exemplo. CheckResult(field, user_value, grid=False, line=1, grid_number=1, ...) (tir/main.py:166) só compara a linha certa da grade se
o script passar grid=True e o número da linha; sem isso, a comparação recai
sempre sobre a primeira linha da tela. AssertTrue(expected=True, scritp_message='') (linha 108) e AssertFalse(expected=False, scritp_message='') (linha 95) recebem a mensagem do cenário no parâmetro
scritp_message, grafado assim — com a troca de letras — na classe Webapp
desta versão. Um script que nomeie o argumento pela grafia correta,
script_message=, recebe TypeError: unexpected keyword argument, o mesmo
tipo de falha que abre este roteiro. A classe Poui, no mesmo arquivo, herda
o mesmo nome de método com contrato diferente, e é aí que a conferência paga:
AssertTrue (linha 1886) e AssertFalse (linha 1873) recebem
script_message, já com a grafia corrigida — o oposto da Webapp —, mas
CheckResult(field=None, user_value=None, po_component='po-input', position=1) (linha 2053) não tem parâmetro de mensagem nenhum, nem
grid, nem line, nem grid_number. Mesmo nome, três assinaturas
diferentes: confirmar qual classe o script importa vale mais que decorar a
ordem dos argumentos.
Mantenha a limpeza previsível. Se um teste altera parâmetro ou deixa tela aberta, o próximo falha por herança. O relatório distingue falha do cenário de falha de preparação ou encerramento.
Como relatar uma divergência com precisão
Link e revisão da documentação, versão ou commit do código, chamada mínima, erro completo e resultado esperado. Se só uma nota antiga menciona a divergência, apresente-a como histórico até recuperar a evidência.
Em vez de “a documentação está errada”: “nesta revisão, este exemplo chama um método que esta classe não expõe”. É afirmação delimitada, verificável e muito mais fácil de corrigir, inclusive numa contribuição ao próprio TIR.
A mesma disciplina vale quando quem sugere a chamada é uma IA, não um exemplo antigo: o texto pode soar igualmente confiante sobre um método ou um campo que não existe na versão instalada. Ver A IA inventou um campo do Protheus: como dar contexto para reduzir esse erro.
Referências
Outrogithub.com
TOTVS — TIR, Test Interface Robot (repositório)
Continue por aqui
- Vídeo
DesenvolvimentoReferência técnica
F340VALOK: o ponto de entrada que barra o OK da compensação a pagar
F340VALOK roda ao clicar OK na lista de títulos da compensação a pagar, recebe a lista em PARAMIXB e, retornando .F., mantém o usuário na lista.
- Vídeo
DesenvolvimentoReferência técnica
F340VLD: o ponto de entrada que barra a compensação no Contas a Pagar
F340VLD roda ao confirmar a primeira tela da compensação a pagar (FINA340), sem PARAMIXB. Retornando .F., a tela não fecha e nenhum título chega a ser listado.
- Vídeo
DesenvolvimentoReferência técnica
F40DELPR: o ponto de entrada que troca a baixa do provisório pela exclusão
F40DELPR roda ao abrir a substituição de título provisório no Contas a Receber, sem PARAMIXB. Retornando .T., o provisório é excluído em vez de baixado.