Skip to content

Commit 9b03754

Browse files
committed
✅(e2e) add test for accessible html export from export modal
checks generated zip contains html and embedded media files Signed-off-by: Cyril <[email protected]>
1 parent 0805216 commit 9b03754

File tree

6 files changed

+89
-126
lines changed

6 files changed

+89
-126
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to
1010

1111
- ♿(frontend) improve accessibility:
1212
- ♿(frontend) add skip to content button for keyboard accessibility #1624
13+
- ⚡️(frontend) Enhance/html copy to download #1669
1314

1415
### Fixed
1516

src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'path';
22

33
import { expect, test } from '@playwright/test';
44
import cs from 'convert-stream';
5+
import JSZip from 'jszip';
56
import { PDFParse } from 'pdf-parse';
67

78
import {
@@ -31,7 +32,7 @@ test.describe('Doc Export', () => {
3132

3233
await expect(page.getByTestId('modal-export-title')).toBeVisible();
3334
await expect(
34-
page.getByText('Download your document in a .docx, .odt or .pdf format.'),
35+
page.getByText(/Download your document in a \.docx, \.odt.*format\./i),
3536
).toBeVisible();
3637
await expect(
3738
page.getByRole('combobox', { name: 'Template' }),
@@ -187,6 +188,86 @@ test.describe('Doc Export', () => {
187188
expect(download.suggestedFilename()).toBe(`${randomDoc}.odt`);
188189
});
189190

191+
test('it exports the doc to html zip', async ({ page, browserName }) => {
192+
const [randomDoc] = await createDoc(
193+
page,
194+
'doc-editor-html-zip',
195+
browserName,
196+
1,
197+
);
198+
199+
await verifyDocName(page, randomDoc);
200+
201+
// Add some content and at least one image so that the ZIP contains media files.
202+
await page.locator('.ProseMirror.bn-editor').click();
203+
await page.locator('.ProseMirror.bn-editor').fill('Hello HTML ZIP');
204+
205+
await page.keyboard.press('Enter');
206+
await page.locator('.bn-block-outer').last().fill('/');
207+
await page.getByText('Resizable image with caption').click();
208+
209+
const fileChooserPromise = page.waitForEvent('filechooser');
210+
await page.getByText('Upload image').click();
211+
212+
const fileChooser = await fileChooserPromise;
213+
await fileChooser.setFiles(path.join(__dirname, 'assets/test.svg'));
214+
215+
const image = page
216+
.locator('.--docs--editor-container img.bn-visual-media')
217+
.first();
218+
219+
// Wait for the image to be attached and have a valid src (aria-hidden prevents toBeVisible on Chromium)
220+
await expect(image).toBeAttached({ timeout: 10000 });
221+
await expect(image).toHaveAttribute('src', /.*\.svg/);
222+
223+
// Give some time for the image to be fully processed
224+
await page.waitForTimeout(1000);
225+
226+
await page
227+
.getByRole('button', {
228+
name: 'Export the document',
229+
})
230+
.click();
231+
232+
await page.getByRole('combobox', { name: 'Format' }).click();
233+
await page.getByRole('option', { name: 'HTML' }).click();
234+
235+
await expect(page.getByTestId('doc-export-download-button')).toBeVisible();
236+
237+
const downloadPromise = page.waitForEvent('download', (download) => {
238+
return download.suggestedFilename().includes(`${randomDoc}.zip`);
239+
});
240+
241+
void page.getByTestId('doc-export-download-button').click();
242+
243+
const download = await downloadPromise;
244+
expect(download.suggestedFilename()).toBe(`${randomDoc}.zip`);
245+
246+
const zipBuffer = await cs.toBuffer(await download.createReadStream());
247+
// Unzip and inspect contents
248+
const zip = await JSZip.loadAsync(zipBuffer);
249+
250+
// Check that index.html exists
251+
const indexHtml = zip.file('index.html');
252+
expect(indexHtml).not.toBeNull();
253+
254+
// Read and verify HTML content
255+
const htmlContent = await indexHtml!.async('string');
256+
expect(htmlContent).toContain('Hello HTML ZIP');
257+
258+
// Check for media files (they are at the root of the ZIP, not in a media/ folder)
259+
// Media files are named like "1-test.svg" or "media-1.png" by deriveMediaFilename
260+
const allFiles = Object.keys(zip.files);
261+
const mediaFiles = allFiles.filter(
262+
(name) => name !== 'index.html' && !name.endsWith('/'),
263+
);
264+
expect(mediaFiles.length).toBeGreaterThan(0);
265+
266+
// Verify the SVG image is included
267+
const svgFile = mediaFiles.find((name) => name.endsWith('.svg'));
268+
expect(svgFile).toBeDefined();
269+
});
270+
190271
/**
191272
* This test tell us that the export to pdf is working with images
192273
* but it does not tell us if the images are being displayed correctly

src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -408,40 +408,6 @@ test.describe('Doc Header', () => {
408408
expect(clipboardContent.trim()).toBe('# Hello World');
409409
});
410410

411-
test('It checks the copy as HTML button', async ({ page, browserName }) => {
412-
test.skip(
413-
browserName === 'webkit',
414-
'navigator.clipboard is not working with webkit and playwright',
415-
);
416-
417-
// create page and navigate to it
418-
await page
419-
.getByRole('button', {
420-
name: 'New doc',
421-
})
422-
.click();
423-
424-
// Add dummy content to the doc
425-
const editor = page.locator('.ProseMirror');
426-
const docFirstBlock = editor.locator('.bn-block-content').first();
427-
await docFirstBlock.click();
428-
await page.keyboard.type('# Hello World', { delay: 100 });
429-
const docFirstBlockContent = docFirstBlock.locator('h1');
430-
await expect(docFirstBlockContent).toHaveText('Hello World');
431-
432-
// Copy content to clipboard
433-
await page.getByLabel('Open the document options').click();
434-
await page.getByRole('menuitem', { name: 'Copy as HTML' }).click();
435-
await expect(page.getByText('Copied to clipboard')).toBeVisible();
436-
437-
// Test that clipboard is in HTML format
438-
const handle = await page.evaluateHandle(() =>
439-
navigator.clipboard.readText(),
440-
);
441-
const clipboardContent = await handle.jsonValue();
442-
expect(clipboardContent.trim()).toBe(`<h1>Hello World</h1><p></p>`);
443-
});
444-
445411
test('it checks the copy link button', async ({ page, browserName }) => {
446412
test.skip(
447413
browserName === 'webkit',

src/frontend/apps/impress/src/features/docs/doc-export/__tests__/ExportMIT.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ describe('useModuleExport', () => {
1616
const Export = await import('@/features/docs/doc-export/');
1717

1818
expect(Export.default).toBeUndefined();
19-
}, 10000);
19+
}, 15000);
2020

2121
it('should load modules when NEXT_PUBLIC_PUBLISH_AS_MIT is false', async () => {
2222
process.env.NEXT_PUBLIC_PUBLISH_AS_MIT = 'false';
2323
const Export = await import('@/features/docs/doc-export/');
2424

2525
expect(Export.default).toHaveProperty('ModalExport');
26-
});
26+
}, 15000);
2727
});

src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBox.spec.tsx

Lines changed: 0 additions & 86 deletions
This file was deleted.

src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxLicence.spec.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ describe('DocToolBox - Licence', () => {
4242
});
4343
const optionsButton = await screen.findByLabelText('Export the document');
4444
await userEvent.click(optionsButton);
45+
46+
// Wait for the export modal to be visible, then assert on its content text.
47+
await screen.findByTestId('modal-export-title');
4548
expect(
46-
await screen.findByText(
47-
'Download your document in a .docx, .odt or .pdf format.',
48-
),
49+
screen.getByText(/Download your document in a .docx, .odt.*format\./i),
4950
).toBeInTheDocument();
5051
}, 10000);
5152

0 commit comments

Comments
 (0)