Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to

### Changed

- ♻️(frontend) adapt custom blocks to new implementation #1375
- ♻️(frontend) Refactor Auth component for improved redirection logic #1461
- ♻️(frontend) replace Arial font-family with token font #1411
- ♿(frontend) improve accessibility:
Expand Down Expand Up @@ -61,6 +62,10 @@ and this project adheres to
- ✨(frontend) load docs logo from public folder via url #1462
- 🔧(keycloak) Fix https required issue in dev mode #1286

## Removed

- 🔥(frontend) remove custom DividerBlock ##1375

## [3.7.0] - 2025-09-12

### Added
Expand Down
18 changes: 8 additions & 10 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,10 +676,9 @@ test.describe('Doc Editor', () => {

await calloutBlock.locator('.inline-content').fill('example text');

await expect(page.locator('.bn-block').first()).toHaveAttribute(
'data-background-color',
'yellow',
);
await expect(
page.locator('.bn-block-content[data-content-type="callout"]').first(),
).toHaveAttribute('data-background-color', 'yellow');

const emojiButton = calloutBlock.getByRole('button');
await expect(emojiButton).toHaveText('💡');
Expand All @@ -703,10 +702,9 @@ test.describe('Doc Editor', () => {
await page.locator('.mantine-Menu-dropdown > button').last().click();
await page.locator('.bn-color-picker-dropdown > button').last().click();

await expect(page.locator('.bn-block').first()).toHaveAttribute(
'data-background-color',
'pink',
);
await expect(
page.locator('.bn-block-content[data-content-type="callout"]').first(),
).toHaveAttribute('data-background-color', 'pink');
});

test('it checks interlink feature', async ({ page, browserName }) => {
Expand Down Expand Up @@ -844,10 +842,10 @@ test.describe('Doc Editor', () => {

await expect(pdfBlock).toBeVisible();

await page.getByText('Add PDF').click();
await page.getByText(/Add (PDF|file)/).click();
const fileChooserPromise = page.waitForEvent('filechooser');
const downloadPromise = page.waitForEvent('download');
await page.getByText('Upload file').click();
await page.getByText(/Upload (PDF|file)/).click();
const fileChooser = await fileChooserPromise;

await fileChooser.setFiles(path.join(__dirname, 'assets/test-pdf.pdf'));
Expand Down
69 changes: 12 additions & 57 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'path';

import { expect, test } from '@playwright/test';
import cs from 'convert-stream';
import pdf from 'pdf-parse';
import { pdf } from 'pdf-parse';

import {
TestLanguage,
Expand Down Expand Up @@ -59,20 +59,16 @@ test.describe('Doc Export', () => {

await verifyDocName(page, randomDoc);

const editor = page.locator('.ProseMirror.bn-editor');

await editor.click();
await editor.locator('.bn-block-outer').last().fill('Hello');

const editor = await writeInEditor({ page, text: 'Hello' });
await page.keyboard.press('Enter');
await editor.locator('.bn-block-outer').last().fill('/');
await openSuggestionMenu({ page });
await page.getByText('Page Break').click();

await expect(editor.locator('.bn-page-break')).toBeVisible();

await page.keyboard.press('Enter');
await expect(
editor.locator('div[data-content-type="pageBreak"]'),
).toBeVisible();

await editor.locator('.bn-block-outer').last().fill('World');
await writeInEditor({ page, text: 'World' });

await page
.getByRole('button', {
Expand All @@ -92,9 +88,11 @@ test.describe('Doc Export', () => {
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
const pdfData = await pdf(pdfBuffer);

expect(pdfData.numpages).toBe(2);
expect(pdfData.text).toContain('\n\nHello\n\nWorld'); // This is the doc text
expect(pdfData.info.Title).toBe(randomDoc);
expect(pdfData.total).toBe(2);
expect(pdfData.text).toContain('Hello\n\nWorld\n\n'); // This is the doc text
expect(
(pdfData as unknown as { info?: { Title?: string } }).info?.Title,
).toBe(randomDoc);
});

test('it exports the doc to docx', async ({ page, browserName }) => {
Expand Down Expand Up @@ -274,49 +272,6 @@ test.describe('Doc Export', () => {
expect(pdfData.text).toContain('Hello World'); // This is the pdf text
});

/**
* We cannot assert the line break is visible in the pdf, but we can assert the
* line break is visible in the editor and that the pdf is generated.
*/
test('it exports the doc with divider', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'export-divider', browserName, 1);

const editor = page.locator('.ProseMirror');
await editor.click();
await editor.fill('Hello World');

// Trigger slash menu to show menu
await editor.locator('.bn-block-outer').last().fill('/');
await page.getByText('Add a horizontal line').click();

await expect(
editor.locator('.bn-block-content[data-content-type="divider"]'),
).toBeVisible();

await page
.getByRole('button', {
name: 'Export the document',
})
.click();

await expect(
page.getByTestId('doc-open-modal-download-button'),
).toBeVisible();

const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
});

void page.getByTestId('doc-export-download-button').click();

const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);

const pdfBuffer = await cs.toBuffer(await download.createReadStream());
const pdfData = await pdf(pdfBuffer);
expect(pdfData.text).toContain('Hello World');
});

test('it exports the doc with multi columns', async ({
page,
browserName,
Expand Down
14 changes: 11 additions & 3 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
mockedDocument,
verifyDocName,
} from './utils-common';
import { writeInEditor } from './utils-editor';
import { createRootSubPage } from './utils-sub-pages';

test.describe('Doc Routing', () => {
Expand Down Expand Up @@ -58,16 +59,23 @@ test.describe('Doc Routing', () => {

await createRootSubPage(page, browserName, '401-doc-child');

await page.locator('.ProseMirror.bn-editor').fill('Hello World');
await writeInEditor({ page, text: 'Hello World' });

const responsePromise = page.route(
/.*\/documents\/.*\/$|users\/me\/$/,
async (route) => {
const request = route.request();

// When we quit a document, a PATCH request is sent to save the document.
// We intercept this request to simulate a 401 error from the backend.
// The GET request to users/me is also intercepted to simulate the user
// being logged out when trying to fetch user info.
// This way we can test the 401 error handling when saving the document
if (
request.method().includes('PATCH') ||
request.method().includes('GET')
(request.url().includes('/documents/') &&
request.method().includes('PATCH')) ||
(request.url().includes('/users/me/') &&
request.method().includes('GET'))
) {
await route.fulfill({
status: 401,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ test.describe('Doc Visibility: Restricted', () => {
await addNewMember(page, 0, 'Reader', otherBrowserName);

await otherPage.reload();
await expect(otherPage.getByText('Hello World')).toBeVisible();
await expect(otherPage.getByText('Hello World')).toBeVisible({
timeout: 10000,
});
});
});

Expand Down
14 changes: 8 additions & 6 deletions src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect, test } from '@playwright/test';

import { TestLanguage, createDoc, waitForLanguageSwitch } from './utils-common';
import { openSuggestionMenu } from './utils-editor';

test.describe('Language', () => {
test.beforeEach(async ({ page }) => {
Expand Down Expand Up @@ -51,6 +52,7 @@ test.describe('Language', () => {
await expect(page.locator('html')).toHaveAttribute('lang', 'en');
await expect(languagePicker).toContainText('English');
});

test('can switch language using only keyboard', async ({ page }) => {
await page.goto('/');
await waitForLanguageSwitch(page, TestLanguage.English);
Expand Down Expand Up @@ -106,18 +108,18 @@ test.describe('Language', () => {
}) => {
await createDoc(page, 'doc-toolbar', browserName, 1);

const editor = page.locator('.ProseMirror');

// Trigger slash menu to show english menu
await editor.click();
await editor.fill('/');
const editor = await openSuggestionMenu({ page });
await expect(page.getByText('Headings', { exact: true })).toBeVisible();

await editor.click(); // close the menu

await expect(page.getByText('Headings', { exact: true })).toBeHidden();

// Change language to French
await waitForLanguageSwitch(page, TestLanguage.French);

// Trigger slash menu to show french menu
await editor.locator('.bn-block-outer').last().fill('/');
await openSuggestionMenu({ page });
await expect(page.getByText('Titres', { exact: true })).toBeVisible();
});
});
4 changes: 2 additions & 2 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const getEditor = async ({ page }: { page: Page }) => {
export const openSuggestionMenu = async ({ page }: { page: Page }) => {
const editor = await getEditor({ page });
await editor.click();
await page.locator('.bn-block-outer').last().fill('/');
await writeInEditor({ page, text: '/' });

return editor;
};
Expand All @@ -22,6 +22,6 @@ export const writeInEditor = async ({
text: string;
}) => {
const editor = await getEditor({ page });
editor.locator('.bn-block-outer').last().fill(text);
editor.locator('.bn-block-outer .bn-inline-content').last().fill(text);
return editor;
};
4 changes: 2 additions & 2 deletions src/frontend/apps/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
"test:ui::chromium": "yarn test:ui --project=chromium"
},
"devDependencies": {
"@playwright/test": "1.55.0",
"@playwright/test": "1.55.1",
"@types/node": "*",
"@types/pdf-parse": "1.1.5",
"eslint-plugin-docs": "*",
"typescript": "*"
},
"dependencies": {
"convert-stream": "1.0.2",
"pdf-parse": "1.1.1"
"pdf-parse": "2.1.7"
},
"packageManager": "[email protected]"
}
57 changes: 30 additions & 27 deletions src/frontend/apps/impress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,46 +19,49 @@
},
"dependencies": {
"@ag-media/react-pdf-table": "2.0.3",
"@blocknote/code-block": "0.37.0",
"@blocknote/core": "0.37.0",
"@blocknote/mantine": "0.37.0",
"@blocknote/react": "0.37.0",
"@blocknote/xl-docx-exporter": "0.37.0",
"@blocknote/xl-multi-column": "0.37.0",
"@blocknote/xl-pdf-exporter": "0.37.0",
"@blocknote/code-block": "0.41.1",
"@blocknote/core": "0.41.1",
"@blocknote/mantine": "0.41.1",
"@blocknote/react": "0.41.1",
"@blocknote/xl-docx-exporter": "0.41.1",
"@blocknote/xl-multi-column": "0.41.1",
"@blocknote/xl-pdf-exporter": "0.41.1",
"@dnd-kit/core": "6.3.1",
"@dnd-kit/modifiers": "9.0.0",
"@emoji-mart/data": "1.2.1",
"@emoji-mart/react": "1.1.1",
"@fontsource-variable/inter": "5.2.8",
"@fontsource-variable/material-symbols-outlined": "5.2.25",
"@fontsource/material-icons": "5.2.5",
"@fontsource/material-icons": "5.2.7",
"@gouvfr-lasuite/integration": "1.0.3",
"@gouvfr-lasuite/ui-kit": "0.16.1",
"@gouvfr-lasuite/ui-kit": "0.16.2",
"@hocuspocus/provider": "2.15.2",
"@mantine/core": "8.3.4",
"@mantine/hooks": "8.3.4",
"@openfun/cunningham-react": "3.2.3",
"@react-pdf/renderer": "4.3.0",
"@sentry/nextjs": "10.11.0",
"@tanstack/react-query": "5.87.4",
"@react-pdf/renderer": "4.3.1",
"@sentry/nextjs": "10.17.0",
"@tanstack/react-query": "5.90.2",
"@tiptap/extensions": "3.4.4",
"canvg": "4.0.3",
"clsx": "2.1.1",
"cmdk": "1.1.1",
"crisp-sdk-web": "1.0.25",
"docx": "9.5.0",
"docx": "*",
"emoji-datasource-apple": "16.0.0",
"emoji-mart": "5.6.0",
"emoji-regex": "10.5.0",
"i18next": "25.5.2",
"i18next": "25.5.3",
"i18next-browser-languagedetector": "8.2.0",
"idb": "8.0.3",
"lodash": "4.17.21",
"luxon": "3.7.2",
"next": "15.5.3",
"posthog-js": "1.264.2",
"next": "15.5.4",
"posthog-js": "1.271.0",
"react": "*",
"react-aria-components": "1.12.1",
"react-aria-components": "1.13.0",
"react-dom": "*",
"react-i18next": "15.7.3",
"react-i18next": "16.0.0",
"react-intersection-observer": "9.16.0",
"react-select": "5.10.2",
"styled-components": "6.1.19",
Expand All @@ -69,32 +72,32 @@
},
"devDependencies": {
"@svgr/webpack": "8.1.0",
"@tanstack/react-query-devtools": "5.87.4",
"@tanstack/react-query-devtools": "5.90.2",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.8.0",
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "16.3.0",
"@testing-library/user-event": "14.6.1",
"@types/lodash": "4.17.20",
"@types/luxon": "3.7.1",
"@types/node": "*",
"@types/react": "*",
"@types/react-dom": "*",
"@vitejs/plugin-react": "5.0.2",
"@vitejs/plugin-react": "5.0.4",
"copy-webpack-plugin": "13.0.1",
"cross-env": "10.0.0",
"dotenv": "17.2.2",
"cross-env": "10.1.0",
"dotenv": "17.2.3",
"eslint-plugin-docs": "*",
"fetch-mock": "9.11.0",
"jsdom": "26.1.0",
"jsdom": "27.0.0",
"node-fetch": "2.7.0",
"prettier": "3.6.2",
"stylelint": "16.24.0",
"stylelint-config-standard": "39.0.0",
"stylelint": "16.25.0",
"stylelint-config-standard": "39.0.1",
"stylelint-prettier": "5.0.3",
"typescript": "*",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4",
"webpack": "5.101.3",
"webpack": "5.102.0",
"workbox-webpack-plugin": "7.1.0"
},
"packageManager": "[email protected]"
Expand Down
Loading
Loading