import { randomUUID } from 'node:crypto'; import { afterEach, beforeEach, expect, it, vi } from 'vitest'; import { newFixture, type Fixture } from '../helpers/fixture.js'; let fixture: Fixture; beforeEach(async () => { vi.resetModules(); fixture = await newFixture(); const { db } = await import('../../src/lib/server/db/index.js'); for (const id of ['first', 'second']) db() .prepare( `INSERT INTO auth_users(id,username,display_name,password_hash,role,created_at,updated_at) VALUES(?,?,?,'unused','moderator',0,0)` ) .run(id, id, id); }); afterEach(async () => fixture.cleanup()); it('filters case queues by workflow, priority and ownership while prioritizing active work', async () => { const { mutateModeration } = await import('../../src/lib/server/moderation/actions.js'); const { moderationOverview, moderationQuery } = await import('../../src/lib/server/moderation/overview.js'); const { db } = await import('../../src/lib/server/db/index.js'); const ids: string[] = []; for (const [title, priority, status, owner] of [ ['Normal report', 'normal', 'open', null], ['Urgent review', 'urgent', 'in_review', 'first'], ['High escalation', 'high', 'in_review', 'second'], ['Closed urgent appeal', 'urgent', 'closed', 'first'] ]) { const { id } = mutateModeration('first', { op: 'create-case', game: 't5', guid: '123', title, idempotencyKey: randomUUID() }); ids.push(id); db() .prepare('UPDATE moderation_cases SET priority=?,status=?,assignee_id=? WHERE id=?') .run(priority, status, owner, id); } const read = (extra = '') => moderationOverview('first', moderationQuery(new URLSearchParams(`view=cases&${extra}`))); expect(read().cases.map((item) => item.id)).toEqual([ids[1], ids[2], ids[0], ids[3]]); expect(read('caseStatus=active').total).toBe(3); expect(read('caseStatus=closed').cases.map((item) => item.id)).toEqual([ids[3]]); expect(read('caseStatus=in_review&priority=high').cases.map((item) => item.id)).toEqual([ ids[2] ]); expect(read('assignedTo=me').cases.map((item) => item.id)).toEqual([ids[1], ids[3]]); expect(read('assignedTo=unassigned').cases.map((item) => item.id)).toEqual([ids[0]]); expect(read('assignedTo=second').cases[0].assignee).toBe('second'); expect( read('caseStatus=active&assignedTo=me&priority=urgent&game=t5&guid=123&q=review&offset=100') .query.offset ).toBe(0); expect(read('caseStatus=active&assignedTo=me&priority=urgent&game=t6').total).toBe(0); expect(read('caseStatus=invalid&priority=invalid').total).toBe(4); expect( moderationOverview( 'first', moderationQuery( new URLSearchParams('caseStatus=closed&assignedTo=unassigned&priority=urgent') ) ).total ).toBe(1); }); it('shows the latest assessment in case queues while preserving earlier findings', async () => { const { mutateModeration } = await import('../../src/lib/server/moderation/actions.js'); const { moderationOverview, moderationQuery } = await import('../../src/lib/server/moderation/overview.js'); const { moderationCaseDetail } = await import('../../src/lib/server/moderation/cases.js'); const mutate = (input: Record) => mutateModeration('first', { ...input, idempotencyKey: randomUUID() }); const { id } = mutate({ op: 'create-case', game: 't5', guid: '123', title: 'Conversation review' }); for (const [revision, finding, summary] of [ [1, 'inconclusive', 'Need more context'], [2, 'substantiated', 'Full excerpt confirms targeted harassment'] ] as const) mutate({ op: 'assess-case', id, revision, summary, rules: ['Respect other players'], findings: [{ category: 'harassment', finding, detail: summary }] }); const queue = moderationOverview('first', moderationQuery(new URLSearchParams('view=cases'))); expect(queue.cases[0].assessment).toMatchObject({ summary: 'Full excerpt confirms targeted harassment', findings: [{ category: 'harassment', finding: 'substantiated' }] }); expect(moderationCaseDetail('first', id).assessmentHistory).toHaveLength(2); });