@@ -2,6 +2,7 @@ import path from 'path';
22
33import { expect , test } from '@playwright/test' ;
44import cs from 'convert-stream' ;
5+ import JSZip from 'jszip' ;
56import { PDFParse } from 'pdf-parse' ;
67
78import {
@@ -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 ( / D o w n l o a d y o u r d o c u m e n t i n a \ .d o c x , \ .o d t . * f o r m a t \. / 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' , / .* \. s v g / ) ;
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
0 commit comments