import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { createTestContext } from '../test/helpers.ts' let ctx: Awaited> beforeAll(async () => { ctx = await createTestContext() }) afterAll(() => ctx.close()) describe('users', () => { it('lets admins create users and rejects duplicate emails', async () => { const body = { name: 'Sam Rivera', email: 'Sam@Example.com', role: 'supervisor', password: 'a sufficiently long password' } const created = await ctx.admin.post('/api/users', body) expect(created.status).toBe(201) expect(created.body.user).toMatchObject({ email: 'sam@example.com', role: 'supervisor', active: true }) expect(created.body.user.passwordHash).toBeUndefined() expect((await ctx.admin.post('/api/users', body)).status).toBe(409) }) it('validates input', async () => { const res = await ctx.admin.post('/api/users', { name: '', email: 'not-an-email', role: 'boss', password: 'short' }) expect(res.status).toBe(400) expect(res.body.issues.map((issue: { path: string }) => issue.path).sort()).toEqual(['email', 'name', 'password', 'role']) }) it('restricts listing to safety managers and creating to admins', async () => { const supervisor = await ctx.createUser('supervisor') const manager = await ctx.createUser('safety_manager') expect((await supervisor.get('/api/users')).status).toBe(403) expect((await manager.get('/api/users')).status).toBe(200) expect((await manager.post('/api/users', { name: 'X', email: 'x@example.com', role: 'admin', password: 'a sufficiently long password' })).status).toBe(403) expect((await ctx.anonymous().get('/api/users')).status).toBe(401) }) it('returns 404 for unknown or malformed ids', async () => { expect((await ctx.admin.patch('/api/users/00000000-0000-4000-8000-000000000000', { name: 'Nobody' })).status).toBe(404) expect((await ctx.admin.patch('/api/users/not-a-uuid', { name: 'Nobody' })).status).toBe(400) }) it('keeps at least one active admin', async () => { const me = await ctx.admin.get('/api/auth/me') const adminId = me.body.user.id expect((await ctx.admin.patch(`/api/users/${adminId}`, { role: 'reporter' })).status).toBe(409) expect((await ctx.admin.patch(`/api/users/${adminId}`, { active: false })).status).toBe(400) const second = await ctx.createUser('admin', 'second-admin@example.com') const demoted = await second.patch(`/api/users/${adminId}`, { role: 'safety_manager' }) expect(demoted.status).toBe(200) expect(demoted.body.user.role).toBe('safety_manager') // The demoted user stays signed in but loses admin rights immediately expect((await ctx.admin.get('/api/auth/me')).status).toBe(200) expect((await ctx.admin.post('/api/users', { name: 'Y', email: 'y@example.com', role: 'reporter', password: 'a sufficiently long password' })).status).toBe(403) }) })