(frontend) add an e2e test for complex PNG exports

Signed-off-by: Mathieu Agopian <mathieu@agopian.info>
This commit is contained in:
Mathieu Agopian
2026-09-04 10:07:25 +02:00
parent 08ff4a96e8
commit 0815c14d78
5 changed files with 24 additions and 48 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

@@ -247,46 +247,6 @@ test.describe('Doc Export', () => {
expect(pdfText.text).toContain('Hello World');
});
/**
* Regression test for https://github.com/suitenumerique/docs/issues/860
*
* PNG images were silently dropped from the exported PDF because the raw
* Blob was passed directly to @react-pdf/renderer's <Image src>, which
* triggered a WASM "too many arguments" error internally and caused the
* image to be omitted. SVG images were unaffected because they were already
* converted to a data URL string before being passed to <Image>.
*/
test('it includes PNG images in the exported PDF', async ({
page,
browserName,
}) => {
// overrideDocContent uploads both an SVG and a PNG image into the editor.
await overrideDocContent({ page, browserName });
await clickInEditorMenu(page, 'Download');
const downloadPromise = page.waitForEvent('download', (download) =>
download.suggestedFilename().endsWith('.pdf'),
);
void page.getByTestId('doc-export-download-button').click();
const download = await downloadPromise;
await page.waitForTimeout(1000);
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
// Each embedded image in a PDF is stored as an XObject stream whose
// dictionary contains /Width <naturalPixelWidth>. Emoji images are 64px
// wide, the SVG (test.svg, 100×100) becomes 100px. The uploaded PNG
// (logo-suite-numerique.png) is 756px wide — a value that won't appear
// for page sizes (A4 = 595 pt) or emoji. With the bug the PNG is silently
// dropped and /Width 756 is absent; after the fix it appears twice (image
// data stream + alpha-mask stream).
const pdfString = pdfBuffer.toString('latin1');
expect(pdfString).toMatch(/\/Width 756/);
});
test('it injects the correct language attribute into PDF export', async ({
page,
browserName,
@@ -57,16 +57,14 @@ export const overrideDocContent = async ({
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles(path.join(__dirname, 'assets/test.svg'));
const image = page
.locator('.--docs--editor-container img.bn-visual-media[src$=".svg"]')
.first();
await expect(image).toBeVisible({
timeout: 10000,
});
.locator('.--docs--editor-container')
.getByRole('img', { name: 'test.svg' });
await expect(image).toBeVisible();
await page.keyboard.press('Enter');
await page.waitForTimeout(1000);
// Add Image PNG
// Add a simple Image PNG (1 IDAT chunk)
await openSuggestionMenu({
page,
suggestion: 'Resizable image with caption',
@@ -78,12 +76,30 @@ export const overrideDocContent = async ({
path.join(__dirname, 'assets/logo-suite-numerique.png'),
);
const imagePng = page
.locator('.--docs--editor-container img.bn-visual-media[src$=".png"]')
.first();
.locator('.--docs--editor-container')
.getByRole('img', { name: 'logo-suite-numerique.png' });
await expect(imagePng).toBeVisible();
await page.waitForTimeout(1000);
// Add a more complex Image PNG (45 IDAT chunks)
await openSuggestionMenu({
page,
suggestion: 'Resizable image with caption',
});
const fileChooserComplexPNGPromise = page.waitForEvent('filechooser');
await page.getByText('Upload image').click();
const fileChooserComplexPNG = await fileChooserComplexPNGPromise;
await fileChooserComplexPNG.setFiles(
path.join(__dirname, 'assets/issue-860-complex-image.png'),
);
const complexImagePng = page
.locator('.--docs--editor-container')
.getByRole('img', { name: 'issue-860-complex-image.png' });
await expect(complexImagePng).toBeVisible();
await page.waitForTimeout(1000);
return randomDoc;
};