const { test, expect } = require('@playwright/test'); /** * v7.64.1 — Delete sur un bloc vide supprime le bloc (comme Backspace). * Instance de test attendue sur FD_BASE_URL (défaut 8081). */ const FD_BASE = process.env.FD_BASE_URL || 'http://localhost:8081'; const USER = process.env.FD_USER || 'e2e@flowdeck.local'; const PASS = process.env.FD_PASS || 'e2e-secret-123'; test.use({ serviceWorkers: 'block' }); async function login(page) { await page.goto(`${FD_BASE}/auth/login?provider=local`, { waitUntil: 'domcontentloaded' }); await page.fill('#email', USER); await page.fill('#password', PASS); await page.click('.btn-primary'); const ok = await page .waitForURL('**/workspaces', { timeout: 8000 }) .then(() => true) .catch(() => false); if (!ok) { const resp = await page.request.post(`${FD_BASE}/auth/register`, { data: { email: USER, password: PASS, name: 'E2E' }, }); if (resp.status() !== 409) expect(resp.ok()).toBeTruthy(); await page.goto(`${FD_BASE}/workspaces`, { waitUntil: 'domcontentloaded' }); } } test('Delete : vide le bloc puis supprime le bloc vide', async ({ page }) => { await login(page); const cookies = await page.context().cookies(); const csrf = (cookies.find((c) => c.name === 'csrf_token') || {}).value || ''; const created = await page.request.post( `${FD_BASE}/board/api/pages?title=Delete key ${Date.now()}`, { headers: { 'X-CSRF-Token': csrf } } ); expect(created.status(), await created.text()).toBeLessThan(400); const { id } = await created.json(); const bs = await page.request.post(`${FD_BASE}/board/api/pages/${id}/blocks`, { headers: { 'X-CSRF-Token': csrf }, data: { title: 'Delete key', blocks: [ { id: 'b1', type: 'paragraph', content: 'hello' }, { id: 'b2', type: 'paragraph', content: 'world' }, ] }, }); expect(bs.status(), await bs.text()).toBeLessThan(400); await page.goto(`${FD_BASE}/pages/${id}`, { waitUntil: 'domcontentloaded' }); await page.waitForSelector('#_blocksCt [data-bid]', { timeout: 15000 }); // ── 1. Delete avec du texte : suppression avant le curseur (comportement natif) ── await page.locator('#_blocksCt [data-bid]').nth(1).click(); await page.keyboard.press('Control+a'); await page.keyboard.press('Delete'); await page.waitForTimeout(200); const contents = await page.evaluate(() => { window.E.sync(); return window.E.blocks.map((b) => b.content); }); expect(contents[0]).toBe('hello'); expect(contents[1].trim()).toBe(''); // bloc vidé (un
résiduel), mais toujours là // ── 2. Delete sur le bloc vide : le bloc est supprimé ── await page.keyboard.press('Delete'); await page.waitForTimeout(300); expect(await page.evaluate(() => window.E.blocks.length)).toBe(1); expect(await page.evaluate(() => window.E.blocks[0].content)).toBe('hello'); await page.screenshot({ path: 'shots/v7641-delete.png' }); // ── 3. dernier bloc vide : jamais supprimé (l'éditeur garde un bloc) ── await page.locator('#_blocksCt [data-bid]').first().click(); await page.keyboard.press('Control+a'); await page.keyboard.press('Delete'); await page.waitForTimeout(150); await page.keyboard.press('Delete'); await page.waitForTimeout(300); expect(await page.evaluate(() => window.E.blocks.length)).toBe(1); expect(await page.evaluate(() => window.E.blocks[0].type)).toBe('paragraph'); });