import { expect, test } from '@playwright/test'; import { contextForUser } from './helpers'; /** * Export pack (issue #65): the pond-settings ZIP download and the page-menu * office-format export. The ZIP needs no conversion sidecar; `.docx` runs a * conversion job and self-skips without `E2E_PANDOC` (CI's e2e stack has no * reachable pandoc — same as the import pack, #64). Selectors are * language-neutral (CSS classes, not button text). */ const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:5173'; async function personalPond( context: Awaited>, ): Promise<{ id: string; slug: string }> { const ponds = await context.request.get('/api/v1/ponds'); const pond = (await ponds.json()).find((p: { type: string }) => p.type === 'personal'); return { id: pond.id, slug: pond.slug }; } test('downloads a pond as a Markdown ZIP from pond settings', async ({ browser }) => { const context = await contextForUser(browser, BASE_URL, 'fixture-user'); const pond = await personalPond(context); // Make sure the pond has at least one page to export. await context.request.post(`/api/v1/ponds/${pond.id}/pages`, { data: { title: `Export Me ${Date.now()}` }, }); const page = await context.newPage(); await page.goto(`/p/${pond.slug}/settings`); const [download] = await Promise.all([ page.waitForEvent('download'), page.locator('.pond-export a').click(), ]); expect(download.suggestedFilename()).toBe(`${pond.slug}.zip`); await context.close(); }); test('exports a page to .docx from the page menu', async ({ browser }) => { test.skip(!process.env.E2E_PANDOC, 'needs a reachable pandoc sidecar'); const context = await contextForUser(browser, BASE_URL, 'fixture-user'); const pond = await personalPond(context); const created = await context.request.post(`/api/v1/ponds/${pond.id}/pages`, { data: { title: `Docx Export ${Date.now()}` }, }); const created_page = await created.json(); const page = await context.newPage(); await page.goto(`/p/${pond.slug}/${created_page.slug}`); // The first export button is `.docx`; clicking runs the job and downloads it. const [download] = await Promise.all([ page.waitForEvent('download', { timeout: 30000 }), page.locator('.editor-page__export button').first().click(), ]); expect(download.suggestedFilename()).toBe(`${created_page.slug}.docx`); await context.close(); }); test('exports a page to PDF from the page menu', async ({ browser }) => { // PDF needs the Gotenberg sidecar reachable by the api (like the .docx case // needs pandoc). CI's e2e stack has none, so this runs locally / on a stage // with E2E_GOTENBERG set. test.skip(!process.env.E2E_GOTENBERG, 'needs a reachable Gotenberg sidecar'); const context = await contextForUser(browser, BASE_URL, 'fixture-user'); const pond = await personalPond(context); const created = await context.request.post(`/api/v1/ponds/${pond.id}/pages`, { data: { title: `Pdf Export ${Date.now()}` }, }); const created_page = await created.json(); const page = await context.newPage(); await page.goto(`/p/${pond.slug}/${created_page.slug}`); // The third export button is PDF (docx, odt, pdf). const [download] = await Promise.all([ page.waitForEvent('download', { timeout: 30000 }), page.locator('.editor-page__export button').nth(2).click(), ]); expect(download.suggestedFilename()).toBe(`${created_page.slug}.pdf`); await context.close(); });