openreader/tests/navigation.spec.ts
Richard R 265e1cb56a feat(tts,config,ui): add advanced segment preloading and block length controls
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.
2026-05-07 12:26:08 -06:00

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);
});
});