Cast: card/list views, sort & filter, online voice picker, "Hear a line" sample button, AI character notes, import auto-save. Platform: WCAG 2.1 AA accessibility pass; German UI translation + language picker; installable PWA with offline shell; GZip + content-visibility virtualization + lazy images + Rehearser PCM memory cap (mobile stability); Playwright suite (desktop + iPhone); opt-in minified bundle build. Fixes: screenplay parser false characters; Fish-Speech inline-tag tones; narrator/voice pickers list full library; clone GUI rework; fish.audio import dedup; voice-ID rename; bulk-delete modal. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.7 KiB
JavaScript
35 lines
1.7 KiB
JavaScript
// @ts-check
|
|
// Verifies the opt-in production bundle (npm run minify → static/dist/main.min.js):
|
|
// the app must load and behave identically through the single-bundle path.
|
|
const { test, expect } = require('@playwright/test');
|
|
|
|
// Block the service worker so request visibility is deterministic (the SW can serve
|
|
// cached responses without a network request, hiding them from page.on('request')).
|
|
test.use({ serviceWorkers: 'block' });
|
|
|
|
test('app works through the production bundle (?bundle=1)', async ({ page }) => {
|
|
const errors = [];
|
|
page.on('pageerror', (e) => errors.push(String(e)));
|
|
|
|
let bundleRequested = false;
|
|
page.on('request', (r) => { if (r.url().includes('/static/dist/main.min.js')) bundleRequested = true; });
|
|
|
|
await page.addInitScript(() => { window.APP_USE_BUNDLE = true; });
|
|
await page.goto('/?bundle=1', { waitUntil: 'domcontentloaded' });
|
|
await expect(page.locator('#sidebar')).toBeVisible();
|
|
|
|
// Wait for the JS pipeline to finish (navTo is defined by nav.js, loaded AFTER the
|
|
// feature bundle) — only then is it valid to check what was loaded.
|
|
await page.waitForFunction(() => typeof window.navTo === 'function', null, { timeout: 15_000 });
|
|
|
|
// The bundle (not the individual feature files) must have served the modules
|
|
expect(bundleRequested).toBeTruthy();
|
|
|
|
// Global API from a bundled module must still be reachable (names are preserved)
|
|
await page.evaluate(() => window.navTo('s-clone'));
|
|
await expect(page.getByText(/Clone a Voice/i).first()).toBeVisible({ timeout: 10_000 });
|
|
|
|
const real = errors.filter(e => /ReferenceError|TypeError|SyntaxError|is not defined|is not a function/.test(e));
|
|
expect(real, real.join('\n')).toHaveLength(0);
|
|
});
|