♻️(frontend) adapt custom blocks to new implementation

Last release of Blocknote introduced breaking
changes for custom blocks.
We adapted our custom blocks to the new
implementation.
"code-block" is considered as a block now, we
update the way to import and use it.
The custom blocks should be now more tiptap friendly.
This commit is contained in:
Anthony LC
2025-10-16 12:10:05 +02:00
parent aca334f81f
commit fe24c00178
30 changed files with 1720 additions and 3066 deletions

View File

@@ -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('💡');
@@ -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 }) => {
@@ -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'));

View File

@@ -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,
@@ -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 expect(
editor.locator('div[data-content-type="pageBreak"]'),
).toBeVisible();
await page.keyboard.press('Enter');
await editor.locator('.bn-block-outer').last().fill('World');
await writeInEditor({ page, text: 'World' });
await page
.getByRole('button', {
@@ -92,9 +88,9 @@ 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.info?.Title).toBe(randomDoc);
});
test('it exports the doc to docx', async ({ page, browserName }) => {

View File

@@ -7,6 +7,7 @@ import {
randomName,
verifyDocName,
} from './utils-common';
import { writeInEditor } from './utils-editor';
import { connectOtherUserToDoc, updateRoleUser } from './utils-share';
import { createRootSubPage } from './utils-sub-pages';
@@ -240,11 +241,7 @@ test.describe('Document create member', () => {
await verifyDocName(page, docTitle);
await page
.locator('.ProseMirror')
.locator('.bn-block-outer')
.last()
.fill('Hello World');
await writeInEditor({ page, text: 'Hello World' });
const docUrl = page.url();

View File

@@ -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', () => {
@@ -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,

View File

@@ -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,
});
});
});

View File

@@ -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 }) => {
@@ -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);
@@ -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();
});
});

View File

@@ -0,0 +1,37 @@
/**
* Type definitions for pdf-parse library
* The library doesn't export complete type definitions for the parsed PDF data
*/
declare module 'pdf-parse' {
export interface PdfInfo {
Title?: string;
Author?: string;
Subject?: string;
Keywords?: string;
Creator?: string;
Producer?: string;
CreationDate?: string;
ModDate?: string;
[key: string]: unknown;
}
export interface PdfData {
/** Total number of pages */
numpages: number;
/** Alias for numpages */
total?: number;
/** Extracted text content from the PDF */
text: string;
/** PDF metadata information */
info?: PdfInfo;
/** PDF metadata (alternative structure) */
metadata?: unknown;
/** PDF version */
version?: string;
}
export function pdf(buffer: Buffer): Promise<PdfData>;
export default pdf;
}

View File

@@ -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;
};
@@ -22,6 +22,6 @@ export const writeInEditor = async ({
text: string;
}) => {
const editor = await getEditor({ page });
await editor.locator('.bn-block-outer').last().fill(text);
await editor.locator('.bn-block-outer .bn-inline-content').last().fill(text);
return editor;
};