jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
708 lines (640 loc) • 17.1 kB
text/typescript
/**
* Tester Agent - Specialized in testing and quality assurance
*/
import { BaseAgent } from './base-agent.js';
import type {
AgentCapabilities,
AgentConfig,
AgentEnvironment,
TaskDefinition,
} from '../../swarm/types.js';
import type { ILogger } from '../../core/logger.js';
import type { IEventBus } from '../../core/event-bus.js';
import type { DistributedMemorySystem } from '../../memory/distributed-memory.js';
// Type definitions for tester activities
interface TestCoverageItem {
path: string;
testCount: number;
coverage: number;
}
interface TestCase {
name: string;
steps: string[];
assertions: string[];
}
interface PerformanceTestCase {
name: string;
steps: string[];
expected: string;
}
interface SecurityIssue {
type: string;
severity: string;
location: string;
description: string;
impact: string;
}
interface ApiTestResult {
endpoint: string;
status: string;
responseTime: number;
statusCode: number;
error?: string;
}
export class TesterAgent extends BaseAgent {
constructor(
id: string,
config: AgentConfig,
environment: AgentEnvironment,
logger: ILogger,
eventBus: IEventBus,
memory: DistributedMemorySystem,
) {
super(id, 'tester', config, environment, logger, eventBus, memory);
}
protected getDefaultCapabilities(): AgentCapabilities {
return {
codeGeneration: true,
codeReview: true,
testing: true,
documentation: true,
research: false,
analysis: true,
webSearch: false,
apiIntegration: true,
fileSystem: true,
terminalAccess: true,
languages: ['typescript', 'javascript', 'python', 'java', 'csharp', 'go'],
frameworks: [
'jest',
'mocha',
'cypress',
'playwright',
'selenium',
'pytest',
'junit',
'testng',
],
domains: [
'unit-testing',
'integration-testing',
'e2e-testing',
'performance-testing',
'security-testing',
'accessibility-testing',
'api-testing',
'mobile-testing',
'load-testing',
'test-automation',
],
tools: [
'test-runner',
'coverage-analyzer',
'mock-generator',
'test-data-factory',
'assertion-library',
'browser-automation',
'api-tester',
'performance-profiler',
],
maxConcurrentTasks: 4,
maxMemoryUsage: 1024 * 1024 * 1024, // 1GB
maxExecutionTime: 1800000, // 30 minutes
reliability: 0.95,
speed: 0.8,
quality: 0.95,
};
}
protected getDefaultConfig(): Partial<AgentConfig> {
return {
autonomyLevel: 0.8,
learningEnabled: true,
adaptationEnabled: true,
maxTasksPerHour: 16,
maxConcurrentTasks: 4,
timeoutThreshold: 1800000,
reportingInterval: 30000,
heartbeatInterval: 12000,
permissions: [
'file-read',
'file-write',
'terminal-access',
'browser-control',
'network-access',
],
trustedAgents: [],
expertise: {
'unit-testing': 0.95,
'integration-testing': 0.9,
'e2e-testing': 0.88,
'test-automation': 0.92,
'performance-testing': 0.85,
'security-testing': 0.8,
},
preferences: {
testFramework: 'jest',
coverageThreshold: 80,
testStrategy: 'pyramid',
mockingStyle: 'minimal',
reportFormat: 'detailed',
},
};
}
override async executeTask(task: TaskDefinition): Promise<any> {
this.logger.info('Tester executing task', {
agentId: this.id,
taskType: task.type,
taskId: task.id,
});
try {
switch (task.type) {
case 'unit-testing':
return await this.createUnitTests(task);
case 'integration-testing':
return await this.createIntegrationTests(task);
case 'e2e-testing':
return await this.createE2ETests(task);
case 'performance-testing':
return await this.performanceTest(task);
case 'security-testing':
return await this.securityTest(task);
case 'api-testing':
return await this.testAPI(task);
case 'test-automation':
return await this.automateTests(task);
case 'test-analysis':
return await this.analyzeTests(task);
default:
return await this.performGeneralTesting(task);
}
} catch (error) {
this.logger.error('Testing task failed', {
agentId: this.id,
taskId: task.id,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
private async createUnitTests(task: TaskDefinition): Promise<any> {
const code = task.input?.code;
const framework = task.input?.framework || 'jest';
const coverage = task.input?.coverage || 80;
const style = task.input?.style || 'arrange-act-assert';
this.logger.info('Creating unit tests', {
framework,
coverage,
style,
});
const testing = {
framework,
style,
targetCoverage: coverage,
testFiles: [] as TestCoverageItem[],
testSuites: [] as any[],
coverage: {
lines: 0,
functions: 0,
branches: 0,
statements: 0,
},
mocks: [] as any[],
assertions: [] as any[],
setup: {
beforeEach: true,
afterEach: true,
fixtures: [] as any[],
},
timestamp: new Date(),
};
// Simulate unit test creation
await this.delay(2000);
testing.testFiles = [
{
path: 'tests/unit/user.test.ts',
testCount: 15,
coverage: 92,
},
{
path: 'tests/unit/auth.test.ts',
testCount: 8,
coverage: 88,
},
];
testing.coverage = {
lines: 87,
functions: 92,
branches: 78,
statements: 89,
};
return testing;
}
private async createIntegrationTests(task: TaskDefinition): Promise<any> {
const components = task.input?.components || [];
const database = task.input?.database || false;
const api = task.input?.api || false;
const framework = task.input?.framework || 'jest';
this.logger.info('Creating integration tests', {
components: components.length,
database,
api,
framework,
});
const integration = {
framework,
components,
database,
api,
testSuites: [] as any[],
environment: {
setup: 'docker-compose',
database: 'test-db',
services: [] as any[],
},
scenarios: [] as TestCase[],
dataFlow: [] as any[],
assertions: [] as any[],
timestamp: new Date(),
};
// Simulate integration test creation
await this.delay(3000);
integration.scenarios = [
{
name: 'User registration flow',
steps: ['Create user', 'Send email', 'Verify account'],
assertions: ['User created', 'Email sent', 'Account active'],
},
{
name: 'Order processing flow',
steps: ['Create order', 'Process payment', 'Update inventory'],
assertions: ['Order confirmed', 'Payment processed', 'Stock updated'],
},
];
return integration;
}
private async createE2ETests(task: TaskDefinition): Promise<any> {
const userJourneys = task.input?.userJourneys || [];
const browser = task.input?.browser || 'chromium';
const framework = task.input?.framework || 'playwright';
const viewport = task.input?.viewport || 'desktop';
this.logger.info('Creating E2E tests', {
userJourneys: userJourneys.length,
browser,
framework,
viewport,
});
const e2e = {
framework,
browser,
viewport,
userJourneys,
testScenarios: [] as PerformanceTestCase[],
pageObjects: [] as any[],
selectors: [] as any[],
assertions: [] as any[],
configuration: {
headless: true,
screenshots: true,
videos: false,
retries: 2,
},
crossBrowser: {
chrome: true,
firefox: true,
safari: false,
},
timestamp: new Date(),
};
// Simulate E2E test creation
await this.delay(4000);
e2e.testScenarios = [
{
name: 'User login and dashboard access',
steps: [
'Navigate to login page',
'Enter credentials',
'Click login button',
'Verify dashboard loads',
],
expected: 'User successfully logged in and sees dashboard',
},
];
return e2e;
}
private async performanceTest(task: TaskDefinition): Promise<any> {
const target = task.input?.target;
const loadPattern = task.input?.loadPattern || 'ramp-up';
const duration = task.input?.duration || '5m';
const virtualUsers = task.input?.virtualUsers || 100;
this.logger.info('Performing performance test', {
target,
loadPattern,
duration,
virtualUsers,
});
const performance = {
target,
loadPattern,
duration,
virtualUsers,
metrics: {
responseTime: {
avg: 0,
p95: 0,
p99: 0,
max: 0,
},
throughput: 0,
errorRate: 0,
resourceUtilization: {
cpu: 0,
memory: 0,
network: 0,
},
},
bottlenecks: [],
recommendations: [],
slaCompliance: {
responseTime: false,
throughput: false,
errorRate: false,
},
timestamp: new Date(),
};
// Simulate performance testing
await this.delay(6000);
performance.metrics = {
responseTime: {
avg: 245,
p95: 520,
p99: 1200,
max: 2500,
},
throughput: 1250,
errorRate: 0.03,
resourceUtilization: {
cpu: 75,
memory: 68,
network: 45,
},
};
return performance;
}
private async securityTest(task: TaskDefinition): Promise<any> {
const target = task.input?.target;
const testTypes = task.input?.types || ['authentication', 'authorization', 'injection'];
const severity = task.input?.severity || 'all';
this.logger.info('Performing security test', {
target,
testTypes,
severity,
});
const security = {
target,
testTypes,
severity,
vulnerabilities: [] as SecurityIssue[],
compliance: {
owasp: [] as any[],
gdpr: [] as any[],
pci: [] as any[],
},
penetrationTests: [] as any[],
recommendations: [] as any[],
riskLevel: 'unknown',
timestamp: new Date(),
};
// Simulate security testing
await this.delay(5000);
security.vulnerabilities = [
{
type: 'SQL Injection',
severity: 'high',
location: '/api/users/search',
description: 'Input not properly sanitized',
impact: 'Data breach potential',
},
];
security.riskLevel = 'medium';
return security;
}
private async testAPI(task: TaskDefinition): Promise<any> {
const endpoints = task.input?.endpoints || [];
const authentication = task.input?.auth || false;
const environment = task.input?.environment || 'staging';
this.logger.info('Testing API', {
endpoints: endpoints.length,
authentication,
environment,
});
const apiTest = {
environment,
authentication,
endpoints,
testResults: [] as ApiTestResult[],
schemas: [] as any[],
responseValidation: true,
errorHandling: [] as any[],
performance: {
averageResponseTime: 0,
slowestEndpoint: '',
fastestEndpoint: '',
},
coverage: {
endpoints: 0,
statusCodes: [] as any[],
errorScenarios: 0,
},
timestamp: new Date(),
};
// Simulate API testing
await this.delay(3000);
apiTest.testResults = [
{
endpoint: 'GET /api/users',
status: 'passed',
responseTime: 150,
statusCode: 200,
},
{
endpoint: 'POST /api/users',
status: 'failed',
responseTime: 300,
statusCode: 500,
error: 'Internal server error',
},
];
return apiTest;
}
private async automateTests(task: TaskDefinition): Promise<any> {
const testSuite = task.input?.testSuite;
const pipeline = task.input?.pipeline || 'ci/cd';
const triggers = task.input?.triggers || ['commit', 'pr'];
this.logger.info('Automating tests', {
testSuite,
pipeline,
triggers,
});
const automation = {
testSuite,
pipeline,
triggers,
configuration: {
parallel: true,
retries: 2,
timeout: '30m',
artifacts: ['reports', 'screenshots'],
},
environments: ['staging', 'production'],
notifications: {
slack: true,
email: true,
github: true,
},
reporting: {
format: 'junit',
coverage: true,
trends: true,
},
timestamp: new Date(),
};
// Simulate test automation setup
await this.delay(2000);
return automation;
}
private async analyzeTests(task: TaskDefinition): Promise<any> {
const testResults = task.input?.results;
const coverage = task.input?.coverage;
const timeframe = task.input?.timeframe || '7d';
this.logger.info('Analyzing tests', {
timeframe,
});
const analysis = {
timeframe,
summary: {
totalTests: 0,
passed: 0,
failed: 0,
skipped: 0,
flaky: 0,
},
trends: {
passRate: [] as any[],
executionTime: [] as any[],
coverage: [] as any[],
},
flakyTests: [] as any[],
slowTests: [] as any[],
recommendations: [] as any[],
insights: [] as string[],
timestamp: new Date(),
};
// Simulate test analysis
await this.delay(1500);
analysis.summary = {
totalTests: 245,
passed: 230,
failed: 10,
skipped: 5,
flaky: 3,
};
analysis.insights = [
'Test execution time increased by 15% this week',
'Coverage decreased in auth module',
'3 tests are consistently flaky and need attention',
];
return analysis;
}
private async performGeneralTesting(task: TaskDefinition): Promise<any> {
this.logger.info('Performing general testing', {
description: task.description,
});
// Default to unit testing
return await this.createUnitTests(task);
}
private async delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
override getAgentStatus(): any {
return {
...super.getAgentStatus(),
specialization: 'Testing & Quality Assurance',
testingTypes: [
'Unit Testing',
'Integration Testing',
'E2E Testing',
'Performance Testing',
'Security Testing',
'API Testing',
],
frameworks: this.capabilities.frameworks,
currentTests: this.getCurrentTasks().length,
averageTestTime: '15-30 minutes',
lastTestCompleted: this.getLastTaskCompletedTime(),
testCoverageGoal: this.config.preferences?.coverageThreshold || 80,
};
}
}
export const createTesterAgent = (
id: string,
config: Partial<AgentConfig>,
environment: Partial<AgentEnvironment>,
logger: ILogger,
eventBus: IEventBus,
memory: DistributedMemorySystem,
): TesterAgent => {
const defaultConfig = {
autonomyLevel: 0.7,
learningEnabled: true,
adaptationEnabled: true,
maxTasksPerHour: 8,
maxConcurrentTasks: 2,
timeoutThreshold: 900000,
reportingInterval: 180000,
heartbeatInterval: 60000,
permissions: [
'test-execution',
'code-access',
'system-access',
'browser-automation',
'security-testing',
],
trustedAgents: [],
expertise: {
'unit-testing': 0.95,
'integration-testing': 0.92,
'e2e-testing': 0.9,
'performance-testing': 0.88,
'security-testing': 0.85,
'api-testing': 0.9,
},
preferences: {
testingApproach: 'comprehensive',
coverageThreshold: 85,
testingFramework: 'jest',
automationLevel: 'high',
},
};
const defaultEnv = {
runtime: 'deno' as const,
version: '1.40.0',
workingDirectory: './agents/tester',
tempDirectory: './tmp/tester',
logDirectory: './logs/tester',
apiEndpoints: {},
credentials: {},
availableTools: ['test-runner', 'coverage-analyzer', 'browser-automation', 'api-tester'],
toolConfigs: {
testRunner: { framework: 'jest', coverage: true },
browser: { headless: true, screenshots: true },
},
};
return new TesterAgent(
id,
{ ...defaultConfig, ...config } as AgentConfig,
{ ...defaultEnv, ...environment } as AgentEnvironment,
logger,
eventBus,
memory,
);
};