feat: implement groups risk overview feature with analytics and routes
This commit is contained in:
114
apps/backend/test/analytics-groups-risk.test.ts
Normal file
114
apps/backend/test/analytics-groups-risk.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { beforeEach, describe, expect, it, mock, vi } from 'bun:test';
|
||||
import { Hono } from 'hono';
|
||||
|
||||
const db = {
|
||||
group: {
|
||||
findMany: mock(),
|
||||
},
|
||||
attendee: {
|
||||
findMany: mock(),
|
||||
},
|
||||
classSession: {
|
||||
findMany: mock(),
|
||||
},
|
||||
attendance: {
|
||||
findMany: mock(),
|
||||
},
|
||||
};
|
||||
|
||||
mock.module('@/lib/prisma', () => ({
|
||||
default: db,
|
||||
getPrismaClient: mock(),
|
||||
UnitOfWork: class {
|
||||
executeResult = mock(async (cb: (tx: unknown) => Promise<unknown>) => cb(db));
|
||||
execute = mock(async (cb: (tx: unknown) => Promise<unknown>) => cb(db));
|
||||
},
|
||||
}));
|
||||
|
||||
import { groupsRiskOverviewRoute } from '@/modules/analytics';
|
||||
|
||||
const userId = 'user-1';
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
const now = Date.now();
|
||||
const at = (offsetDays: number) => new Date(now - offsetDays * DAY_MS);
|
||||
|
||||
function makeApp(userValue: unknown) {
|
||||
const app = new Hono();
|
||||
app.use('*', async (c, next) => {
|
||||
c.set('user', userValue as never);
|
||||
await next();
|
||||
});
|
||||
app.route('/groups-risk', groupsRiskOverviewRoute);
|
||||
return app;
|
||||
}
|
||||
|
||||
describe('GET /groups-risk/overview', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('devuelve items vacíos si el usuario no tiene grupos', async () => {
|
||||
prismaFetchGroupFindMany([]);
|
||||
prismaFetchAttendeeFindMany([]);
|
||||
prismaFetchClassSessionFindMany([]);
|
||||
prismaFetchAttendanceFindMany([]);
|
||||
|
||||
const res = await makeApp({ id: userId }).request('/groups-risk/overview');
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.json()).toEqual({ items: [] });
|
||||
});
|
||||
|
||||
it('marca HIGH a un grupo con un alumno con 3 ausencias consecutivas', async () => {
|
||||
prismaFetchGroupFindMany([
|
||||
{ id: 'group-1', name: 'Funcional' },
|
||||
{ id: 'group-2', name: 'Yoga' },
|
||||
]);
|
||||
prismaFetchAttendeeFindMany([
|
||||
{ id: 'a-1', groupId: 'group-1' },
|
||||
{ id: 'a-2', groupId: 'group-2' },
|
||||
]);
|
||||
prismaFetchClassSessionFindMany([
|
||||
{ id: 's1', groupId: 'group-1', startsAt: at(-1) },
|
||||
{ id: 's2', groupId: 'group-1', startsAt: at(-2) },
|
||||
{ id: 's3', groupId: 'group-1', startsAt: at(-3) },
|
||||
{ id: 's4', groupId: 'group-2', startsAt: at(-1) },
|
||||
]);
|
||||
prismaFetchAttendanceFindMany([
|
||||
attendance('a-1', 'ABSENT', at(-1)),
|
||||
attendance('a-1', 'ABSENT', at(-2)),
|
||||
attendance('a-1', 'ABSENT', at(-3)),
|
||||
attendance('a-2', 'PRESENT', at(-1)),
|
||||
]);
|
||||
|
||||
const res = await makeApp({ id: userId }).request('/groups-risk/overview');
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.json()).toEqual({
|
||||
items: [
|
||||
{ groupId: 'group-1', groupName: 'Funcional', riskLevel: 'HIGH' },
|
||||
{ groupId: 'group-2', groupName: 'Yoga', riskLevel: 'NONE' },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function prismaFetchGroupFindMany(rows: unknown[]) {
|
||||
db.group.findMany.mockResolvedValue(rows);
|
||||
}
|
||||
|
||||
function prismaFetchAttendeeFindMany(rows: unknown[]) {
|
||||
db.attendee.findMany.mockResolvedValue(rows);
|
||||
}
|
||||
|
||||
function prismaFetchClassSessionFindMany(rows: unknown[]) {
|
||||
db.classSession.findMany.mockResolvedValue(rows);
|
||||
}
|
||||
|
||||
function prismaFetchAttendanceFindMany(rows: unknown[]) {
|
||||
db.attendance.findMany.mockResolvedValue(rows);
|
||||
}
|
||||
|
||||
function attendance(attendeeId: string, status: string, startsAt: string) {
|
||||
return { attendeeId, status, classSession: { startsAt } };
|
||||
}
|
||||
Reference in New Issue
Block a user