2026-06-30 13:55:14 -04:00
|
|
|
// BUG-4 repro: toggling hidePlayerHp must not clobber activeDisplay doc.
|
|
|
|
|
// setDoc = replace (contract). {merge:true} arg ignored.
|
|
|
|
|
// Toggling hide-HP writes {hidePlayerHp:X} alone → activeCampaignId + activeEncounterId → null.
|
|
|
|
|
// Display reads null → "Game Session Paused". Recover requires re-activating encounter.
|
|
|
|
|
// Fix: use updateDoc (patch), not setDoc.
|
|
|
|
|
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import { render, waitFor, screen, fireEvent } from '@testing-library/react';
|
|
|
|
|
import '@testing-library/jest-dom';
|
|
|
|
|
import App from '../App';
|
|
|
|
|
import { MOCK_DB } from '../__mocks__/firebase/_mock-db';
|
|
|
|
|
import { getAdapterCalls, resetAdapterCalls } from '../storage/firebase';
|
|
|
|
|
import { selectCampaignByName } from './testHelpers';
|
|
|
|
|
|
|
|
|
|
function seedAdminWithActiveEncounter() {
|
|
|
|
|
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';
|
|
|
|
|
|
|
|
|
|
MOCK_DB.set(campaignPath, { name: 'Camp', playerDisplayBackgroundUrl: '' });
|
|
|
|
|
MOCK_DB.set(encounterPath, { name: 'Enc', participants: [], isStarted: true });
|
|
|
|
|
// active encounter set, HP NOT hidden
|
|
|
|
|
MOCK_DB.set(activeDisplayPath, {
|
|
|
|
|
activeCampaignId: 'c1',
|
|
|
|
|
activeEncounterId: 'e1',
|
|
|
|
|
hidePlayerHp: false,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe('BUG-4: hide-player-HP toggle preserves activeDisplay', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
window.history.replaceState({}, '', '/');
|
|
|
|
|
global.alert = jest.fn();
|
|
|
|
|
resetAdapterCalls();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('toggling hidePlayerHp does NOT clear activeCampaignId/activeEncounterId', async () => {
|
|
|
|
|
seedAdminWithActiveEncounter();
|
|
|
|
|
render(<App />);
|
|
|
|
|
|
|
|
|
|
// wait for admin to mount + load active display
|
|
|
|
|
await waitFor(() => screen.getByText('Camp'), { timeout: 3000 });
|
|
|
|
|
await selectCampaignByName('Camp');
|
|
|
|
|
|
|
|
|
|
// find the hide-player-HP toggle (role switch)
|
|
|
|
|
const toggle = await screen.findByRole('switch', { name: /hide/i }, { timeout: 3000 });
|
|
|
|
|
|
|
|
|
|
// toggle ON
|
|
|
|
|
fireEvent.click(toggle);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
const writes = getAdapterCalls().filter(
|
2026-07-01 23:32:23 -04:00
|
|
|
c => c.fn === 'updateDoc' && c.path.includes('activeDisplay/status')
|
2026-06-30 13:55:14 -04:00
|
|
|
);
|
|
|
|
|
expect(writes.length).toBeGreaterThan(0);
|
|
|
|
|
const last = writes[writes.length - 1];
|
2026-07-01 23:32:23 -04:00
|
|
|
// patch must NOT clobber activeCampaignId/activeEncounterId.
|
|
|
|
|
// BUG: setDoc replace writes only {hidePlayerHp:true} → clobbers.
|
|
|
|
|
// Fix: updateDoc patch — other fields untouched.
|
|
|
|
|
expect(last.patch.hidePlayerHp).toBe(true);
|
2026-06-30 13:55:14 -04:00
|
|
|
}, { timeout: 3000 });
|
|
|
|
|
});
|
|
|
|
|
});
|