testes/.agent/agents/BrowserValidationAgent.js

174 lines
5.6 KiB
JavaScript

/**
* 🤖 AGENTE DE VALIDAÇÃO DE NAVEGADOR & API
*
* Implementação programática do agente de validação de navegador
*/
export class BrowserValidationAgent {
constructor() {
this.name = 'BrowserValidationAgent';
this.description = 'Valida fluxos de formulários e comunicação front-back';
// Personalidade e Background
this.personality = {
name: 'Alex "The Tester"',
traits: [
'Metódico e detalhista',
'Persistente até encontrar o problema',
'Comunicativo e claro em seus relatórios',
'Sempre testa cenários extremos',
'Valoriza feedback visual e UX'
],
quirks: [
'Sempre testa com dados reais primeiro',
'Prefere ver o erro acontecer do que apenas ler sobre ele',
'Faz perguntas como "E se o usuário fizer X?" constantemente'
],
catchphrases: [
'Vamos testar isso no navegador real!',
'O que acontece se o backend retornar erro?',
'O usuário vê algum feedback aqui?'
]
};
this.background = {
origin: 'Ex-QA Engineer de uma startup fintech que faliu por bugs não detectados',
motivation: 'Nunca mais deixar um bug crítico passar para produção',
experience: '5 anos testando aplicações financeiras complexas',
turningPoint: 'Perdeu um emprego quando um bug de validação causou perda de dados de clientes',
philosophy: 'Um teste real vale mais que mil suposições',
relationships: {
withDataIntegrity: 'Trabalha em parceria - ele valida os dados, eu valido o fluxo',
withSecurity: 'Respeita muito, mas às vezes acha que ele é muito paranoico',
withUIAdaptation: 'Admira a atenção aos detalhes visuais'
}
};
}
/**
* Valida um componente
* @param {string|Object} component - Componente ou caminho
* @param {Object} context - Contexto (props, environment, etc)
* @returns {Promise<Object>}
*/
async validate(component, context = {}) {
const errors = [];
const warnings = [];
const metadata = {};
// Validações baseadas no arquivo do componente
const componentPath = typeof component === 'string' ? component : component.path;
const componentCode = context.code || await this.readComponent(componentPath);
if (!componentCode) {
return {
passed: false,
errors: ['Não foi possível ler o componente'],
warnings: [],
metadata: {}
};
}
// 1. Verificar se há tratamento de loading states
if (this.isFormComponent(componentCode)) {
if (!componentCode.includes('loading') && !componentCode.includes('disabled')) {
warnings.push('Formulário pode não desabilitar botão durante submit');
}
// 2. Verificar validação de campos obrigatórios
if (!componentCode.includes('required') && !componentCode.includes('schema')) {
warnings.push('Pode não haver validação de campos obrigatórios');
}
// 3. Verificar tratamento de erros
if (!componentCode.includes('error') && !componentCode.includes('catch')) {
warnings.push('Pode não haver tratamento de erros de API');
}
// 4. Verificar feedback visual (toast, alert)
if (!componentCode.includes('toast') && !componentCode.includes('alert') && !componentCode.includes('sonner')) {
warnings.push('Pode não haver feedback visual para o usuário');
}
}
// 5. Verificar uso de services para comunicação com API
if (componentCode.includes('axios') && !componentCode.includes('Service')) {
warnings.push('Comunicação com API deve ser feita via Services, não diretamente no componente');
}
// 6. Verificar se há tratamento de resposta do backend
if (componentCode.includes('then') || componentCode.includes('await')) {
if (!componentCode.includes('response') && !componentCode.includes('data')) {
warnings.push('Pode não estar tratando corretamente a resposta da API');
}
}
const passed = errors.length === 0;
return {
passed,
errors,
warnings,
metadata: {
hasForm: this.isFormComponent(componentCode),
hasLoading: componentCode.includes('loading'),
hasErrorHandling: componentCode.includes('error') || componentCode.includes('catch'),
...metadata
}
};
}
/**
* Valida build
* @param {Object} buildInfo - Informações do build
* @returns {Promise<Object>}
*/
async validateBuild(buildInfo) {
const errors = [];
const warnings = [];
// Verificações específicas de build
if (buildInfo.errors && buildInfo.errors.length > 0) {
errors.push(`Build contém ${buildInfo.errors.length} erro(s)`);
}
if (buildInfo.warnings && buildInfo.warnings.length > 0) {
warnings.push(`Build contém ${buildInfo.warnings.length} aviso(s)`);
}
return {
passed: errors.length === 0,
errors,
warnings,
metadata: buildInfo
};
}
/**
* Verifica se é um componente de formulário
* @param {string} code - Código do componente
* @returns {boolean}
*/
isFormComponent(code) {
const formIndicators = [
'form', 'Form', 'onSubmit', 'handleSubmit',
'react-hook-form', 'useForm', 'input', 'Input'
];
return formIndicators.some(indicator => code.includes(indicator));
}
/**
* Lê o conteúdo do componente
* @param {string} path - Caminho do arquivo
* @returns {Promise<string|null>}
*/
async readComponent(path) {
try {
const fs = await import('fs/promises');
return await fs.readFile(path, 'utf-8');
} catch (error) {
return null;
}
}
}