// BUG-7: reorderParticipants not logged. // Every combat op returns { patch, log }. Handler calls logAction(log.message, // ctx, { updates: log.undo }) → writes entry to logs collection. // reorderParticipants returns log: null → handler skips logAction → drag // invisible in combat log + no undo payload (siblings all have one). // // RED: prove log is null (bug). Fix: return { message, undo }. 'use strict'; const shared = require('@ttrpg/shared'); const { makeParticipant, reorderParticipants } = shared; function p(id, init) { return makeParticipant({ id, name: id, type: 'monster', initiative: init, maxHp: 100, currentHp: 100 }); } function enc(ps) { return { name:'t', participants:ps, isStarted:false, isPaused:false, round:0, currentTurnParticipantId:null, turnOrderIds:[] }; } describe('BUG-7: reorderParticipants logged', () => { test('returns log object (not null) with message + undo', () => { const e = enc([p('a', 10), p('b', 10), p('c', 10)]); const r = reorderParticipants(e, 'c', 'b'); expect(r.patch).not.toBeNull(); expect(r.log).not.toBeNull(); expect(typeof r.log.message).toBe('string'); expect(r.log.message.length).toBeGreaterThan(0); expect(r.log.undo).toBeDefined(); }); test('undo restores original participants order', () => { const e = enc([p('a', 10), p('b', 10), p('c', 10)]); const orig = e.participants.map(p => p.id); const r = reorderParticipants(e, 'c', 'b'); const restored = { ...e, ...r.log.undo }; expect(restored.participants.map(p => p.id)).toEqual(orig); }); test('no-op (same id) returns null log', () => { const e = enc([p('a', 10), p('b', 10)]); const r = reorderParticipants(e, 'a', 'a'); expect(r.log).toBeNull(); }); test('no-op (cross-init blocked) returns null log', () => { const e = enc([p('a', 10), p('b', 5)]); const r = reorderParticipants(e, 'a', 'b'); expect(r.patch).toBeNull(); expect(r.log).toBeNull(); }); });