Files
electric-cherry/tests/unit/moderation-case-overview.test.ts
T

103 lines
4.4 KiB
TypeScript

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', 'escalated', 'second'],
['Closed urgent appeal', 'urgent', 'appeal_upheld', '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=escalated&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<string, unknown>) =>
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);
});