import { test, expect, type BrowserContext } from '@playwright/test'; async function fresh(ctx: BrowserContext) { const page = await ctx.newPage(); await page.goto('/'); await page.evaluate(() => { indexedDB.deleteDatabase('ttrpg-manager'); localStorage.clear(); }); await page.reload(); return page; } test('GM hosts a session; a player on another device sees live combat', async ({ browser }) => { const gmCtx = await browser.newContext(); const playerCtx = await browser.newContext(); // GM: load the sample campaign and host a session. const gm = await fresh(gmCtx); gm.on('dialog', (d) => d.dismiss()); // dismiss the optional-password prompt await gm.getByLabel('Settings').click(); await gm.getByRole('button', { name: 'Load sample campaign' }).click(); await expect(gm.getByRole('heading', { name: 'Sample: Lost Mine' })).toBeVisible(); await gm.getByRole('button', { name: '📡 Host' }).click(); const code = (await gm.getByTestId('join-code').textContent())?.replace(/[^A-Z0-9]/g, '') ?? ''; expect(code).toHaveLength(6); // Player: join via the room code on a separate context (device). const player = await playerCtx.newPage(); await player.goto(`/play?room=${code}`); await expect(player.getByRole('heading', { name: 'Sample: Lost Mine' })).toBeVisible(); await expect(player.getByText('Lia the Brave').first()).toBeVisible(); // party synced (also shown on the seat-claim screen) // GM starts the seeded encounter → player sees initiative live, enemy HP masked. await gm.getByLabel('Primary').getByRole('link', { name: 'Combat' }).click(); await gm.getByText('Goblin Ambush').click(); await gm.getByRole('button', { name: 'Start combat' }).click(); await expect(player.getByText(/Round \d+/)).toBeVisible(); await expect(player.getByText('Goblin').first()).toBeVisible(); // enemy exact HP must NOT be shown to players await expect(player.getByText('7/7')).toHaveCount(0); // Player navigates away — the live connection persists (badge stays) and // returning still shows the synced table. await player.getByLabel('Primary').getByRole('link', { name: 'Dice' }).click(); await expect(player.getByTestId('player-live')).toBeVisible(); await expect(player.getByTestId('player-live')).toContainText(code); await player.getByTestId('player-live').getByRole('link').click(); await expect(player.getByText('Lia the Brave').first()).toBeVisible(); await gmCtx.close(); await playerCtx.close(); });