164 lines
7.0 KiB
JavaScript
164 lines
7.0 KiB
JavaScript
/**
|
|
* E2E tests for the ObsiGate media viewers & persistent player (roadmap #109/#110).
|
|
*
|
|
* Fixtures : `test_vault/sample-audio.mp3` (1 s sine) + `test_vault/sample-video.webm`.
|
|
*
|
|
* Run (local):
|
|
* BASE_URL=http://localhost:2029 npx playwright test tests/e2e/media-viewer.spec.js
|
|
*/
|
|
|
|
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.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 });
|
|
}
|
|
|
|
test.describe('Media viewers — HTML5 audio/video (#109)', () => {
|
|
|
|
test('rend un lecteur audio natif branché sur /api/media', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-audio.mp3');
|
|
|
|
const audio = page.locator('#content-area .audio-viewer-container audio.np-media--audio');
|
|
await expect(audio).toBeVisible({ timeout: 10000 });
|
|
await expect(audio).toHaveAttribute('src', /\/api\/media\/TestVault\?path=/);
|
|
await expect(audio).toHaveAttribute('controls', '');
|
|
await expect(page.locator('#content-area .media-duration-badge')).not.toHaveText('--:--', { timeout: 10000 });
|
|
});
|
|
|
|
test('rend un lecteur vidéo natif branché sur /api/media', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-video.webm');
|
|
|
|
const video = page.locator('#content-area .video-viewer-container video.np-media--video');
|
|
await expect(video).toBeVisible({ timeout: 10000 });
|
|
await expect(video).toHaveAttribute('src', /\/api\/media\/TestVault\?path=/);
|
|
await expect(video).toHaveAttribute('playsinline', '');
|
|
});
|
|
|
|
test('le streaming média honore les requêtes Range (206)', async ({ page }) => {
|
|
await login(page);
|
|
const resp = await page.request.get(
|
|
`${BASE}/api/media/TestVault?path=${encodeURIComponent('sample-video.webm')}`,
|
|
{ headers: { Range: 'bytes=0-99' } },
|
|
);
|
|
expect(resp.status()).toBe(206);
|
|
expect(resp.headers()['content-range']).toMatch(/^bytes 0-99\/\d+$/);
|
|
expect(resp.headers()['accept-ranges']).toBe('bytes');
|
|
});
|
|
});
|
|
|
|
test.describe('Now Playing — lecture persistante (#110)', () => {
|
|
|
|
test('affiche le dock et continue la lecture quand on navigue ailleurs', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-audio.mp3');
|
|
await expect(page.locator('#content-area audio.np-media--audio')).toBeVisible({ timeout: 10000 });
|
|
|
|
// Naviguer vers une note : le média doit passer dans le dock.
|
|
await openFile(page, 'TestVault', 'note1.md');
|
|
const dock = page.locator('#now-playing-host .np-dock--audio');
|
|
await expect(dock).toBeVisible({ timeout: 10000 });
|
|
await expect(dock.locator('.np-dock-title')).toHaveText('sample-audio.mp3');
|
|
|
|
// S'assurer de la lecture (l'autoplay peut être bloqué sans geste).
|
|
const media = page.locator('#now-playing-host audio.np-media--audio');
|
|
if (await media.evaluate((el) => el.paused)) {
|
|
await dock.locator('[data-np="play"]').click();
|
|
}
|
|
await expect.poll(() => media.evaluate((el) => !el.paused), { timeout: 5000 }).toBe(true);
|
|
|
|
// Naviguer encore : toujours en lecture.
|
|
await openFile(page, 'TestVault', 'Accueil.md');
|
|
await expect(dock).toBeVisible();
|
|
expect(await media.evaluate((el) => !el.paused)).toBe(true);
|
|
});
|
|
|
|
test('revient sur le média depuis le dock', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-audio.mp3');
|
|
await expect(page.locator('#content-area audio.np-media--audio')).toBeVisible({ timeout: 10000 });
|
|
await openFile(page, 'TestVault', 'note1.md');
|
|
|
|
const dock = page.locator('#now-playing-host .np-dock--audio');
|
|
await expect(dock).toBeVisible({ timeout: 10000 });
|
|
await dock.locator('[data-np="reopen"]').click();
|
|
|
|
await expect(page.locator('#content-area .audio-viewer-container audio.np-media--audio')).toBeVisible({ timeout: 10000 });
|
|
await expect(dock).toBeHidden();
|
|
});
|
|
|
|
test('ferme la lecture depuis le dock', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-audio.mp3');
|
|
await expect(page.locator('#content-area audio.np-media--audio')).toBeVisible({ timeout: 10000 });
|
|
await openFile(page, 'TestVault', 'note1.md');
|
|
|
|
const dock = page.locator('#now-playing-host .np-dock--audio');
|
|
await expect(dock).toBeVisible({ timeout: 10000 });
|
|
await dock.locator('[data-np="close"]').click();
|
|
await expect(page.locator('#now-playing-host .np-dock--audio')).toBeHidden();
|
|
});
|
|
|
|
test('le mini-player vidéo flotte et reste visible en naviguant', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-video.webm');
|
|
await expect(page.locator('#content-area video.np-media--video')).toBeVisible({ timeout: 10000 });
|
|
await openFile(page, 'TestVault', 'note1.md');
|
|
|
|
const mini = page.locator('#now-playing-host .np-dock--video');
|
|
await expect(mini).toBeVisible({ timeout: 10000 });
|
|
await expect(mini.locator('video.np-media--video')).toBeVisible();
|
|
});
|
|
|
|
test('la mini-fenêtre vidéo peut être déplacée librement (centre)', async ({ page }) => {
|
|
await login(page);
|
|
await openFile(page, 'TestVault', 'sample-video.webm');
|
|
await expect(page.locator('#content-area video.np-media--video')).toBeVisible({ timeout: 10000 });
|
|
await openFile(page, 'TestVault', 'note1.md');
|
|
|
|
const mini = page.locator('#now-playing-host .np-dock--video');
|
|
await expect(mini).toBeVisible({ timeout: 10000 });
|
|
const before = await mini.evaluate((el) => ({ left: parseFloat(el.style.left), top: parseFloat(el.style.top) }));
|
|
|
|
const box = await mini.boundingBox();
|
|
await page.mouse.move(box.x + box.width / 2, box.y + 12);
|
|
await page.mouse.down();
|
|
await page.mouse.move(640, 360, { steps: 12 });
|
|
await page.mouse.up();
|
|
|
|
const after = await mini.evaluate((el) => ({ left: parseFloat(el.style.left), top: parseFloat(el.style.top) }));
|
|
expect(after.left).not.toBe(before.left);
|
|
expect(after.top).not.toBe(before.top);
|
|
// Doit pouvoir rester au centre (pas de re-aimantation sur les bords).
|
|
expect(after.left).toBeGreaterThan(50);
|
|
expect(after.left).toBeLessThan(900);
|
|
expect(after.top).toBeGreaterThan(20);
|
|
expect(after.top).toBeLessThan(600);
|
|
});
|
|
});
|