Introduce configurable segment preloading depth, sentence lookahead, and TTS segment max block length for both PDF and EPUB readers. Add new settings to user preferences, config context, and document settings UI. Refactor TTS segment splitting logic to support per-user max block length and propagate these options through PDF/EPUB adapters and TTS segment generation. Update API, manifest pagination, and segment deduplication for improved performance and correctness. Add tests for new NLP options and manifest logic. BREAKING CHANGE: TTS segment splitting and manifest APIs now require max block length and preloading parameters; user config schema updated.
124 lines
4.6 KiB
TypeScript
124 lines
4.6 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import {
|
|
setupTest,
|
|
uploadFiles,
|
|
ensureDocumentsListed,
|
|
clickDocumentLink,
|
|
expectViewerForFile,
|
|
uploadAndDisplay,
|
|
playTTSAndWaitForASecond,
|
|
expectProcessingTransition,
|
|
} from './helpers';
|
|
|
|
// Single-spec helpers kept local to avoid cluttering shared helpers:
|
|
async function navigateToPdfPageViaNavigator(page: any, targetPage: number) {
|
|
// Navigator popover shows "X / Y"
|
|
const navTrigger = page.getByRole('button', { name: /\d+\s*\/\s*\d+/ });
|
|
await expect(navTrigger).toBeVisible({ timeout: 10000 });
|
|
await navTrigger.click();
|
|
|
|
const input = page.getByLabel('Page number');
|
|
await expect(input).toBeVisible({ timeout: 10000 });
|
|
await input.fill(String(targetPage));
|
|
await input.press('Enter');
|
|
}
|
|
|
|
async function countRenderedPdfPages(page: any): Promise<number> {
|
|
return await page.locator('.react-pdf__Page').count();
|
|
}
|
|
|
|
async function triggerViewportResize(page: any, width: number, height: number) {
|
|
await page.setViewportSize({ width, height });
|
|
}
|
|
|
|
test.describe('Document link navigation by type', () => {
|
|
test.beforeEach(async ({ page }, testInfo) => {
|
|
await setupTest(page, testInfo);
|
|
});
|
|
|
|
test('navigates to /pdf, /epub, /html and renders correct viewers', async ({ page }) => {
|
|
// Upload documents
|
|
await uploadFiles(page, 'sample.pdf', 'sample.epub', 'sample.txt');
|
|
|
|
// Ensure links exist
|
|
await ensureDocumentsListed(page, ['sample.pdf', 'sample.epub', 'sample.txt']);
|
|
|
|
// PDF
|
|
await clickDocumentLink(page, 'sample.pdf');
|
|
await expectViewerForFile(page, 'sample.pdf');
|
|
await page.goBack();
|
|
|
|
// EPUB
|
|
await clickDocumentLink(page, 'sample.epub');
|
|
await expectViewerForFile(page, 'sample.epub');
|
|
await page.goBack();
|
|
|
|
// TXT (HTML viewer)
|
|
await clickDocumentLink(page, 'sample.txt');
|
|
await expectViewerForFile(page, 'sample.txt');
|
|
});
|
|
});
|
|
|
|
test.describe('PDF view modes and Navigator', () => {
|
|
test.beforeEach(async ({ page }, testInfo) => {
|
|
await setupTest(page, testInfo);
|
|
});
|
|
|
|
test('switches Single/Dual/Scroll modes and uses Navigator to change page', async ({ page }) => {
|
|
test.setTimeout(60_000);
|
|
// Open PDF viewer
|
|
await uploadAndDisplay(page, 'sample.pdf');
|
|
await expect(page.locator('.react-pdf__Document')).toBeVisible({ timeout: 15000 });
|
|
|
|
// Open document settings (page-level settings)
|
|
await page.getByRole('button', { name: 'Open settings' }).click();
|
|
|
|
// Page mode now uses pill-style radios; switch from Single Page to Two Pages
|
|
await page.getByRole('radiogroup', { name: 'Page mode' }).getByRole('radio', { name: 'Two Pages' }).click();
|
|
await page.getByRole('button', { name: 'Close' }).click();
|
|
|
|
// Expect dual-page rendering (sample.pdf has >= 2 pages)
|
|
const dualCount = await countRenderedPdfPages(page);
|
|
expect(dualCount).toBeGreaterThanOrEqual(2);
|
|
|
|
// Switch to Continuous Scroll
|
|
await page.getByRole('button', { name: 'Open settings' }).click();
|
|
await page.getByRole('radiogroup', { name: 'Page mode' }).getByRole('radio', { name: 'Continuous Scroll' }).click();
|
|
await page.getByRole('button', { name: 'Close' }).click();
|
|
|
|
// Expect continuous scroll renders at least as many pages as dual mode
|
|
const scrollCount = await countRenderedPdfPages(page);
|
|
expect(scrollCount).toBeGreaterThanOrEqual(dualCount);
|
|
|
|
// Use Navigator to go to a page (clamps to last if too large)
|
|
await navigateToPdfPageViaNavigator(page, 999);
|
|
// Navigator jump is configured to pause; ensure Play is visible then resume
|
|
await expect(page.getByRole('button', { name: 'Play' })).toBeVisible({ timeout: 10000 });
|
|
await page.getByRole('button', { name: 'Play' }).click();
|
|
await expectProcessingTransition(page);
|
|
});
|
|
});
|
|
|
|
test.describe('EPUB resize pauses TTS', () => {
|
|
test.beforeEach(async ({ page }, testInfo) => {
|
|
await setupTest(page, testInfo);
|
|
});
|
|
|
|
test('resizing viewport pauses playback and play resumes after', async ({ page }) => {
|
|
// Start playback on EPUB
|
|
await playTTSAndWaitForASecond(page, 'sample.epub');
|
|
|
|
// Trigger a significant viewport resize to fire useEPUBResize
|
|
await triggerViewportResize(page, 1200, 900);
|
|
await page.waitForTimeout(750); // allow resize flag to propagate
|
|
await triggerViewportResize(page, 900, 700);
|
|
await page.waitForTimeout(750);
|
|
|
|
// After resize, playback should have paused (Play button visible)
|
|
await expect(page.getByRole('button', { name: 'Play' })).toBeVisible({ timeout: 15000 });
|
|
|
|
// Resume playback and ensure processing -> playing
|
|
await page.getByRole('button', { name: 'Play' }).click();
|
|
await expectProcessingTransition(page);
|
|
});
|
|
});
|