fix(pdf): affichage des pages du viewer PDF via iframe (BUG-060)
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* E2E tests for ObsiGate PDF inline viewer (BUG-060).
|
||||
*
|
||||
* Regression : la CSP posée par BUG-034 (`object-src 'none'`) bloque l'élément
|
||||
* `<embed>` qui servait le PDF. Le viewer doit rendre le stream dans une
|
||||
* `<iframe>` (autorisée par `frame-src 'self'`).
|
||||
*
|
||||
* Fixtures : `test_vault/sample-pdf.pdf` (3 pages, texte simple).
|
||||
*
|
||||
* Run (local):
|
||||
* BASE_URL=http://localhost:2029 npx playwright test tests/e2e/pdf-viewer.spec.js
|
||||
* BASE_URL=http://localhost:2029 npx playwright test tests/e2e/pdf-viewer.spec.js --headed
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const BASE = process.env.BASE_URL || 'http://localhost:2029';
|
||||
|
||||
const CREDS = {
|
||||
username: process.env.OBSIGATE_USER || 'admin',
|
||||
password: process.env.OBSIGATE_PASS || 'test123',
|
||||
};
|
||||
|
||||
async function login(page) {
|
||||
await page.goto(BASE);
|
||||
const loginForm = page.locator('#login-screen');
|
||||
await expect(loginForm).toBeVisible({ timeout: 5000 }).catch(() => {});
|
||||
if (await loginForm.isVisible()) {
|
||||
await page.fill('#login-username', CREDS.username);
|
||||
await page.fill('#login-password', CREDS.password);
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function openFile(page, vault, filePath) {
|
||||
const treeItem = page.locator(`.tree-item[data-vault="${vault}"][data-path="${filePath}"]`);
|
||||
if (!(await treeItem.isVisible().catch(() => false))) {
|
||||
const vaultItem = page.locator(`.vault-item[data-vault="${vault}"]`).first();
|
||||
if (await vaultItem.count() > 0) {
|
||||
await vaultItem.click();
|
||||
await page.waitForTimeout(800);
|
||||
}
|
||||
}
|
||||
await treeItem.dblclick({ timeout: 5000 });
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
test.describe('PDF viewer — affichage inline (BUG-060)', () => {
|
||||
|
||||
test('ouvre un PDF dans une iframe (pas d\'<embed>) et le stream charge sans violation CSP', async ({ page }) => {
|
||||
const cspViolations = [];
|
||||
page.on('console', (msg) => {
|
||||
const text = msg.text();
|
||||
if (text.includes('Content Security Policy') && (text.includes('object-src') || text.includes('Refused'))) {
|
||||
cspViolations.push(text);
|
||||
}
|
||||
});
|
||||
|
||||
await login(page);
|
||||
|
||||
// Le stream est demandé au moment où le viewer monte l'iframe : enregistrer
|
||||
// l'écoute AVANT d'ouvrir le fichier (sinon la réponse est déjà passée).
|
||||
const streamResponsePromise = page.waitForResponse(
|
||||
(r) => r.url().includes('/pdf/stream') && (r.status() === 200 || r.status() === 206),
|
||||
{ timeout: 15000 },
|
||||
);
|
||||
|
||||
await openFile(page, 'TestVault', 'sample-pdf.pdf');
|
||||
|
||||
const iframe = page.locator('#content-area .pdf-iframe');
|
||||
await expect(iframe).toBeVisible({ timeout: 15000 });
|
||||
await expect(iframe).toHaveAttribute('src', /\/api\/file\/TestVault\/pdf\/stream\?path=/);
|
||||
|
||||
// La balise doit être une iframe (le <embed>/<object> serait bloqué par CSP)
|
||||
const tagName = await iframe.evaluate((el) => el.tagName);
|
||||
expect(tagName).toBe('IFRAME');
|
||||
expect(await page.locator('#content-area embed, #content-area object').count()).toBe(0);
|
||||
|
||||
// La barre d'outils indique le nombre de pages du PDF
|
||||
await expect(page.locator('.pdf-info')).toContainText('3 pages');
|
||||
|
||||
// Le stream est bien servi en application/pdf (200 ou 206 Range)
|
||||
const streamResp = await streamResponsePromise;
|
||||
expect(streamResp.headers()['content-type'] || '').toContain('application/pdf');
|
||||
|
||||
// Le cadre embarque réellement le document PDF (navigateur natif)
|
||||
const pdfFrame = await iframe.contentFrame();
|
||||
expect(pdfFrame).not.toBeNull();
|
||||
|
||||
// Aucune violation CSP liée à object-src pendant l'ouverture
|
||||
expect(cspViolations).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user