import { afterEach, describe, expect, it, vi } from 'vitest'; import { pickGcgDelivery, shareOrDownloadGcg } from './share'; import type { GcgExport } from './model'; const file = {} as File; const gcg: GcgExport = { gameId: 'g1', filename: 'game.gcg', content: '#title game' }; describe('pickGcgDelivery', () => { it('shares when the platform can share files', () => { expect(pickGcgDelivery({ canShare: () => true, share: async () => {} }, file)).toBe('share'); }); it('downloads when the platform cannot share files', () => { expect(pickGcgDelivery({ canShare: () => false, share: async () => {} }, file)).toBe('download'); }); it('downloads when there is no navigator', () => { expect(pickGcgDelivery(undefined, file)).toBe('download'); }); it('downloads when the Web Share API is incomplete', () => { expect(pickGcgDelivery({ canShare: () => true } as never, file)).toBe('download'); }); }); describe('shareOrDownloadGcg', () => { afterEach(() => vi.unstubAllGlobals()); function stubDownloadEnv(canShare: boolean, share: () => Promise) { const anchor = { href: '', download: '', click: vi.fn(), remove: vi.fn() }; const createElement = vi.fn(() => anchor); vi.stubGlobal('File', class {}); vi.stubGlobal('Blob', class {}); vi.stubGlobal('navigator', { canShare: () => canShare, share }); vi.stubGlobal('document', { createElement, body: { appendChild: vi.fn() } }); vi.stubGlobal('URL', { createObjectURL: vi.fn(() => 'blob:x'), revokeObjectURL: vi.fn() }); return { anchor, createElement }; } it('never falls back to the navigating Blob download when a share is cancelled', async () => { // Reproduces the iOS Telegram Mini App break: Web Share is available and the user cancels it // (AbortError). The fallback navigates the WKWebView to the blob: URL and strands // the app, so a cancelled (or failed) share must do nothing here. const share = vi.fn().mockRejectedValue(new DOMException('cancelled', 'AbortError')); const { createElement } = stubDownloadEnv(true, share); await shareOrDownloadGcg(gcg); expect(share).toHaveBeenCalledOnce(); expect(createElement).not.toHaveBeenCalled(); // no download anchor → no webview navigation }); it('downloads via an anchor when the platform cannot share files', async () => { const { anchor, createElement } = stubDownloadEnv(false, vi.fn()); await shareOrDownloadGcg(gcg); expect(createElement).toHaveBeenCalledWith('a'); expect(anchor.click).toHaveBeenCalledOnce(); }); });