- Add GrowerAdvisoryAgent test file - Fix PlantChain constructor initialization order (plantIndex before genesis block) - Fix blockchain.getChain() calls to use blockchain.chain property - Add PropagationType export to blockchain types - Fix SoilComposition.type property references (was soilType) - Fix ClimateConditions.temperatureDay property references (was avgTemperature) - Fix ClimateConditions.humidityAverage property references (was avgHumidity) - Fix LightingConditions.naturalLight.hoursPerDay nested access - Add 'critical' severity to QualityReport issues - Add 'sqm' unit to PlantingRecommendation.quantityUnit - Fix GrowerAdvisoryAgent growthMetrics property access - Update TypeScript to v5 for react-hook-form compatibility - Enable downlevelIteration in tsconfig for Map iteration - Fix crypto Buffer type issues in anonymity.ts - Fix zones.tsx status type comparison - Fix next.config.js images.domains filter - Rename [[...slug]].tsx to [...slug].tsx to resolve routing conflict
215 lines
6.4 KiB
TypeScript
215 lines
6.4 KiB
TypeScript
/**
|
|
* GrowerAdvisoryAgent Tests
|
|
* Tests for the grower advisory and recommendation system
|
|
*/
|
|
|
|
import {
|
|
GrowerAdvisoryAgent,
|
|
getGrowerAdvisoryAgent,
|
|
} from '../../../lib/agents/GrowerAdvisoryAgent';
|
|
|
|
describe('GrowerAdvisoryAgent', () => {
|
|
let agent: GrowerAdvisoryAgent;
|
|
|
|
beforeEach(() => {
|
|
agent = new GrowerAdvisoryAgent();
|
|
});
|
|
|
|
describe('Initialization', () => {
|
|
it('should create agent with correct configuration', () => {
|
|
expect(agent.config.id).toBe('grower-advisory-agent');
|
|
expect(agent.config.name).toBe('Grower Advisory Agent');
|
|
expect(agent.config.enabled).toBe(true);
|
|
expect(agent.config.priority).toBe('high');
|
|
});
|
|
|
|
it('should have correct interval (5 minutes)', () => {
|
|
expect(agent.config.intervalMs).toBe(300000);
|
|
});
|
|
|
|
it('should start in idle status', () => {
|
|
expect(agent.status).toBe('idle');
|
|
});
|
|
|
|
it('should have empty metrics initially', () => {
|
|
const metrics = agent.getMetrics();
|
|
expect(metrics.tasksCompleted).toBe(0);
|
|
expect(metrics.tasksFailed).toBe(0);
|
|
expect(metrics.errors).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('Grower Profile Management', () => {
|
|
it('should register a grower profile', () => {
|
|
const profile = createGrowerProfile('grower-1');
|
|
agent.registerGrowerProfile(profile);
|
|
|
|
const retrieved = agent.getGrowerProfile('grower-1');
|
|
expect(retrieved).not.toBeNull();
|
|
expect(retrieved?.growerId).toBe('grower-1');
|
|
});
|
|
|
|
it('should return null for unknown grower', () => {
|
|
const retrieved = agent.getGrowerProfile('unknown-grower');
|
|
expect(retrieved).toBeNull();
|
|
});
|
|
|
|
it('should update existing profile', () => {
|
|
const profile1 = createGrowerProfile('grower-1');
|
|
profile1.experienceLevel = 'beginner';
|
|
agent.registerGrowerProfile(profile1);
|
|
|
|
const profile2 = createGrowerProfile('grower-1');
|
|
profile2.experienceLevel = 'expert';
|
|
agent.registerGrowerProfile(profile2);
|
|
|
|
const retrieved = agent.getGrowerProfile('grower-1');
|
|
expect(retrieved?.experienceLevel).toBe('expert');
|
|
});
|
|
});
|
|
|
|
describe('Recommendations', () => {
|
|
it('should return empty recommendations for unknown grower', () => {
|
|
const recs = agent.getRecommendations('unknown-grower');
|
|
expect(recs).toEqual([]);
|
|
});
|
|
|
|
it('should get recommendations after profile registration', () => {
|
|
const profile = createGrowerProfile('grower-1');
|
|
agent.registerGrowerProfile(profile);
|
|
|
|
// Recommendations are generated during runOnce
|
|
const recs = agent.getRecommendations('grower-1');
|
|
expect(Array.isArray(recs)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Rotation Advice', () => {
|
|
it('should return null for unknown grower', () => {
|
|
const advice = agent.getRotationAdvice('unknown-grower');
|
|
expect(advice).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('Market Opportunities', () => {
|
|
it('should return array of opportunities', () => {
|
|
const opps = agent.getOpportunities();
|
|
expect(Array.isArray(opps)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Grower Performance', () => {
|
|
it('should return null for unknown grower', () => {
|
|
const perf = agent.getPerformance('unknown-grower');
|
|
expect(perf).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('Seasonal Alerts', () => {
|
|
it('should return array of seasonal alerts', () => {
|
|
const alerts = agent.getSeasonalAlerts();
|
|
expect(Array.isArray(alerts)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Agent Lifecycle', () => {
|
|
it('should start and change status to running', async () => {
|
|
await agent.start();
|
|
expect(agent.status).toBe('running');
|
|
await agent.stop();
|
|
});
|
|
|
|
it('should stop and change status to idle', async () => {
|
|
await agent.start();
|
|
await agent.stop();
|
|
expect(agent.status).toBe('idle');
|
|
});
|
|
|
|
it('should pause when running', async () => {
|
|
await agent.start();
|
|
agent.pause();
|
|
expect(agent.status).toBe('paused');
|
|
await agent.stop();
|
|
});
|
|
|
|
it('should resume after pause', async () => {
|
|
await agent.start();
|
|
agent.pause();
|
|
agent.resume();
|
|
expect(agent.status).toBe('running');
|
|
await agent.stop();
|
|
});
|
|
});
|
|
|
|
describe('Singleton', () => {
|
|
it('should return same instance from getGrowerAdvisoryAgent', () => {
|
|
const agent1 = getGrowerAdvisoryAgent();
|
|
const agent2 = getGrowerAdvisoryAgent();
|
|
expect(agent1).toBe(agent2);
|
|
});
|
|
});
|
|
|
|
describe('Alerts', () => {
|
|
it('should return alerts array', () => {
|
|
const alerts = agent.getAlerts();
|
|
expect(Array.isArray(alerts)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Task Execution', () => {
|
|
it('should execute runOnce successfully', async () => {
|
|
const profile = createGrowerProfile('grower-1');
|
|
agent.registerGrowerProfile(profile);
|
|
|
|
const result = await agent.runOnce();
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.status).toBe('completed');
|
|
expect(result?.type).toBe('grower_advisory');
|
|
});
|
|
|
|
it('should report metrics in task result', async () => {
|
|
const profile = createGrowerProfile('grower-1');
|
|
agent.registerGrowerProfile(profile);
|
|
|
|
const result = await agent.runOnce();
|
|
|
|
expect(result?.result).toHaveProperty('growersAdvised');
|
|
expect(result?.result).toHaveProperty('recommendationsGenerated');
|
|
expect(result?.result).toHaveProperty('opportunitiesIdentified');
|
|
expect(result?.result).toHaveProperty('alertsGenerated');
|
|
});
|
|
|
|
it('should count registered growers', async () => {
|
|
agent.registerGrowerProfile(createGrowerProfile('grower-1'));
|
|
agent.registerGrowerProfile(createGrowerProfile('grower-2'));
|
|
agent.registerGrowerProfile(createGrowerProfile('grower-3'));
|
|
|
|
const result = await agent.runOnce();
|
|
|
|
expect(result?.result?.growersAdvised).toBe(3);
|
|
});
|
|
});
|
|
});
|
|
|
|
// Helper function to create test grower profiles
|
|
function createGrowerProfile(
|
|
growerId: string,
|
|
lat: number = 40.7128,
|
|
lon: number = -74.006
|
|
) {
|
|
return {
|
|
growerId,
|
|
growerName: `Test Grower ${growerId}`,
|
|
location: { latitude: lat, longitude: lon },
|
|
availableSpaceSqm: 100,
|
|
specializations: ['lettuce', 'tomato'],
|
|
certifications: ['organic'],
|
|
experienceLevel: 'intermediate' as const,
|
|
preferredCrops: ['lettuce', 'tomato', 'basil'],
|
|
growingHistory: [
|
|
{ cropType: 'lettuce', successRate: 85, avgYield: 4.5 },
|
|
{ cropType: 'tomato', successRate: 75, avgYield: 8.0 },
|
|
],
|
|
};
|
|
}
|