test(analytics): add unit tests for AVM batch, history, comparison endpoints

Add comprehensive test coverage for the three AVM API upgrade endpoints:
- BatchValuationHandler: batch results, partial failures, error handling
- ValuationHistoryHandler: history retrieval, limit, empty state, errors
- ValuationComparisonHandler: multi-property compare, summary, edge cases
- AnalyticsController: route-level tests for all new endpoints

Fix async error handling in handlers by adding await to cache.getOrSet
calls so try/catch blocks properly catch rejections.

Fix pre-existing web test failures: add missing FLOOD_RISK_OPTIONS and
QUALITY_LABELS to valuation-form mock, update valuation-results assertions
to match current component rendering.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-16 17:28:38 +07:00
parent ac4191cdf0
commit 74804757c5
9 changed files with 467 additions and 9 deletions

View File

@@ -1,8 +1,12 @@
import { type QueryBus } from '@nestjs/cqrs';
import { BatchValuationQuery } from '../../application/queries/batch-valuation/batch-valuation.query';
import { GetDistrictStatsQuery } from '../../application/queries/get-district-stats/get-district-stats.query';
import { GetHeatmapQuery } from '../../application/queries/get-heatmap/get-heatmap.query';
import { GetMarketReportQuery } from '../../application/queries/get-market-report/get-market-report.query';
import { GetPriceTrendQuery } from '../../application/queries/get-price-trend/get-price-trend.query';
import { GetValuationQuery } from '../../application/queries/get-valuation/get-valuation.query';
import { ValuationComparisonQuery } from '../../application/queries/valuation-comparison/valuation-comparison.query';
import { ValuationHistoryQuery } from '../../application/queries/valuation-history/valuation-history.query';
import { AnalyticsController } from '../controllers/analytics.controller';
describe('AnalyticsController', () => {
@@ -76,4 +80,80 @@ describe('AnalyticsController', () => {
);
expect(result).toBe(expected);
});
it('getValuation executes GetValuationQuery with correct params', async () => {
const expected = { estimatedPrice: '5000000000', confidence: 0.85 };
mockQueryBus.execute.mockResolvedValue(expected);
const result = await controller.getValuation({
propertyId: 'prop-123',
latitude: undefined,
longitude: undefined,
areaM2: undefined,
propertyType: undefined,
} as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new GetValuationQuery('prop-123', undefined, undefined, undefined, undefined),
);
expect(result).toBe(expected);
});
it('batchValuation executes BatchValuationQuery with correct params', async () => {
const expected = [
{ propertyId: 'prop-1', valuation: { estimatedPrice: '5000000000' } },
{ propertyId: 'prop-2', valuation: { estimatedPrice: '6000000000' } },
];
mockQueryBus.execute.mockResolvedValue(expected);
const result = await controller.batchValuation({
propertyIds: ['prop-1', 'prop-2'],
} as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new BatchValuationQuery(['prop-1', 'prop-2']),
);
expect(result).toBe(expected);
});
it('getValuationHistory executes ValuationHistoryQuery with correct params', async () => {
const expected = { propertyId: 'prop-1', history: [], totalRecords: 0 };
mockQueryBus.execute.mockResolvedValue(expected);
const result = await controller.getValuationHistory('prop-1', { limit: 25 } as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new ValuationHistoryQuery('prop-1', 25),
);
expect(result).toBe(expected);
});
it('getValuationHistory defaults limit to 50', async () => {
const expected = { propertyId: 'prop-1', history: [], totalRecords: 0 };
mockQueryBus.execute.mockResolvedValue(expected);
const result = await controller.getValuationHistory('prop-1', {} as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new ValuationHistoryQuery('prop-1', 50),
);
expect(result).toBe(expected);
});
it('compareValuations executes ValuationComparisonQuery with correct params', async () => {
const expected = {
properties: [],
summary: { highestValue: null, lowestValue: null, averagePricePerM2: 0, averageConfidence: 0 },
};
mockQueryBus.execute.mockResolvedValue(expected);
const result = await controller.compareValuations({
propertyIds: ['prop-1', 'prop-2', 'prop-3'],
} as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new ValuationComparisonQuery(['prop-1', 'prop-2', 'prop-3']),
);
expect(result).toBe(expected);
});
});