- 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.
48 lines
2.6 KiB
TypeScript
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)
|
|
})
|
|
})
|