import { expect, test, type Page } from './fixtures'; // The finished-game export: the history header's 📤 button opens the app's own format // chooser modal — never Telegram's native popup, whose callback runs without user // activation and so kills navigator.share / clipboard writes (verified on-device). // The PNG option is offered only outside the in-app WebViews (no working binary // delivery there until the server-rendered signed-URL path lands); the GCG file is // always offered. g3 ("vs Rick") is the seeded finished game. Web Share is // force-disabled per test so both engines deterministically exercise the download // branch. async function disableWebShare(page: Page): Promise { await page.addInitScript(() => { Object.defineProperty(navigator, 'canShare', { value: () => false, configurable: true }); Object.defineProperty(navigator, 'share', { value: undefined, configurable: true }); }); } async function openFinishedHistory(page: Page): Promise { await page.goto('/'); await page.getByRole('button', { name: /guest/i }).click(); await page.getByRole('button', { name: /Rick/ }).click(); await expect(page.locator('[data-cell]').first()).toBeVisible(); await page.locator('.scoreboard').click(); await expect(page.getByRole('button', { name: 'Export game' })).toBeVisible(); } test('the export chooser downloads the PNG image on a plain browser', async ({ page }) => { await disableWebShare(page); await openFinishedHistory(page); await page.getByRole('button', { name: 'Export game' }).click(); // The app's own chooser modal offers both formats on the plain web. await expect(page.getByRole('button', { name: 'GCG file' })).toBeVisible(); const download = page.waitForEvent('download'); await page.getByRole('button', { name: 'Image (PNG)' }).click(); expect((await download).suggestedFilename()).toMatch(/^game-.+\.png$/); }); test('the export chooser downloads the GCG file on a plain browser', async ({ page }) => { await disableWebShare(page); await openFinishedHistory(page); await page.getByRole('button', { name: 'Export game' }).click(); const download = page.waitForEvent('download'); await page.getByRole('button', { name: 'GCG file' }).click(); expect((await download).suggestedFilename()).toMatch(/^game-.+\.gcg$/); }); test('inside Telegram the chooser is the app modal and withholds the image option', async ({ page, }) => { await disableWebShare(page); // A Telegram WebApp stub with showPopup present: were the chooser still native, it would // be called — the spy locks the regression (its activation-less callback breaks share and // clipboard delivery on real devices). await page.addInitScript(() => { Object.assign(window, { Telegram: { WebApp: { initData: 'query_id=test&user=%7B%22id%22%3A1%7D&auth_date=1&hash=deadbeef', initDataUnsafe: {}, ready() {}, expand() {}, showPopup(_params: unknown, cb: (id: string) => void) { (window as unknown as { __popupCalled?: boolean }).__popupCalled = true; setTimeout(() => cb(''), 0); }, }, }, }); }); await page.goto('/'); await expect(page.getByText('Your turn')).toBeVisible(); // auto-authenticated lobby await page.getByRole('button', { name: /Rick/ }).click(); await expect(page.locator('[data-cell]').first()).toBeVisible(); await page.locator('.scoreboard').click(); await page.getByRole('button', { name: 'Export game' }).click(); // The app's own modal opened with the GCG option only — no PNG in an in-app WebView… await expect(page.getByRole('button', { name: 'GCG file' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Image (PNG)' })).toHaveCount(0); // …and the native popup was never used for the chooser. expect( await page.evaluate(() => (window as unknown as { __popupCalled?: boolean }).__popupCalled), ).toBeFalsy(); });