2026-07-06 10:31:46 -04:00
|
|
|
// Toggle-active semantics guard.
|
|
|
|
|
// Design: toggle active is a status edit, NOT a turn action.
|
|
|
|
|
// Deactivating current does not advance turn or increment round. DM clicks
|
|
|
|
|
// Next Turn explicitly; Next Turn skips inactive participants.
|
2026-07-01 14:22:02 -04:00
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
2026-07-06 10:31:46 -04:00
|
|
|
const { makeParticipant, nextTurn, toggleParticipantActive } = require('@ttrpg/shared');
|
|
|
|
|
const { mockCtx } = require('./_helpers');
|
2026-07-01 14:22:02 -04:00
|
|
|
|
|
|
|
|
function p(id, init, extra = {}) {
|
|
|
|
|
return makeParticipant({ id, name: id, type: 'monster',
|
|
|
|
|
initiative: init, maxHp: 100, currentHp: 100, ...extra });
|
|
|
|
|
}
|
|
|
|
|
function enc(ps, extra = {}) {
|
|
|
|
|
return { name:'t', participants:ps, isStarted:false, isPaused:false,
|
|
|
|
|
round:0, currentTurnParticipantId:null, turnOrderIds:[], ...extra };
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 10:31:46 -04:00
|
|
|
describe('toggle-active is not a turn advance', () => {
|
|
|
|
|
test('mid-round: deactivating current leaves current unchanged', async () => {
|
|
|
|
|
const { ctx } = mockCtx();
|
|
|
|
|
const e = enc([p('a',10),p('b',5),p('c',3)], { isStarted:true, round:1,
|
2026-07-01 14:22:02 -04:00
|
|
|
turnOrderIds:['a','b','c'], currentTurnParticipantId:'a' });
|
2026-07-06 10:31:46 -04:00
|
|
|
const deact = await toggleParticipantActive(e, 'a', ctx);
|
|
|
|
|
expect(deact.currentTurnParticipantId).toBe('a');
|
|
|
|
|
expect(deact.round).toBe(1);
|
|
|
|
|
expect(deact.participants.find(p => p.id === 'a').isActive).toBe(false);
|
2026-07-01 14:22:02 -04:00
|
|
|
});
|
|
|
|
|
|
2026-07-06 10:31:46 -04:00
|
|
|
test('nextTurn after deactivating current skips inactive participant', async () => {
|
|
|
|
|
const { ctx } = mockCtx();
|
|
|
|
|
const e = enc([p('a',10),p('b',5),p('c',3)], { isStarted:true, round:1,
|
|
|
|
|
turnOrderIds:['a','b','c'], currentTurnParticipantId:'a' });
|
|
|
|
|
const deact = await toggleParticipantActive(e, 'a', ctx);
|
|
|
|
|
const next = await nextTurn(deact, ctx);
|
|
|
|
|
expect(next.currentTurnParticipantId).toBe('b');
|
|
|
|
|
expect(next.round).toBe(1);
|
2026-07-01 14:22:02 -04:00
|
|
|
});
|
|
|
|
|
|
2026-07-06 10:31:46 -04:00
|
|
|
test('wrap: deactivating current does not increment round; nextTurn does', async () => {
|
|
|
|
|
const { ctx } = mockCtx();
|
|
|
|
|
const e = enc([p('a',10),p('b',5),p('c',3)], { isStarted:true, round:2,
|
|
|
|
|
turnOrderIds:['a','b','c'], currentTurnParticipantId:'c' });
|
|
|
|
|
const deact = await toggleParticipantActive(e, 'c', ctx);
|
|
|
|
|
expect(deact.currentTurnParticipantId).toBe('c');
|
|
|
|
|
expect(deact.round).toBe(2);
|
|
|
|
|
const next = await nextTurn(deact, ctx);
|
|
|
|
|
expect(next.currentTurnParticipantId).toBe('a');
|
|
|
|
|
expect(next.round).toBe(3);
|
2026-07-01 14:22:02 -04:00
|
|
|
});
|
|
|
|
|
});
|