// 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(); // 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']); }); });