consulta history fix

This commit is contained in:
valenti 2026-04-13 07:59:33 -04:00
parent 20a8c33959
commit 4af6ffc728
3 changed files with 98 additions and 4 deletions

View File

@ -0,0 +1,69 @@
import { ConsultaHistory } from '../../models/ConsultaHistory';
import { ConsultaHistoryService } from '../consultaHistoryService';
jest.mock('../../models/ConsultaHistory', () => ({
ConsultaHistory: {
countDocuments: jest.fn(),
aggregate: jest.fn()
}
}));
describe('ConsultaHistoryService.getConsultaStats', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('guards daily stats aggregation by converting invalid createdAt values safely', async () => {
const tenantId = 'tenant-test';
const countDocumentsMock = ConsultaHistory.countDocuments as jest.Mock;
const aggregateMock = ConsultaHistory.aggregate as jest.Mock;
countDocumentsMock
.mockResolvedValueOnce(2)
.mockResolvedValueOnce(1)
.mockResolvedValueOnce(1)
.mockResolvedValueOnce(1)
.mockResolvedValueOnce(1);
aggregateMock
.mockResolvedValueOnce([{ totalCredits: 1 }])
.mockResolvedValueOnce([{ avgTime: 150 }])
.mockResolvedValueOnce([{ _id: '2026-01-02', count: 1 }])
.mockResolvedValueOnce([{ _id: '/api/rut/lookup', count: 2 }]);
const stats = await ConsultaHistoryService.getConsultaStats(tenantId);
expect(stats.totalConsultations).toBe(2);
expect(stats.consultationsByDay).toEqual([{ date: '2026-01-02', count: 1 }]);
expect(stats.consultationsByEndpoint).toEqual([{ endpoint: '/api/rut/lookup', count: 2 }]);
expect(aggregateMock).toHaveBeenCalledTimes(4);
const dailyStatsPipeline = aggregateMock.mock.calls[2][0];
expect(dailyStatsPipeline).toEqual(
expect.arrayContaining([
{ $match: { tenantId } },
{
$addFields: {
createdAtDate: {
$convert: {
input: '$createdAt',
to: 'date',
onError: null,
onNull: null
}
}
}
},
{ $match: { createdAtDate: { $ne: null } } }
])
);
const groupStage = dailyStatsPipeline.find((stage: any) => stage.$group);
expect(groupStage.$group._id).toEqual({
$dateToString: {
format: '%Y-%m-%d',
date: '$createdAtDate'
}
});
});
});

View File

@ -1,6 +1,5 @@
import { ConsultaHistory, IConsultaHistory, IConsultaHistoryWithUser } from '../models/ConsultaHistory';
import { AuthenticatedRequest } from '../types/auth';
import { Request, Response } from 'express';
import { EvaluationJob, EvaluationResult } from '../models/evaluation';
export interface ConsultaLogData {
@ -286,9 +285,22 @@ export class ConsultaHistoryService {
]),
ConsultaHistory.aggregate([
{ $match: query },
{
$addFields: {
createdAtDate: {
$convert: {
input: '$createdAt',
to: 'date',
onError: null,
onNull: null
}
}
}
},
{ $match: { createdAtDate: { $ne: null } } },
{
$group: {
_id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } },
_id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAtDate' } },
count: { $sum: 1 }
}
},

View File

@ -4,7 +4,7 @@ import dotenv from 'dotenv';
import { TextEncoder, TextDecoder } from 'util';
// Polyfills for Node.js environment
global.TextEncoder = TextEncoder;
global.TextEncoder = TextEncoder as any;
global.TextDecoder = TextDecoder as any;
// Load test environment variables
@ -57,8 +57,13 @@ jest.mock('../services/notificationService', () => ({
// Global test database setup
let mongoServer: MongoMemoryServer;
const shouldStartMongoMemoryServer = process.env.SKIP_MONGO_MEMORY_SERVER !== 'true';
beforeAll(async () => {
if (!shouldStartMongoMemoryServer) {
return;
}
// Start in-memory MongoDB instance
mongoServer = await MongoMemoryServer.create();
const mongoUri = mongoServer.getUri();
@ -68,6 +73,10 @@ beforeAll(async () => {
});
beforeEach(async () => {
if (!shouldStartMongoMemoryServer || mongoose.connection.readyState !== 1) {
return;
}
// Clear all collections before each test
const collections = mongoose.connection.collections;
for (const key in collections) {
@ -77,6 +86,10 @@ beforeEach(async () => {
});
afterAll(async () => {
if (!shouldStartMongoMemoryServer || !mongoServer || mongoose.connection.readyState === 0) {
return;
}
// Cleanup
await mongoose.connection.dropDatabase();
await mongoose.connection.close();