Files
open-safetylog-ehs/server/routes/stats.test.ts
T
jayjennings 3f6dff5f24
CI / Lint, typecheck, test, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
feat: implement permissions and actions management
- Add permissions logic for status options in corrective actions.
- Create tests for permissions functionality.
- Implement queries for user authentication and actions management.
- Develop Actions page to display and manage corrective actions.
- Create authentication pages for login, setup, and password reset.
- Add IncidentDetail page to view incident details and associated actions.
- Implement Settings page for user management and password changes.
2026-10-06 11:20:44 -07:00

48 lines
2.6 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { createTestContext, daysFromToday, hoursAgo } from '../test/helpers.ts'
let ctx: Awaited<ReturnType<typeof createTestContext>>
beforeAll(async () => {
ctx = await createTestContext()
})
afterAll(() => ctx.close())
describe('stats', () => {
it('summarises the dashboard from real data', async () => {
const north = await ctx.createSite('North')
await ctx.createSite('South')
const supervisor = await ctx.createUser('supervisor')
const report = (title: string, severity = 'medium', type = 'hazard') =>
supervisor.post('/api/incidents', { title, type, severity, occurredAt: hoursAgo(3), siteId: north.id }).then((r) => r.body.incident.number as number)
const a = await report('A', 'low')
await report('B', 'high', 'injury')
await supervisor.post(`/api/incidents/${a}/transitions`, { to: 'triage' })
await supervisor.post(`/api/incidents/${a}/transitions`, { to: 'closed' })
const c = await report('C')
await supervisor.post(`/api/incidents/${c}/actions`, { title: 'Overdue', assigneeId: supervisor.user.id, dueDate: daysFromToday(-1) })
await supervisor.post(`/api/incidents/${c}/actions`, { title: 'This week', assigneeId: supervisor.user.id, dueDate: daysFromToday(3) })
await supervisor.post(`/api/incidents/${c}/root-causes`, { category: 'equipment', description: 'Worn' })
const overview = (await supervisor.get('/api/stats/overview')).body
expect(overview).toMatchObject({ openIncidents: 2, reportedLast7Days: 3, actionsDueThisWeek: 1, overdueActions: 1, actionProgress: { total: 2, completed: 0 } })
expect(overview.byStatus).toMatchObject({ reported: 2, closed: 1 })
expect(overview.averageCloseDays).toBeGreaterThanOrEqual(0)
expect(overview.weeklyTrend).toHaveLength(12)
expect(overview.weeklyTrend.at(-1).count).toBeGreaterThanOrEqual(1)
expect(overview.bySite).toEqual([
{ siteId: north.id, name: 'North', count: 3 },
{ siteId: expect.any(String), name: 'South', count: 0 },
])
const analytics = (await supervisor.get('/api/stats/analytics?days=30')).body
expect(analytics).toMatchObject({ periodDays: 30, total: 3, topRootCause: { category: 'equipment', count: 1, share: 1 } })
expect(analytics.byType).toEqual(expect.arrayContaining([{ type: 'hazard', count: 2 }, { type: 'injury', count: 1 }]))
})
it("scopes a reporter's numbers to what they can see", async () => {
const reporter = await ctx.createUser('reporter')
expect((await reporter.get('/api/stats/overview')).body.openIncidents).toBe(0)
})
})