// @ts-check // Voice bundle export/import in the library toolbar (mocked routes only; never touches the live library). const { test, expect } = require('./_guard'); async function setup(page, calls) { await page.route('**/api/voices/import', async route => { calls.push('import'); const name = route.request().postData() || ''; if (name.includes('bad.zip')) return route.fulfill({ status: 400, json: { detail: 'Hash mismatch: audio.wav' } }); return route.fulfill({ json: { ok: true, voice_id: 'EN_F_x_2', status: 'renamed' } }); }); await page.route('**/api/voices/*/export', route => { calls.push('export'); return route.fulfill({ body: 'PK', contentType: 'application/zip' }); }); await page.route('**/api/voices*', route => route.fulfill({ json: [] })); await page.route('**/api/settings*', route => route.fulfill({ json: {} })); await page.goto('/', { waitUntil: 'domcontentloaded' }); await page.waitForFunction(() => typeof window.importVoiceBundles === 'function', null, { timeout: 15_000 }); } test('bundle buttons are labelled and at least 44px', async ({ page }) => { await setup(page, []); for (const id of ['export-voices-btn', 'import-voices-btn']) { const b = page.locator('#' + id); await expect(b).toHaveText(/Export selected|Import bundle/); const box = await b.boundingBox().catch(() => null); const h = await b.evaluate(el => parseFloat(getComputedStyle(el).minHeight)); expect(h).toBeGreaterThanOrEqual(44); if (box) expect(box.height).toBeGreaterThanOrEqual(44); } }); test('export downloads a bundle per voice', async ({ page }) => { const calls = []; await setup(page, calls); const dl = page.waitForEvent('download'); await page.evaluate(() => window.exportVoiceBundles(['EN_F_x'])); expect((await dl).suggestedFilename()).toBe('EN_F_x.voice.zip'); expect(calls).toContain('export'); }); test('import reports renamed voices and shows server errors', async ({ page }) => { const calls = []; await setup(page, calls); await page.evaluate(() => window.importVoiceBundles([new File(['PK'], 'ok.zip')])); await expect(page.locator('#toast')).toContainText('EN_F_x_2 (name was taken)'); await page.evaluate(() => window.importVoiceBundles([new File(['PK'], 'bad.zip')])); await expect(page.locator('#toast')).toContainText('Import of bad.zip failed: Hash mismatch'); });