mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-10 11:47:52 +02:00
✅(frontend) add an e2e test for complex PNG exports
In order to ensure that complex PNG images are exported correctly, we have added an end-to-end test that verifies the export functionality. This test will help catch any regressions related to image exports in future updates. Signed-off-by: Mathieu Agopian <mathieu@agopian.info>
This commit is contained in:
BIN
Binary file not shown.
Binary file not shown.
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,
|
||||
|
||||
@@ -261,8 +261,7 @@ export const goToGridDoc = async (
|
||||
|
||||
export const updateDocTitle = async (page: Page, title: string) => {
|
||||
const input = page.getByRole('textbox', { name: 'Document title' });
|
||||
await expect(input).toHaveText('');
|
||||
await expect(input).toBeVisible();
|
||||
await expect(input).toBeEmpty({ timeout: 10000 });
|
||||
await input.fill(title, {
|
||||
force: true,
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -56,10 +56,19 @@ export const createRootSubPage = async (
|
||||
};
|
||||
|
||||
export const clickOnAddRootSubPage = async (page: Page) => {
|
||||
const currentUrl = page.url();
|
||||
const docTree = page.getByTestId('doc-tree');
|
||||
const rootItem = page.getByTestId('doc-tree-root-item');
|
||||
await expect(rootItem).toBeVisible();
|
||||
await rootItem.hover();
|
||||
const responsePromise = waitForResponseCreateDoc(page);
|
||||
await rootItem.getByTestId('doc-tree-item-actions-add-child').click();
|
||||
const response = await responsePromise;
|
||||
const { id } = (await response.json()) as { id: string };
|
||||
await page.waitForURL((url) => url.href !== currentUrl);
|
||||
await expect(docTree.getByTestId(`doc-sub-page-item-${id}`)).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
};
|
||||
|
||||
export const addChild = async ({
|
||||
|
||||
Reference in New Issue
Block a user