consulta history fix
This commit is contained in:
parent
20a8c33959
commit
4af6ffc728
69
server/src/services/__tests__/consultaHistoryService.test.ts
Normal file
69
server/src/services/__tests__/consultaHistoryService.test.ts
Normal 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'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { ConsultaHistory, IConsultaHistory, IConsultaHistoryWithUser } from '../models/ConsultaHistory';
|
import { ConsultaHistory, IConsultaHistory, IConsultaHistoryWithUser } from '../models/ConsultaHistory';
|
||||||
import { AuthenticatedRequest } from '../types/auth';
|
import { AuthenticatedRequest } from '../types/auth';
|
||||||
import { Request, Response } from 'express';
|
|
||||||
import { EvaluationJob, EvaluationResult } from '../models/evaluation';
|
import { EvaluationJob, EvaluationResult } from '../models/evaluation';
|
||||||
|
|
||||||
export interface ConsultaLogData {
|
export interface ConsultaLogData {
|
||||||
|
|
@ -286,9 +285,22 @@ export class ConsultaHistoryService {
|
||||||
]),
|
]),
|
||||||
ConsultaHistory.aggregate([
|
ConsultaHistory.aggregate([
|
||||||
{ $match: query },
|
{ $match: query },
|
||||||
|
{
|
||||||
|
$addFields: {
|
||||||
|
createdAtDate: {
|
||||||
|
$convert: {
|
||||||
|
input: '$createdAt',
|
||||||
|
to: 'date',
|
||||||
|
onError: null,
|
||||||
|
onNull: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ $match: { createdAtDate: { $ne: null } } },
|
||||||
{
|
{
|
||||||
$group: {
|
$group: {
|
||||||
_id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } },
|
_id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAtDate' } },
|
||||||
count: { $sum: 1 }
|
count: { $sum: 1 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import dotenv from 'dotenv';
|
||||||
import { TextEncoder, TextDecoder } from 'util';
|
import { TextEncoder, TextDecoder } from 'util';
|
||||||
|
|
||||||
// Polyfills for Node.js environment
|
// Polyfills for Node.js environment
|
||||||
global.TextEncoder = TextEncoder;
|
global.TextEncoder = TextEncoder as any;
|
||||||
global.TextDecoder = TextDecoder as any;
|
global.TextDecoder = TextDecoder as any;
|
||||||
|
|
||||||
// Load test environment variables
|
// Load test environment variables
|
||||||
|
|
@ -57,8 +57,13 @@ jest.mock('../services/notificationService', () => ({
|
||||||
|
|
||||||
// Global test database setup
|
// Global test database setup
|
||||||
let mongoServer: MongoMemoryServer;
|
let mongoServer: MongoMemoryServer;
|
||||||
|
const shouldStartMongoMemoryServer = process.env.SKIP_MONGO_MEMORY_SERVER !== 'true';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
if (!shouldStartMongoMemoryServer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Start in-memory MongoDB instance
|
// Start in-memory MongoDB instance
|
||||||
mongoServer = await MongoMemoryServer.create();
|
mongoServer = await MongoMemoryServer.create();
|
||||||
const mongoUri = mongoServer.getUri();
|
const mongoUri = mongoServer.getUri();
|
||||||
|
|
@ -68,6 +73,10 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
if (!shouldStartMongoMemoryServer || mongoose.connection.readyState !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear all collections before each test
|
// Clear all collections before each test
|
||||||
const collections = mongoose.connection.collections;
|
const collections = mongoose.connection.collections;
|
||||||
for (const key in collections) {
|
for (const key in collections) {
|
||||||
|
|
@ -77,6 +86,10 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
if (!shouldStartMongoMemoryServer || !mongoServer || mongoose.connection.readyState === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
await mongoose.connection.dropDatabase();
|
await mongoose.connection.dropDatabase();
|
||||||
await mongoose.connection.close();
|
await mongoose.connection.close();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user