tests: harden pdf readiness waits and extend tts/pdf timeouts
This commit is contained in:
parent
3f17874fe5
commit
e70b3619e0
8 changed files with 31 additions and 15 deletions
|
|
@ -443,7 +443,7 @@ export default function PDFViewerPage() {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{isLoading || !isParseReady || !isPdfViewerReady ? (
|
{isLoading || !isParseReady || !isPdfViewerReady ? (
|
||||||
<div className="absolute inset-0 z-10">
|
<div className="absolute inset-0 z-10" data-testid="pdf-status-loader">
|
||||||
{renderPdfStatusLoader()}
|
{renderPdfStatusLoader()}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ test.describe('Accessibility smoke', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('TTS controls expose aria labels and are keyboard focusable', async ({ page }) => {
|
test('TTS controls expose aria labels and are keyboard focusable', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
|
|
||||||
// TTS bar present
|
// TTS bar present
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ async function resetAudiobookIfPresent(page: Page, bookId?: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
test('exports full MP3 audiobook for PDF using mocked 10s TTS sample', async ({ page }, testInfo) => {
|
test('exports full MP3 audiobook for PDF using mocked 10s TTS sample', async ({ page }, testInfo) => {
|
||||||
test.setTimeout(60_000);
|
test.setTimeout(120_000);
|
||||||
|
|
||||||
// Ensure TTS is mocked and app is ready
|
// Ensure TTS is mocked and app is ready
|
||||||
await setupTest(page, testInfo);
|
await setupTest(page, testInfo);
|
||||||
|
|
@ -382,7 +382,7 @@ test('exports partial MP3 audiobook for EPUB using mocked 10s TTS sample', async
|
||||||
});
|
});
|
||||||
|
|
||||||
test('exports a single MP3 audiobook PDF page via chapters menu', async ({ page }, testInfo) => {
|
test('exports a single MP3 audiobook PDF page via chapters menu', async ({ page }, testInfo) => {
|
||||||
test.setTimeout(60_000);
|
test.setTimeout(120_000);
|
||||||
await setupTest(page, testInfo);
|
await setupTest(page, testInfo);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
@ -413,6 +413,7 @@ test('exports a single MP3 audiobook PDF page via chapters menu', async ({ page
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resets all MP3 audiobook PDF pages', async ({ page }, testInfo) => {
|
test('resets all MP3 audiobook PDF pages', async ({ page }, testInfo) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await setupTest(page, testInfo);
|
await setupTest(page, testInfo);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
@ -451,7 +452,7 @@ test('resets all MP3 audiobook PDF pages', async ({ page }, testInfo) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('regenerates a single MP3 audiobook PDF page and exports full audiobook', async ({ page }, testInfo) => {
|
test('regenerates a single MP3 audiobook PDF page and exports full audiobook', async ({ page }, testInfo) => {
|
||||||
test.setTimeout(60_000);
|
test.setTimeout(120_000);
|
||||||
await setupTest(page, testInfo);
|
await setupTest(page, testInfo);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
@ -525,7 +526,7 @@ test('regenerates a single MP3 audiobook PDF page and exports full audiobook', a
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resumes audiobook when a chapter is missing and full download succeeds (PDF)', async ({ page }, testInfo) => {
|
test('resumes audiobook when a chapter is missing and full download succeeds (PDF)', async ({ page }, testInfo) => {
|
||||||
test.setTimeout(60_000);
|
test.setTimeout(120_000);
|
||||||
await setupTest(page, testInfo);
|
await setupTest(page, testInfo);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,23 @@ function sha256HexOfFile(filePath: string) {
|
||||||
|
|
||||||
async function waitForPdfViewerReady(page: Page, timeout = 60000) {
|
async function waitForPdfViewerReady(page: Page, timeout = 60000) {
|
||||||
await expect(page).toHaveURL(/\/pdf\/[A-Za-z0-9._%-]+$/, { timeout: Math.min(timeout, 20000) });
|
await expect(page).toHaveURL(/\/pdf\/[A-Za-z0-9._%-]+$/, { timeout: Math.min(timeout, 20000) });
|
||||||
|
const loader = page.getByTestId('pdf-status-loader').first();
|
||||||
|
const parseFailedBanner = page.getByText('PDF parsing failed. Retry to continue.').first();
|
||||||
await expect
|
await expect
|
||||||
.poll(async () => {
|
.poll(async () => {
|
||||||
|
const parseFailed = await parseFailedBanner.isVisible().catch(() => false);
|
||||||
|
if (parseFailed) return 'failed';
|
||||||
|
|
||||||
const documentVisible = await page.locator('.react-pdf__Document').first().isVisible().catch(() => false);
|
const documentVisible = await page.locator('.react-pdf__Document').first().isVisible().catch(() => false);
|
||||||
if (documentVisible) return true;
|
|
||||||
const pageVisible = await page.locator('.react-pdf__Page').first().isVisible().catch(() => false);
|
const pageVisible = await page.locator('.react-pdf__Page').first().isVisible().catch(() => false);
|
||||||
if (pageVisible) return true;
|
|
||||||
const canvasVisible = await page.locator('.react-pdf__Page canvas').first().isVisible().catch(() => false);
|
const canvasVisible = await page.locator('.react-pdf__Page canvas').first().isVisible().catch(() => false);
|
||||||
if (canvasVisible) return true;
|
|
||||||
return false;
|
const hasRenderedPdf = documentVisible || pageVisible || canvasVisible;
|
||||||
|
const loaderVisible = await loader.isVisible().catch(() => false);
|
||||||
|
if (hasRenderedPdf && !loaderVisible) return 'ready';
|
||||||
|
return 'loading';
|
||||||
}, { timeout })
|
}, { timeout })
|
||||||
.toBe(true);
|
.toBe('ready');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -396,7 +402,7 @@ export async function expectViewerForFile(page: Page, fileName: string) {
|
||||||
if (lower.endsWith('.pdf') || lower.endsWith('.docx')) {
|
if (lower.endsWith('.pdf') || lower.endsWith('.docx')) {
|
||||||
// DOCX converts to PDF, so viewer expectations are PDF
|
// DOCX converts to PDF, so viewer expectations are PDF
|
||||||
await expect(page).toHaveURL(/\/pdf\/[A-Za-z0-9._%-]+$/);
|
await expect(page).toHaveURL(/\/pdf\/[A-Za-z0-9._%-]+$/);
|
||||||
await expect(page.locator('.react-pdf__Document')).toBeVisible({ timeout: 15000 });
|
await waitForPdfViewerReady(page, 60000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (lower.endsWith('.epub')) {
|
if (lower.endsWith('.epub')) {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ test.describe('Landing and app routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('documents back link returns to /app', async ({ page }, testInfo) => {
|
test('documents back link returns to /app', async ({ page }, testInfo) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await setupTest(page, testInfo);
|
await setupTest(page, testInfo);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ test.describe('Document link navigation by type', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('navigates to /pdf, /epub, /html and renders correct viewers', async ({ page }) => {
|
test('navigates to /pdf, /epub, /html and renders correct viewers', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
// Upload documents
|
// Upload documents
|
||||||
await uploadFiles(page, 'sample.pdf', 'sample.epub', 'sample.txt');
|
await uploadFiles(page, 'sample.pdf', 'sample.epub', 'sample.txt');
|
||||||
|
|
||||||
|
|
@ -65,10 +66,9 @@ test.describe('PDF view modes and Navigator', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('switches Single/Dual/Scroll modes and uses Navigator to change page', async ({ page }) => {
|
test('switches Single/Dual/Scroll modes and uses Navigator to change page', async ({ page }) => {
|
||||||
test.setTimeout(60_000);
|
test.setTimeout(120_000);
|
||||||
// Open PDF viewer
|
// Open PDF viewer
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
await expect(page.locator('.react-pdf__Document')).toBeVisible({ timeout: 15000 });
|
|
||||||
|
|
||||||
// Open document settings (page-level settings)
|
// Open document settings (page-level settings)
|
||||||
await page.getByRole('button', { name: 'Open settings' }).click();
|
await page.getByRole('button', { name: 'Open settings' }).click();
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ test.describe('Play/Pause Tests', () => {
|
||||||
test.describe.configure({ mode: 'serial', timeout: 60000 });
|
test.describe.configure({ mode: 'serial', timeout: 60000 });
|
||||||
|
|
||||||
test('plays and pauses TTS for a PDF document', async ({ page }) => {
|
test('plays and pauses TTS for a PDF document', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
// Play TTS for the PDF document
|
// Play TTS for the PDF document
|
||||||
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
@ -61,6 +62,7 @@ test.describe('Play/Pause Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('plays and pauses TTS for an DOCX document', async ({ page }) => {
|
test('plays and pauses TTS for an DOCX document', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
// Play TTS for the DOCX document
|
// Play TTS for the DOCX document
|
||||||
await playTTSAndWaitForASecond(page, 'sample.docx');
|
await playTTSAndWaitForASecond(page, 'sample.docx');
|
||||||
|
|
||||||
|
|
@ -77,6 +79,7 @@ test.describe('Play/Pause Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('switches to a single voice and resumes playing', async ({ page }) => {
|
test('switches to a single voice and resumes playing', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
// Start playback
|
// Start playback
|
||||||
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
@ -96,6 +99,7 @@ test.describe('Play/Pause Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('keeps selected single voice instead of resetting to first option', async ({ page }) => {
|
test('keeps selected single voice instead of resetting to first option', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
||||||
|
|
||||||
await openVoicesMenu(page);
|
await openVoicesMenu(page);
|
||||||
|
|
@ -122,6 +126,7 @@ test.describe('Play/Pause Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!process.env.CI) test('selects multiple Kokoro voices and resumes playing', async ({ page }) => {
|
if (!process.env.CI) test('selects multiple Kokoro voices and resumes playing', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
// Start playback
|
// Start playback
|
||||||
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
||||||
|
|
||||||
|
|
@ -142,6 +147,7 @@ test.describe('Play/Pause Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('changing TTS native speed toggles processing and returns to playing', async ({ page }) => {
|
test('changing TTS native speed toggles processing and returns to playing', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
await playTTSAndWaitForASecond(page, 'sample.pdf');
|
||||||
await changeNativeSpeedAndAssert(page, 1.5);
|
await changeNativeSpeedAndAssert(page, 1.5);
|
||||||
await expectMediaState(page, 'playing');
|
await expectMediaState(page, 'playing');
|
||||||
|
|
|
||||||
|
|
@ -88,10 +88,10 @@ test.describe('Document Upload Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('displays a PDF document', async ({ page }) => {
|
test('displays a PDF document', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await uploadAndDisplay(page, 'sample.pdf');
|
await uploadAndDisplay(page, 'sample.pdf');
|
||||||
await expectViewerForFile(page, 'sample.pdf');
|
await expectViewerForFile(page, 'sample.pdf');
|
||||||
// Additional content checks specific to the sample PDF
|
// Additional content checks specific to the sample PDF
|
||||||
await expect(page.locator('.react-pdf__Page')).toBeVisible();
|
|
||||||
await expect(page.getByRole('heading', { level: 1, name: 'sample.pdf' })).toBeVisible();
|
await expect(page.getByRole('heading', { level: 1, name: 'sample.pdf' })).toBeVisible();
|
||||||
await expect(page.getByRole('button', { name: /1\s*\/\s*2/ })).toBeVisible();
|
await expect(page.getByRole('button', { name: /1\s*\/\s*2/ })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
@ -105,10 +105,10 @@ test.describe('Document Upload Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('displays a DOCX document as PDF after conversion', async ({ page }) => {
|
test('displays a DOCX document as PDF after conversion', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
await uploadAndDisplay(page, 'sample.docx');
|
await uploadAndDisplay(page, 'sample.docx');
|
||||||
await expectViewerForFile(page, 'sample.docx'); // DOCX converts to PDF
|
await expectViewerForFile(page, 'sample.docx'); // DOCX converts to PDF
|
||||||
// Keep specific content checks
|
// Keep specific content checks
|
||||||
await expect(page.locator('.react-pdf__Page')).toBeVisible();
|
|
||||||
await expect(page.getByText('Demonstration of DOCX')).toBeVisible();
|
await expect(page.getByText('Demonstration of DOCX')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -119,6 +119,7 @@ test.describe('Document Upload Tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('uploads PDF/EPUB/TXT and opens correct viewer for each', async ({ page }) => {
|
test('uploads PDF/EPUB/TXT and opens correct viewer for each', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
// Upload multiple files
|
// Upload multiple files
|
||||||
await uploadFiles(page, 'sample.pdf', 'sample.epub', 'sample.txt');
|
await uploadFiles(page, 'sample.pdf', 'sample.epub', 'sample.txt');
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue