// Unit tests for the moderation dashboard's pure reshaping/annotation logic. // DB-free (like the rest of this suite) — the SQL layer is exercised manually // against a dev database per the plan's verification steps. const { test } = require('node:test') const assert = require('node:assert/strict') const moderation = require('../src/model/moderation/moderation.pure') test('reshapeWindows: folds rows into windows and zero-fills missing types', () => { const rows = [ { action_type: 'ban', d1: 1, d7: 3, d30: 5 }, { action_type: 'warn', d1: 0, d7: 2, d30: 9 }, ] const { windows } = moderation.reshapeWindows(rows) assert.deepEqual(windows['24h'], { ban: 1, kick: 0, mute: 0, warn: 0 }) assert.deepEqual(windows['7d'], { ban: 3, kick: 0, mute: 0, warn: 2 }) assert.deepEqual(windows['30d'], { ban: 5, kick: 0, mute: 0, warn: 9 }) }) test('reshapeWindows: coerces string/decimal SUM results to numbers', () => { const { windows } = moderation.reshapeWindows([{ action_type: 'mute', d1: '2', d7: '2', d30: '4' }]) assert.strictEqual(windows['24h'].mute, 2) assert.strictEqual(windows['30d'].mute, 4) }) test('reshapeWindows: ignores unknown action types (e.g. future enum values)', () => { const { windows } = moderation.reshapeWindows([{ action_type: 'filter_hit', d1: 9, d7: 9, d30: 9 }]) assert.deepEqual(windows['24h'], { ban: 0, kick: 0, mute: 0, warn: 0 }) }) test('reshapeWindows: empty input yields all-zero windows', () => { const { windows } = moderation.reshapeWindows([]) assert.deepEqual(windows, { '24h': { ban: 0, kick: 0, mute: 0, warn: 0 }, '7d': { ban: 0, kick: 0, mute: 0, warn: 0 }, '30d': { ban: 0, kick: 0, mute: 0, warn: 0 }, }) }) test('annotate: flags automated when staff id matches the bot application id', () => { const [row] = moderation.annotate([{ staff_user_id: '999', target_site_user_id: null }], '999') assert.equal(row.is_automated, true) }) test('annotate: string/number snowflake mismatch still matches (coerced)', () => { // mod_actions stores staff_user_id as VARCHAR, but bot_config.application_id // could arrive as a number — the compare must coerce both sides. const [row] = moderation.annotate([{ staff_user_id: 999, target_site_user_id: null }], '999') assert.equal(row.is_automated, true) }) test('annotate: staff action (id differs from bot) is not automated', () => { const [row] = moderation.annotate([{ staff_user_id: '111', target_site_user_id: null }], '999') assert.equal(row.is_automated, false) }) test('annotate: no bot application id configured means nothing is automated', () => { const [row] = moderation.annotate([{ staff_user_id: '999', target_site_user_id: null }], null) assert.equal(row.is_automated, false) }) test('annotate: folds joined identity columns into linked_account', () => { const [row] = moderation.annotate( [{ staff_user_id: '1', target_site_user_id: 7, target_site_username: 'perry' }], null, ) assert.deepEqual(row.linked_account, { id: 7, username: 'perry' }) }) test('annotate: no linked identity yields null linked_account', () => { const [row] = moderation.annotate([{ staff_user_id: '1', target_site_user_id: null }], null) assert.equal(row.linked_account, null) }) test('windowValue: picks the right column per window key and coerces to number', () => { const row = { d1: '2', d7: 5, d30: '11' } assert.strictEqual(moderation.windowValue(row, '24h'), 2) assert.strictEqual(moderation.windowValue(row, '7d'), 5) assert.strictEqual(moderation.windowValue(row, '30d'), 11) }) test('windowValue: null row (no rows in window) yields 0', () => { assert.strictEqual(moderation.windowValue(null, '24h'), 0) assert.strictEqual(moderation.windowValue(undefined, '30d'), 0) }) test('windowValue: null sum column yields 0', () => { assert.strictEqual(moderation.windowValue({ d1: null, d7: null, d30: null }, '7d'), 0) })