92 lines
3.6 KiB
JavaScript
92 lines
3.6 KiB
JavaScript
/**
|
|
* 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}"]`);
|
|
// Le vault peut être replié (auth activée) : l'étendre avant de chercher le fichier.
|
|
if (!(await treeItem.count())) {
|
|
await page.locator(`.tree-item.vault-item[data-vault="${vault}"]`).first().click();
|
|
await treeItem.waitFor({ state: 'attached', timeout: 8000 });
|
|
}
|
|
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([]);
|
|
});
|
|
}); |