Rework backend #1
@@ -182,6 +182,7 @@ REWORK_PLAN.md.
|
|||||||
- [x] BUG-5: fixed (1-list model, 500 rounds clean)
|
- [x] BUG-5: fixed (1-list model, 500 rounds clean)
|
||||||
- [x] BUG-6: fixed structurally (1-list model)
|
- [x] BUG-6: fixed structurally (1-list model)
|
||||||
- [x] BUG-12: fixed — campaign selection follows activeDisplay
|
- [x] BUG-12: fixed — campaign selection follows activeDisplay
|
||||||
|
- [x] BUG-15: fixed — DisplayView no longer re-sorts (drag order preserved)
|
||||||
- [ ] BUG-8: ws adapter reconnect
|
- [ ] BUG-8: ws adapter reconnect
|
||||||
- [ ] BUG-10: deact+reactivate double-act
|
- [ ] BUG-10: deact+reactivate double-act
|
||||||
- [ ] BUG-11: FE Combat.scenario crash
|
- [ ] BUG-11: FE Combat.scenario crash
|
||||||
|
|||||||
+4
-3
@@ -2500,9 +2500,10 @@ function DisplayView() {
|
|||||||
|
|
||||||
let participantsToRender = [];
|
let participantsToRender = [];
|
||||||
if (participants) {
|
if (participants) {
|
||||||
// Hide inactive monsters (pre-staged/summoned reserves) from the player view
|
// 1-list model: participants[] IS the display order (DM drag = source of
|
||||||
const visibleParticipants = participants.filter(p => p.isActive || p.type !== 'monster');
|
// truth). Do NOT re-sort by initiative — that diverges from AdminView /
|
||||||
participantsToRender = sortParticipantsByInitiative(visibleParticipants, visibleParticipants);
|
// turnOrderIds after any cross-init drag (BUG-15).
|
||||||
|
participantsToRender = participants.filter(p => p.isActive || p.type !== 'monster');
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayStyles = campaignBackgroundUrl
|
const displayStyles = campaignBackgroundUrl
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// RED test: DisplayView must render participants in turnOrderIds (drag) order,
|
||||||
|
// NOT re-sort by initiative. 1-list model: participants[] = display source.
|
||||||
|
// Bug: DisplayView line ~2505 calls sortParticipantsByInitiative(), ignoring
|
||||||
|
// DM drag order. After cross-init drag, display diverges from AdminView/turnOrderIds.
|
||||||
|
import React from 'react';
|
||||||
|
import { render, waitFor, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import App from '../App';
|
||||||
|
import { MOCK_DB } from '../__mocks__/firebase/_mock-db';
|
||||||
|
import { resetAdapterCalls } from '../storage/firebase';
|
||||||
|
|
||||||
|
function seedDragOrder() {
|
||||||
|
const campaignPath = 'artifacts/ttrpg-initiative-tracker-default/public/data/campaigns/c1';
|
||||||
|
const encounterPath = 'artifacts/ttrpg-initiative-tracker-default/public/data/campaigns/c1/encounters/e1';
|
||||||
|
const activeDisplayPath = 'artifacts/ttrpg-initiative-tracker-default/public/data/activeDisplay/status';
|
||||||
|
// Three monsters, init-sorted would be: high(20), mid(11), low(10).
|
||||||
|
// But participants[] = DRAG order: low BEFORE mid (DM dragged across init).
|
||||||
|
const participants = [
|
||||||
|
{ id: 'high', name: 'High', type: 'monster', initiative: 20, currentHp: 10, maxHp: 10, isActive: true },
|
||||||
|
{ id: 'low', name: 'Low', type: 'monster', initiative: 10, currentHp: 10, maxHp: 10, isActive: true },
|
||||||
|
{ id: 'mid', name: 'Mid', type: 'monster', initiative: 11, currentHp: 10, maxHp: 10, isActive: true },
|
||||||
|
];
|
||||||
|
MOCK_DB.set(campaignPath, { name: 'Camp', playerDisplayBackgroundUrl: '' });
|
||||||
|
MOCK_DB.set(encounterPath, {
|
||||||
|
name: 'Enc',
|
||||||
|
participants,
|
||||||
|
turnOrderIds: participants.map(p => p.id),
|
||||||
|
round: 1,
|
||||||
|
currentTurnParticipantId: 'high',
|
||||||
|
isStarted: true,
|
||||||
|
});
|
||||||
|
MOCK_DB.set(activeDisplayPath, { activeCampaignId: 'c1', activeEncounterId: 'e1', hidePlayerHp: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('DisplayView drag order (BUG-15)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
window.history.replaceState({}, '', '/display');
|
||||||
|
global.alert = jest.fn();
|
||||||
|
window.open = jest.fn();
|
||||||
|
// jsdom lacks scrollIntoView (DisplayView auto-scrolls current actor)
|
||||||
|
Element.prototype.scrollIntoView = jest.fn();
|
||||||
|
resetAdapterCalls();
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
window.history.replaceState({}, '', '/');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders participants in participants[] order, not init-sorted', async () => {
|
||||||
|
seedDragOrder();
|
||||||
|
render(<App />);
|
||||||
|
|
||||||
|
// wait for participant names to render
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getAllByText(/High|Mid|Low/i).length).toBeGreaterThanOrEqual(3);
|
||||||
|
}, { timeout: 3000 });
|
||||||
|
|
||||||
|
// collect name elements in DOM order (strip Current marker)
|
||||||
|
const names = screen.getAllByText(/High|Mid|Low/i).map(el => el.textContent.replace(/\(Current\)/i, '').trim());
|
||||||
|
// participants[] order = High, Low, Mid (drag moved Low before Mid).
|
||||||
|
// Display must mirror this. Init-sorted would be High, Mid, Low.
|
||||||
|
expect(names).toEqual(['High', 'Low', 'Mid']);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user