diff --git a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts
index e7574fabb0aa8..f35cf19ec1bba 100644
--- a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts
+++ b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts
@@ -865,68 +865,6 @@ describe('getBlock', () => {
});
});
-// Inline snapshot is not supported under describe.parallel config
-describe('collection.exportJSX works', () => {
- it('collection matches snapshot', () => {
- const options = createTestOptions();
- const collection = new DocCollection(options);
- collection.meta.initialize();
- const doc = collection.createDoc({ id: 'doc:home' });
-
- doc.addBlock('affine:page', { title: new doc.Text('hello') });
-
- expect(collection.exportJSX()).toMatchInlineSnapshot(`
-
- `);
- });
-
- it('empty collection matches snapshot', () => {
- const options = createTestOptions();
- const collection = new DocCollection(options);
- collection.meta.initialize();
- collection.createDoc({ id: 'doc:home' });
-
- expect(collection.exportJSX()).toMatchInlineSnapshot('null');
- });
-
- it('collection with multiple blocks children matches snapshot', () => {
- const options = createTestOptions();
- const collection = new DocCollection(options);
- collection.meta.initialize();
- const doc = collection.createDoc({ id: 'doc:home' });
- doc.load(() => {
- const rootId = doc.addBlock('affine:page', {
- title: new doc.Text(),
- });
- const noteId = doc.addBlock('affine:note', {}, rootId);
- doc.addBlock('affine:paragraph', {}, noteId);
- doc.addBlock('affine:paragraph', {}, noteId);
- });
-
- expect(collection.exportJSX()).toMatchInlineSnapshot(/* xml */ `
-
-
-
-
-
-
- `);
- });
-});
-
describe('flags', () => {
it('update flags', () => {
const options = createTestOptions();
diff --git a/blocksuite/framework/store/src/__tests__/jsx.unit.spec.ts b/blocksuite/framework/store/src/__tests__/jsx.unit.spec.ts
deleted file mode 100644
index 78818f2806a0e..0000000000000
--- a/blocksuite/framework/store/src/__tests__/jsx.unit.spec.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-// checkout https://vitest.dev/guide/debugging.html for debugging tests
-
-import { describe, expect, it } from 'vitest';
-
-import { yDocToJSXNode } from '../utils/jsx.js';
-
-describe('basic', () => {
- it('serialized doc match snapshot', () => {
- expect(
- yDocToJSXNode(
- {
- '0': {
- 'sys:id': '0',
- 'sys:children': ['1'],
- 'sys:flavour': 'affine:page',
- },
- '1': {
- 'sys:id': '1',
- 'sys:children': [],
- 'sys:flavour': 'affine:paragraph',
- 'prop:text': [],
- 'prop:type': 'text',
- },
- },
- '0'
- )
- ).toMatchInlineSnapshot(`
-
-
-
- `);
- });
-
- it('block with plain text should match snapshot', () => {
- expect(
- yDocToJSXNode(
- {
- '0': {
- 'sys:id': '0',
- 'sys:flavour': 'affine:page',
- 'sys:children': ['1'],
- 'prop:title': 'this is title',
- },
- '1': {
- 'sys:id': '2',
- 'sys:flavour': 'affine:paragraph',
- 'sys:children': [],
- 'prop:type': 'text',
- 'prop:text': [{ insert: 'just plain text' }],
- },
- },
- '0'
- )
- ).toMatchInlineSnapshot(`
-
-
-
- `);
- });
-
- it('doc record match snapshot', () => {
- expect(
- yDocToJSXNode(
- {
- '0': {
- 'sys:id': '0',
- 'sys:flavour': 'affine:page',
- 'sys:children': ['1'],
- 'prop:title': 'this is title',
- },
- '1': {
- 'sys:id': '2',
- 'sys:flavour': 'affine:paragraph',
- 'sys:children': [],
- 'prop:type': 'text',
- 'prop:text': [
- { insert: 'this is ' },
- {
- insert: 'a ',
- attributes: { link: 'http://www.example.com' },
- },
- {
- insert: 'link',
- attributes: { link: 'http://www.example.com', bold: true },
- },
- { insert: ' with', attributes: { bold: true } },
- { insert: ' bold' },
- ],
- },
- },
- '0'
- )
- ).toMatchInlineSnapshot(`
-
-
-
-
-
-
-
- >
- }
- prop:type="text"
- />
-
- `);
- });
-});
diff --git a/blocksuite/framework/store/src/store/addon/index.ts b/blocksuite/framework/store/src/store/addon/index.ts
deleted file mode 100644
index 84e7ac652cff1..0000000000000
--- a/blocksuite/framework/store/src/store/addon/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { test } from './test.js';
-export { DocCollectionAddonType } from './type.js';
diff --git a/blocksuite/framework/store/src/store/addon/shared.ts b/blocksuite/framework/store/src/store/addon/shared.ts
deleted file mode 100644
index c5bfec474400e..0000000000000
--- a/blocksuite/framework/store/src/store/addon/shared.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { DocCollection, DocCollectionOptions } from '../collection.js';
-
-type DocCollectionConstructor = {
- new (storeOptions: DocCollectionOptions): Omit;
-};
-
-export type AddOn = (
- originalClass: DocCollectionConstructor,
- context: ClassDecoratorContext
-) => { new (storeOptions: DocCollectionOptions): unknown };
-
-export type AddOnReturn = (
- originalClass: DocCollectionConstructor,
- context: ClassDecoratorContext
-) => typeof DocCollection;
-
-export function addOnFactory(fn: AddOn) {
- return fn as AddOnReturn;
-}
diff --git a/blocksuite/framework/store/src/store/addon/test.ts b/blocksuite/framework/store/src/store/addon/test.ts
deleted file mode 100644
index cc3a8c486d0ba..0000000000000
--- a/blocksuite/framework/store/src/store/addon/test.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { assertExists } from '@blocksuite/global/utils';
-
-import type { JSXElement } from '../../utils/jsx.js';
-import { serializeYDoc, yDocToJSXNode } from '../../utils/jsx.js';
-import { addOnFactory } from './shared.js';
-
-export interface TestAddon {
- importDocSnapshot: (json: unknown, docId: string) => Promise;
- exportJSX: (blockId?: string, docId?: string) => JSXElement;
-}
-
-export const test = addOnFactory(
- originalClass =>
- class extends originalClass {
- /** @internal Only for testing */
- exportJSX(blockId?: string, docId = this.meta.docMetas.at(0)?.id) {
- assertExists(docId);
- const doc = this.doc.spaces.get(docId);
- assertExists(doc);
- const docJson = serializeYDoc(doc);
- if (!docJson) {
- throw new Error(`Doc ${docId} doesn't exist`);
- }
- const blockJson = docJson.blocks as Record;
- if (!blockId) {
- const rootId = Object.keys(blockJson).at(0);
- if (!rootId) {
- return null;
- }
- blockId = rootId;
- }
- if (!blockJson[blockId]) {
- return null;
- }
- return yDocToJSXNode(blockJson, blockId);
- }
- }
-);
diff --git a/blocksuite/framework/store/src/store/addon/type.ts b/blocksuite/framework/store/src/store/addon/type.ts
deleted file mode 100644
index d6d12553bd004..0000000000000
--- a/blocksuite/framework/store/src/store/addon/type.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { TestAddon } from './test.js';
-
-export class DocCollectionAddonType implements TestAddon {
- exportJSX!: TestAddon['exportJSX'];
-
- importDocSnapshot!: TestAddon['importDocSnapshot'];
-}
diff --git a/blocksuite/framework/store/src/store/collection.ts b/blocksuite/framework/store/src/store/collection.ts
index a5c86f37463b3..d37e89a17c132 100644
--- a/blocksuite/framework/store/src/store/collection.ts
+++ b/blocksuite/framework/store/src/store/collection.ts
@@ -23,7 +23,6 @@ import {
BlockSuiteDoc,
type RawAwarenessState,
} from '../yjs/index.js';
-import { DocCollectionAddonType, test } from './addon/index.js';
import { BlockCollection, type GetDocOptions } from './doc/block-collection.js';
import type { Doc, Query } from './doc/index.js';
import type { IdGeneratorType } from './id.js';
@@ -73,10 +72,7 @@ export interface StackItem {
meta: Map<'cursor-location' | 'selection-state', unknown>;
}
-// oxlint-disable-next-line
-// @ts-ignore FIXME: typecheck error
-@test
-export class DocCollection extends DocCollectionAddonType {
+export class DocCollection {
static Y = Y;
protected readonly _schema: Schema;
@@ -142,7 +138,6 @@ export class DocCollection extends DocCollectionAddonType {
},
logger = new NoopLogger(),
}: DocCollectionOptions) {
- super();
this._schema = schema;
this.id = id || '';
diff --git a/blocksuite/framework/store/src/utils/formatter.ts b/blocksuite/framework/store/src/utils/formatter.ts
deleted file mode 100644
index c96219862cefe..0000000000000
--- a/blocksuite/framework/store/src/utils/formatter.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { BlockModel } from '../schema/base.js';
-
-function isBlockModel(a: unknown): a is BlockModel {
- return a instanceof BlockModel;
-}
-
-/**
- * Ported from https://github.com/vuejs/core/blob/main/packages/runtime-core/src/customFormatter.ts
- *
- * See [Custom Object Formatters in Chrome DevTools](https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U)
- */
-function initCustomFormatter() {
- if (
- !(process.env.NODE_ENV === 'development') ||
- typeof window === 'undefined'
- ) {
- return;
- }
-
- const bannerStyle = {
- style:
- 'color: #eee; background: #3F6FDB; margin-right: 5px; padding: 2px; border-radius: 4px',
- };
- const typeStyle = {
- style:
- 'color: #eee; background: #DB6D56; margin-right: 5px; padding: 2px; border-radius: 4px',
- };
-
- // custom formatter for Chrome
- // https://www.mattzeunert.com/2016/02/19/custom-chrome-devtools-object-formatters.html
- const formatter = {
- header(obj: unknown, config = { expand: false }) {
- if (!isBlockModel(obj) || config.expand) {
- return null;
- }
- if (obj.text) {
- return [
- 'div',
- {},
- ['span', bannerStyle, obj.constructor.name],
- ['span', typeStyle, obj.flavour],
- obj.text.toString(),
- ];
- }
-
- return [
- 'div',
- {},
- ['span', bannerStyle, obj.constructor.name],
- ['span', typeStyle, obj.flavour],
- ];
- },
- hasBody() {
- return true;
- },
- body(obj: unknown) {
- return ['object', { object: obj, config: { expand: true } }];
- },
- };
-
- if ((window as any).devtoolsFormatters) {
- (window as any).devtoolsFormatters.push(formatter);
- } else {
- (window as any).devtoolsFormatters = [formatter];
- }
-}
-
-initCustomFormatter();
diff --git a/blocksuite/framework/store/src/utils/jsx.ts b/blocksuite/framework/store/src/utils/jsx.ts
deleted file mode 100644
index c969e50817c1b..0000000000000
--- a/blocksuite/framework/store/src/utils/jsx.ts
+++ /dev/null
@@ -1,165 +0,0 @@
-import * as Y from 'yjs';
-
-type DocRecord = Record<
- string,
- {
- 'sys:id': string;
- 'sys:flavour': string;
- 'sys:children': string[];
- [id: string]: unknown;
- }
->;
-
-export interface JSXElement {
- // Ad-hoc for `ReactTestComponent` identify.
- // Use ReactTestComponent serializer prevent snapshot be be wrapped in a string, which cases " to be escaped.
- // See https://github.com/facebook/jest/blob/f1263368cc85c3f8b70eaba534ddf593392c44f3/packages/pretty-format/src/plugins/ReactTestComponent.ts#L78-L79
- $$typeof: symbol | 0xea71357;
- type: string;
- props: { 'prop:text'?: string | JSXElement } & Record;
- children?: null | (JSXElement | string | number)[];
-}
-
-// Ad-hoc for `ReactTestComponent` identify.
-// See https://github.com/facebook/jest/blob/f1263368cc85c3f8b70eaba534ddf593392c44f3/packages/pretty-format/src/plugins/ReactTestComponent.ts#L26-L29
-const testSymbol = Symbol.for('react.test.json');
-
-function isValidRecord(data: unknown): data is DocRecord {
- if (typeof data !== 'object' || data === null) {
- return false;
- }
- // TODO enhance this check
- return true;
-}
-
-const IGNORED_PROPS = new Set([
- 'sys:id',
- 'sys:version',
- 'sys:flavour',
- 'sys:children',
- 'prop:xywh',
- 'prop:cells',
- 'prop:elements',
-]);
-
-export function yDocToJSXNode(
- serializedDoc: Record,
- nodeId: string
-): JSXElement {
- if (!isValidRecord(serializedDoc)) {
- throw new Error('Failed to parse doc record! Invalid data.');
- }
- const node = serializedDoc[nodeId];
- if (!node) {
- throw new Error(
- `Failed to parse doc record! Node not found! id: ${nodeId}.`
- );
- }
- // TODO maybe need set PascalCase
- const flavour = node['sys:flavour'];
- // TODO maybe need check children recursively nested
- const children = node['sys:children'];
- const props = Object.fromEntries(
- Object.entries(node).filter(([key]) => !IGNORED_PROPS.has(key))
- );
-
- if ('prop:text' in props && props['prop:text'] instanceof Array) {
- props['prop:text'] = parseDelta(props['prop:text'] as DeltaText);
- }
-
- if ('prop:title' in props && props['prop:title'] instanceof Array) {
- props['prop:title'] = parseDelta(props['prop:title'] as DeltaText);
- }
-
- if ('prop:columns' in props && props['prop:columns'] instanceof Array) {
- props['prop:columns'] = `Array [${props['prop:columns'].length}]`;
- }
-
- if ('prop:views' in props && props['prop:views'] instanceof Array) {
- props['prop:views'] = `Array [${props['prop:views'].length}]`;
- }
-
- return {
- $$typeof: testSymbol,
- type: flavour,
- props,
- children: children?.map(id => yDocToJSXNode(serializedDoc, id)) ?? [],
- };
-}
-
-export function serializeYDoc(doc: Y.Doc) {
- const json: Record = {};
- doc.share.forEach((value, key) => {
- if (value instanceof Y.Map) {
- json[key] = serializeYMap(value);
- } else {
- json[key] = value.toJSON();
- }
- });
- return json;
-}
-
-function serializeY(value: unknown): unknown {
- if (value instanceof Y.Doc) {
- return serializeYDoc(value);
- }
- if (value instanceof Y.Map) {
- return serializeYMap(value);
- }
- if (value instanceof Y.Text) {
- return serializeYText(value);
- }
- if (value instanceof Y.Array) {
- return value.toArray().map(x => serializeY(x));
- }
- if (value instanceof Y.AbstractType) {
- return value.toJSON();
- }
- return value;
-}
-
-function serializeYMap(map: Y.Map) {
- const json: Record = {};
- map.forEach((value, key) => {
- json[key] = serializeY(value);
- });
- return json;
-}
-
-type DeltaText = {
- insert: string;
- attributes?: Record;
-}[];
-
-function serializeYText(text: Y.Text): DeltaText {
- const delta = text.toDelta();
- return delta;
-}
-
-function parseDelta(text: DeltaText) {
- if (!text.length) {
- return undefined;
- }
- if (text.length === 1 && !text[0].attributes) {
- // just plain text
- return text[0].insert;
- }
- return {
- // The `Symbol.for('react.fragment')` will render as ``
- // so we use a empty string to render it as `<>`.
- // But it will empty children ad `< />`
- // so we return `undefined` directly if not delta text.
- $$typeof: testSymbol, // Symbol.for('react.element'),
- type: '', // Symbol.for('react.fragment'),
- props: {},
- children: text?.map(({ insert, attributes }) => ({
- $$typeof: testSymbol,
- type: 'text',
- props: {
- // Not place at `children` to avoid the trailing whitespace be trim by formatter.
- insert,
- ...attributes,
- },
- })),
- };
-}
diff --git a/blocksuite/presets/src/__tests__/main/snapshot.spec.ts b/blocksuite/presets/src/__tests__/main/snapshot.spec.ts
index f286c8c0e8b99..f2eeeb559850a 100644
--- a/blocksuite/presets/src/__tests__/main/snapshot.spec.ts
+++ b/blocksuite/presets/src/__tests__/main/snapshot.spec.ts
@@ -21,6 +21,8 @@ const fieldChecker: Record boolean> = {
},
};
+const skipFields = new Set(['_lastXYWH']);
+
const snapshotTest = async (snapshotUrl: string, elementsCount: number) => {
const pageService = window.editor.host!.std.getService('affine:page');
if (!pageService) {
@@ -66,17 +68,22 @@ const snapshotTest = async (snapshotUrl: string, elementsCount: number) => {
return;
}
+ if (skipFields.has(field)) {
+ return;
+ }
+
if (fieldChecker[typeField] || fieldChecker[field]) {
const checker = fieldChecker[typeField] || fieldChecker[field];
expect(checker(value)).toBe(true);
- } else {
- expect(
- value,
- `type: ${element.type} field: "${field}"`
- ).not.toBeUndefined();
- expect(value, `type: ${element.type} field: "${field}"`).not.toBeNull();
- expect(value, `type: ${element.type} field: "${field}"`).not.toBeNaN();
+ return;
}
+
+ expect(
+ value,
+ `type: ${element.type} field: "${field}"`
+ ).not.toBeUndefined();
+ expect(value, `type: ${element.type} field: "${field}"`).not.toBeNull();
+ expect(value, `type: ${element.type} field: "${field}"`).not.toBeNaN();
}
});
};
@@ -89,13 +96,11 @@ beforeEach(async () => {
const xywhPattern = /\[(\s*-?\d+(\.\d+)?\s*,){3}(\s*-?\d+(\.\d+)?\s*)\]/;
-// FIXME: snapshot tests
-test.skip('snapshot 1 importing', async () => {
+test('snapshot 1 importing', async () => {
await snapshotTest('https://test.affineassets.com/test-snapshot-1.zip', 25);
});
-// FIXME: snapshot tests
-test.skip('snapshot 2 importing', async () => {
+test('snapshot 2 importing', async () => {
await snapshotTest(
'https://test.affineassets.com/test-snapshot-2%20(onboarding).zip',
174
diff --git a/blocksuite/tests-legacy/attachment.spec.ts b/blocksuite/tests-legacy/attachment.spec.ts
index 8472e68adae22..cb8aab31dbb36 100644
--- a/blocksuite/tests-legacy/attachment.spec.ts
+++ b/blocksuite/tests-legacy/attachment.spec.ts
@@ -1,3 +1,6 @@
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
import { sleep } from '@blocksuite/global/utils';
import { expect, type Page } from '@playwright/test';
import { switchEditorMode } from 'utils/actions/edgeless.js';
@@ -20,6 +23,7 @@ import {
captureHistory,
enterPlaygroundRoom,
focusRichText,
+ getPageSnapshot,
initEmptyEdgelessState,
initEmptyParagraphState,
resetHistory,
@@ -34,14 +38,12 @@ import {
assertParentBlockFlavour,
assertRichImage,
assertRichTextInlineRange,
- assertStoreMatchJSX,
} from './utils/asserts.js';
import { test } from './utils/playwright.js';
const FILE_NAME = 'test-card-1.png';
-const FILE_PATH = `../playground/public/${FILE_NAME}`;
-const FILE_ID = 'ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA=';
-const FILE_SIZE = 45801;
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const FILE_PATH = path.resolve(__dirname, `../playground/public/${FILE_NAME}`);
function getAttachment(page: Page) {
const attachment = page.locator('affine-attachment');
@@ -124,9 +126,9 @@ function getAttachment(page: Page) {
};
}
-test('can insert attachment from slash menu', async ({ page }) => {
+test('can insert attachment from slash menu', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { noteId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
const { insertAttachment, waitLoading, getName, getSize } =
getAttachment(page);
@@ -140,50 +142,14 @@ test('can insert attachment from slash menu', async ({ page }) => {
expect(await getName()).toBe(FILE_NAME);
expect(await getSize()).toBe('45.8 kB');
- await assertStoreMatchJSX(
- page,
- `
-
-
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
-test('should undo/redo works for attachment', async ({ page }) => {
+test('should undo/redo works for attachment', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { noteId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
const { insertAttachment, waitLoading } = getAttachment(page);
@@ -193,122 +159,24 @@ test('should undo/redo works for attachment', async ({ page }) => {
// Wait for the attachment to be uploaded
await waitLoading();
- await assertStoreMatchJSX(
- page,
- `
-
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await undoByKeyboard(page);
await waitNextFrame(page);
+
// The loading/error state should not be restored after undo
- await assertStoreMatchJSX(
- page,
- `
-
-
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
await redoByKeyboard(page);
await waitNextFrame(page);
- await assertStoreMatchJSX(
- page,
- `
-
-
-`,
- noteId
+
+ // The loading/error state should not be restored after undo
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_3.json`
);
});
@@ -351,9 +219,9 @@ test('should rename attachment works', async ({ page }) => {
expect(await getName()).toBe('abc');
});
-test('should turn attachment to image works', async ({ page }) => {
+test('should turn attachment to image works', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { noteId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
const { insertAttachment, waitLoading, turnToEmbed, turnImageToCard } =
getAttachment(page);
@@ -364,90 +232,18 @@ test('should turn attachment to image works', async ({ page }) => {
await turnToEmbed();
- await assertStoreMatchJSX(
- page,
- `
-
-
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await turnImageToCard();
- await assertStoreMatchJSX(
- page,
- `
-
-
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
});
-test('should attachment can be deleted', async ({ page }) => {
+test('should attachment can be deleted', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { noteId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
const { attachment, insertAttachment, waitLoading } = getAttachment(page);
await focusRichText(page);
@@ -457,38 +253,16 @@ test('should attachment can be deleted', async ({ page }) => {
await attachment.click();
await pressBackspace(page);
- await assertStoreMatchJSX(
- page,
- `
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
-test.fixme(`support dragging attachment block directly`, async ({ page }) => {
+test(`support dragging attachment block directly`, async ({
+ page,
+}, testInfo) => {
await enterPlaygroundRoom(page);
- const { noteId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
const { insertAttachment, waitLoading, getName, getSize } =
getAttachment(page);
@@ -502,43 +276,8 @@ test.fixme(`support dragging attachment block directly`, async ({ page }) => {
expect(await getName()).toBe(FILE_NAME);
expect(await getSize()).toBe('45.8 kB');
- await assertStoreMatchJSX(
- page,
- `
-
-`,
- noteId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
const attachmentBlock = page.locator('affine-attachment');
@@ -562,58 +301,8 @@ test.fixme(`support dragging attachment block directly`, async ({ page }) => {
await page.waitForTimeout(200);
await page.waitForTimeout(200);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-
-
-
-
-
-
-`
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
// drag bookmark block
@@ -624,59 +313,8 @@ test.fixme(`support dragging attachment block directly`, async ({ page }) => {
const rects = page.locator('affine-block-selection').locator('visible=true');
await expect(rects).toHaveCount(1);
-
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-
-
-
-
-
-
-`
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_3.json`
);
});
diff --git a/blocksuite/tests-legacy/clipboard/list.spec.ts b/blocksuite/tests-legacy/clipboard/list.spec.ts
index bb1e526c0cfe1..9abb4092e3f75 100644
--- a/blocksuite/tests-legacy/clipboard/list.spec.ts
+++ b/blocksuite/tests-legacy/clipboard/list.spec.ts
@@ -1,4 +1,5 @@
import { expect } from '@playwright/test';
+import type { BlockSnapshot } from '@store/index.js';
import { lightThemeV2 } from '@toeverything/theme/v2';
import { initDatabaseColumn } from '../database/actions.js';
@@ -53,7 +54,6 @@ import {
assertExists,
assertRichTextModelType,
assertRichTexts,
- assertStoreMatchJSX,
assertText,
} from '../utils/asserts.js';
import { scoped, test } from '../utils/playwright.js';
@@ -437,104 +437,17 @@ test(scoped`should copy and paste of database work`, async ({ page }) => {
await pasteByKeyboard(page);
await page.waitForTimeout(100);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-
-
-
-
-
-
-
-
-
-
-`
- );
+ let pageJson = await getPageSnapshot(page, false);
+ let note = (pageJson as BlockSnapshot).children[0];
+ const database = note.children[0];
+ expect(database.flavour).toBe('affine:database');
await undoByKeyboard(page);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-
-
-
-
-
-
-
-`
- );
+
+ pageJson = await getPageSnapshot(page, false);
+ note = (pageJson as BlockSnapshot).children[0];
+ const db = note.children.find(child => child.flavour === 'affine:database');
+ expect(db).toBeDefined();
});
test(`copy canvas element and text note in edgeless mode`, async ({ page }) => {
diff --git a/blocksuite/tests-legacy/code/crud.spec.ts b/blocksuite/tests-legacy/code/crud.spec.ts
index fc8cc5a5a04a9..96693391733e6 100644
--- a/blocksuite/tests-legacy/code/crud.spec.ts
+++ b/blocksuite/tests-legacy/code/crud.spec.ts
@@ -29,7 +29,6 @@ import {
import {
assertBlockCount,
assertRichTexts,
- assertStoreMatchJSX,
assertTitle,
} from '../utils/asserts.js';
import { test } from '../utils/playwright.js';
@@ -150,9 +149,9 @@ test('use shortcut can create code block', async ({ page }) => {
await expect(locator).toBeVisible();
});
-test('change code language can work', async ({ page }) => {
+test('change code language can work', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { codeBlockId } = await initEmptyCodeBlockState(page);
+ await initEmptyCodeBlockState(page);
await focusRichText(page);
const codeBlockController = getCodeBlock(page);
@@ -170,26 +169,12 @@ test('change code language can work', async ({ page }) => {
await codeBlockController.codeBlock.hover();
await expect(codeBlockController.languageButton).toHaveText('Rust');
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await undoByKeyboard(page);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
// Can switch to another language
@@ -273,54 +258,33 @@ test('undo and redo works in code block', async ({ page }) => {
await assertRichTexts(page, ['const a = 10;']);
});
-test('toggle code block wrap can work', async ({ page }) => {
+test('toggle code block wrap can work', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { codeBlockId } = await initEmptyCodeBlockState(page);
+ await initEmptyCodeBlockState(page);
const codeBlockController = getCodeBlock(page);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await codeBlockController.codeBlock.hover();
await (await codeBlockController.openMore()).wrapButton.click();
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
await codeBlockController.codeBlock.hover();
await (await codeBlockController.openMore()).cancelWrapButton.click();
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_3.json`
);
});
-test('add caption works', async ({ page }) => {
+test('add caption works', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { codeBlockId } = await initEmptyCodeBlockState(page);
+ await initEmptyCodeBlockState(page);
const codeBlockController = getCodeBlock(page);
await codeBlockController.codeBlock.hover();
@@ -329,59 +293,31 @@ test('add caption works', async ({ page }) => {
await pressEnter(page);
await waitNextFrame(page, 100);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
-test('undo code block wrap can work', async ({ page }) => {
+test('undo code block wrap can work', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { codeBlockId } = await initEmptyCodeBlockState(page);
+ await initEmptyCodeBlockState(page);
await focusRichText(page);
const codeBlockController = getCodeBlock(page);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await codeBlockController.codeBlock.hover();
await (await codeBlockController.openMore()).wrapButton.click();
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
await focusRichText(page);
await undoByKeyboard(page);
- await assertStoreMatchJSX(
- page,
- /*xml*/ `
-`,
- codeBlockId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_3.json`
);
});
diff --git a/blocksuite/tests-legacy/link.spec.ts b/blocksuite/tests-legacy/link.spec.ts
index 568a3eb8aa7c1..54741227a671d 100644
--- a/blocksuite/tests-legacy/link.spec.ts
+++ b/blocksuite/tests-legacy/link.spec.ts
@@ -20,10 +20,7 @@ import {
type,
waitNextFrame,
} from './utils/actions/index.js';
-import {
- assertKeyboardWorkInInput,
- assertStoreMatchJSX,
-} from './utils/asserts.js';
+import { assertKeyboardWorkInInput } from './utils/asserts.js';
import { test } from './utils/playwright.js';
const pressCreateLinkShortCut = async (page: Page) => {
@@ -146,63 +143,26 @@ async function createLinkBlock(page: Page, str: string, link: string) {
test('type character in link should not jump out link node', async ({
page,
-}) => {
+}, testInfo) => {
await enterPlaygroundRoom(page);
- const id = await createLinkBlock(page, 'link text', 'http://example.com');
+ await createLinkBlock(page, 'link text', 'http://example.com');
await focusRichText(page, 0);
await page.keyboard.press('ArrowLeft');
await type(page, 'IN_LINK');
- await assertStoreMatchJSX(
- page,
- `
-
-
-
- >
- }
- prop:type="text"
-/>`,
- id
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
test('type character after link should not extend the link attributes', async ({
page,
-}) => {
+}, testInfo) => {
await enterPlaygroundRoom(page);
- const id = await createLinkBlock(page, 'link text', 'http://example.com');
+ await createLinkBlock(page, 'link text', 'http://example.com');
await focusRichText(page, 0);
await type(page, 'AFTER_LINK');
- await assertStoreMatchJSX(
- page,
- `
-
-
-
-
- >
- }
- prop:type="text"
-/>`,
- id
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
@@ -237,11 +197,11 @@ test('readonly mode should not trigger link popup', async ({ page }) => {
await expect(linkPopoverInput).not.toBeVisible();
});
-test('should mock selection not stored', async ({ page }) => {
+test('should mock selection not stored', async ({ page }, testInfo) => {
const linkText = 'linkText';
const link = 'http://example.com';
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, linkText);
@@ -254,15 +214,8 @@ test('should mock selection not stored', async ({ page }) => {
await expect(mockSelectNode).toBeVisible();
// the mock select node should not be stored in the Y doc
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
await type(page, link);
@@ -346,9 +299,9 @@ test('link bar should not be appear when the range is collapsed', async ({
await expect(linkPopoverLocator).toBeVisible();
});
-test('create link with paste', async ({ page }) => {
+test('create link with paste', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, 'aaa');
@@ -375,22 +328,8 @@ test('create link with paste', async ({ page }) => {
await expect(confirmBtn).not.toHaveAttribute('disabled');
await pressEnter(page);
await expect(createLinkPopoverLocator).not.toBeVisible();
- await assertStoreMatchJSX(
- page,
- `
-
-
- >
- }
- prop:type="text"
-/>`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
@@ -447,8 +386,7 @@ test('convert link to card', async ({ page }, testInfo) => {
await expect(linkToEmbedBtn).not.toBeVisible();
});
-//TODO: wait for embed block completed
-test.skip('convert link to embed', async ({ page }) => {
+test('convert link to embed', async ({ page }, testInfo) => {
const linkText = 'alinkTexta';
const link = 'https://www.youtube.com/watch?v=U6s2pdxebSo';
await enterPlaygroundRoom(page);
@@ -471,73 +409,13 @@ test.skip('convert link to embed', async ({ page }) => {
await expect(linkPopoverLocator).not.toBeVisible();
await focusRichText(page);
- await assertStoreMatchJSX(
- page,
- `
-
-
-
-
-
-
-
- >
- }
- prop:type="text"
- />
-
-`
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
- const linkToCardBtn = page.getByTestId('link-to-card');
- const linkToEmbedBtn = page.getByTestId('link-to-embed');
const linkLocator = page.locator('affine-link a');
await linkLocator.hover();
await waitNextFrame(page);
await expect(linkPopoverLocator).toBeVisible();
- await expect(linkToCardBtn).toBeVisible();
- await expect(linkToEmbedBtn).toBeVisible();
-
- await page.mouse.move(0, 0);
- await waitNextFrame(page);
- await expect(linkPopoverLocator).not.toBeVisible();
- await focusRichText(page, 1);
- await pressTab(page);
-
- await linkLocator.hover();
- await waitNextFrame(page);
- await expect(linkPopoverLocator).toBeVisible();
- await expect(linkToCardBtn).not.toBeVisible();
- await expect(linkToEmbedBtn).not.toBeVisible();
});
diff --git a/blocksuite/tests-legacy/linked-page.spec.ts b/blocksuite/tests-legacy/linked-page.spec.ts
index bcfa9ca1e4214..e83b2917b674b 100644
--- a/blocksuite/tests-legacy/linked-page.spec.ts
+++ b/blocksuite/tests-legacy/linked-page.spec.ts
@@ -16,11 +16,9 @@ import {
pressArrowRight,
pressBackspace,
pressEnter,
- redoByKeyboard,
selectAllByKeyboard,
SHORT_KEY,
type,
- undoByKeyboard,
} from './utils/actions/keyboard.js';
import {
captureHistory,
@@ -37,7 +35,6 @@ import {
assertExists,
assertParentBlockFlavour,
assertRichTexts,
- assertStoreMatchJSX,
assertTitle,
} from './utils/asserts.js';
import { test } from './utils/playwright.js';
@@ -95,22 +92,17 @@ test.describe('multiple page', () => {
});
test.describe('reference node', () => {
- test('linked doc popover can show and hide correctly', async ({ page }) => {
+ test('linked doc popover can show and hide correctly', async ({
+ page,
+ }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, '[[');
// `[[` should be converted to `@`
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
const { linkedDocPopover } = getLinkedDocPopover(page);
await expect(linkedDocPopover).toBeVisible();
@@ -140,46 +132,23 @@ test.describe('reference node', () => {
await expect(linkedDocPopover).toBeHidden();
});
- test('should reference node attributes correctly', async ({ page }) => {
+ test('should reference node attributes correctly', async ({
+ page,
+ }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
- const { id } = await addNewPage(page);
+ await initEmptyParagraphState(page);
+ await addNewPage(page);
await focusRichText(page);
await type(page, '[[');
await pressEnter(page);
- await assertStoreMatchJSX(
- page,
- `
-
-
- >
- }
- prop:type="text"
-/>`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await pressBackspace(page);
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
});
@@ -211,10 +180,10 @@ test.describe('reference node', () => {
test('text inserted in the between of reference nodes should not be extend attributes', async ({
page,
- }) => {
+ }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
- const { id } = await addNewPage(page);
+ await initEmptyParagraphState(page);
+ await addNewPage(page);
await focusRichText(page);
await type(page, '1');
@@ -234,51 +203,17 @@ test.describe('reference node', () => {
await type(page, '3');
await assertRichTexts(page, ['1 3 2']);
- const snapshot = `
-
-
-
-
-
-
- >
- }
- prop:type="text"
-/>`;
- await assertStoreMatchJSX(page, snapshot, paragraphId);
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
+ );
});
test('text can be inserted as expected when reference node is in the start or end of line', async ({
page,
- }) => {
+ }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
- const { id } = await addNewPage(page);
+ await initEmptyParagraphState(page);
+ await addNewPage(page);
await focusRichText(page);
await type(page, '@');
@@ -304,51 +239,17 @@ test.describe('reference node', () => {
await type(page, '1');
await assertRichTexts(page, ['1 3 2']);
- const snapshot = `
-
-
-
-
-
-
- >
- }
- prop:type="text"
-/>`;
- await assertStoreMatchJSX(page, snapshot, paragraphId);
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
+ );
});
test('should the cursor move correctly around reference node', async ({
page,
- }) => {
+ }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
- const { id } = await addNewPage(page);
+ await initEmptyParagraphState(page);
+ await addNewPage(page);
await focusRichText(page);
await type(page, '1');
@@ -370,57 +271,16 @@ test.describe('reference node', () => {
await type(page, '4');
await assertRichTexts(page, ['14 32']);
- const snapshot = `
-
-
-
-
- >
- }
- prop:type="text"
-/>`;
- await assertStoreMatchJSX(page, snapshot, paragraphId);
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
+ );
await page.keyboard.press('ArrowRight');
await captureHistory(page);
await pressBackspace(page);
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
- );
- await undoByKeyboard(page);
- await assertStoreMatchJSX(page, snapshot, paragraphId);
- await redoByKeyboard(page);
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
});
@@ -747,13 +607,15 @@ test.describe('linked page with clipboard', () => {
});
});
-test('should [[Selected text]] converted to linked page', async ({ page }) => {
+test('should [[Selected text]] converted to linked page', async ({
+ page,
+}, testInfo) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/toeverything/blocksuite/issues/2730',
});
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, '1234');
@@ -761,33 +623,8 @@ test('should [[Selected text]] converted to linked page', async ({ page }) => {
await type(page, '[');
await assertRichTexts(page, ['1[2]34']);
await type(page, '[');
- await assertStoreMatchJSX(
- page,
- `
-
-
-
-
- >
- }
- prop:type="text"
-/>`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
await switchToPage(page, '3');
await assertTitle(page, '2');
diff --git a/blocksuite/tests-legacy/paragraph.spec.ts b/blocksuite/tests-legacy/paragraph.spec.ts
index 9c8a373170e65..ad95559f059f5 100644
--- a/blocksuite/tests-legacy/paragraph.spec.ts
+++ b/blocksuite/tests-legacy/paragraph.spec.ts
@@ -50,7 +50,6 @@ import {
assertDocTitleFocus,
assertRichTextInlineRange,
assertRichTexts,
- assertStoreMatchJSX,
assertTitle,
} from './utils/asserts.js';
import { test } from './utils/playwright.js';
@@ -1296,9 +1295,11 @@ test.describe('readonly mode', () => {
await expect(placeholder).toBeHidden();
});
- test('should readonly mode not be able to modify text', async ({ page }) => {
+ test('should readonly mode not be able to modify text', async ({
+ page,
+ }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, 'hello');
@@ -1308,27 +1309,13 @@ test.describe('readonly mode', () => {
await type(page, 'world');
await dragBetweenIndices(page, [0, 1], [0, 3]);
await page.keyboard.press(`${SHORT_KEY}+b`);
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_1.json`
);
await undoByKeyboard(page);
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}_2.json`
);
});
});
diff --git a/blocksuite/tests-legacy/slash-menu.spec.ts b/blocksuite/tests-legacy/slash-menu.spec.ts
index 928fe9d1400b5..1f11918ddd022 100644
--- a/blocksuite/tests-legacy/slash-menu.spec.ts
+++ b/blocksuite/tests-legacy/slash-menu.spec.ts
@@ -34,7 +34,6 @@ import {
assertBlockCount,
assertExists,
assertRichTexts,
- assertStoreMatchJSX,
} from './utils/asserts.js';
import { test } from './utils/playwright.js';
@@ -62,9 +61,10 @@ test.describe('slash menu should show and hide correctly', () => {
await expect(slashMenu).toBeVisible();
});
- test('slash menu should hide after click away', async ({ page }) => {
- const id = await initEmptyParagraphState(page);
- const paragraphId = id.paragraphId;
+ test('slash menu should hide after click away', async ({
+ page,
+ }, testInfo) => {
+ await initEmptyParagraphState(page);
const slashMenu = page.locator(`.slash-menu`);
await focusRichText(page);
await type(page, '/');
@@ -72,15 +72,9 @@ test.describe('slash menu should show and hide correctly', () => {
// Click outside should close slash menu
await page.mouse.click(0, 50);
await expect(slashMenu).toBeHidden();
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
@@ -106,9 +100,8 @@ test.describe('slash menu should show and hide correctly', () => {
test('delete the slash symbol should close the slash menu', async ({
page,
- }) => {
- const id = await initEmptyParagraphState(page);
- const paragraphId = id.paragraphId;
+ }, testInfo) => {
+ await initEmptyParagraphState(page);
const slashMenu = page.locator(`.slash-menu`);
await focusRichText(page);
await type(page, '/');
@@ -116,14 +109,8 @@ test.describe('slash menu should show and hide correctly', () => {
await pressBackspace(page);
await expect(slashMenu).toBeHidden();
- await assertStoreMatchJSX(
- page,
- `
-`,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
@@ -522,13 +509,15 @@ test('should slash menu works with fast type', async ({ page }) => {
await expect(slashMenu).toBeVisible();
});
-test('should clean slash string after soft enter', async ({ page }) => {
+test('should clean slash string after soft enter', async ({
+ page,
+}, testInfo) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/toeverything/blocksuite/issues/1126',
});
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, 'hello');
await pressShiftEnter(page);
@@ -536,15 +525,8 @@ test('should clean slash string after soft enter', async ({ page }) => {
await type(page, '/copy');
await pressEnter(page);
- await assertStoreMatchJSX(
- page,
- `
- `,
- paragraphId
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
@@ -720,9 +702,9 @@ test.describe('slash menu with date & time', () => {
});
test.describe('slash menu with style', () => {
- test('should style text line works', async ({ page }) => {
+ test('should style text line works', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, 'hello/');
@@ -730,28 +712,15 @@ test.describe('slash menu with style', () => {
await expect(slashMenu).toBeVisible();
const bold = page.getByTestId('Bold');
await bold.click();
- await assertStoreMatchJSX(
- page,
- `
-
-
- >
- }
- prop:type="text"
-/>`,
- paragraphId
+
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
- test('should style empty line works', async ({ page }) => {
+ test('should style empty line works', async ({ page }, testInfo) => {
await enterPlaygroundRoom(page);
- const { paragraphId } = await initEmptyParagraphState(page);
+ await initEmptyParagraphState(page);
await focusRichText(page);
await type(page, '/');
@@ -761,22 +730,9 @@ test.describe('slash menu with style', () => {
await bold.click();
await page.waitForTimeout(50);
await type(page, 'hello');
- await assertStoreMatchJSX(
- page,
- `
-
-
- >
- }
- prop:type="text"
-/>`,
- paragraphId
+
+ expect(await getPageSnapshot(page, true)).toMatchSnapshot(
+ `${testInfo.title}.json`
);
});
});
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/can-insert-attachment-from-slash-menu.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/can-insert-attachment-from-slash-menu.json
new file mode 100644
index 0000000000000..bb3fac3be0430
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/can-insert-attachment-from-slash-menu.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA="
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-attachment-can-be-deleted.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-attachment-can-be-deleted.json
new file mode 100644
index 0000000000000..e7c7c2e21c7f9
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-attachment-can-be-deleted.json
@@ -0,0 +1,40 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json
new file mode 100644
index 0000000000000..9eb1cb4229c11
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-1.json
@@ -0,0 +1,59 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "4",
+ "flavour": "affine:image",
+ "version": 1,
+ "props": {
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA=",
+ "width": 0,
+ "height": 0,
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "size": 45801,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-2.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-2.json
new file mode 100644
index 0000000000000..82cb4cf1b5eb3
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-turn-attachment-to-image-works-2.json
@@ -0,0 +1,61 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "5",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA=",
+ "caption": "",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-1.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-1.json
new file mode 100644
index 0000000000000..bb3fac3be0430
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-1.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA="
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-2.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-2.json
new file mode 100644
index 0000000000000..35cc21baf0451
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-2.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "/"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-3.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-3.json
new file mode 100644
index 0000000000000..bb3fac3be0430
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/should-undo-redo-works-for-attachment-3.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA="
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-1.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-1.json
new file mode 100644
index 0000000000000..bb3fac3be0430
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-1.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA="
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-2.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-2.json
new file mode 100644
index 0000000000000..10f23da14788b
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-2.json
@@ -0,0 +1,117 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA="
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "4",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "111"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "5",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "222"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "6",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "333"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-3.json b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-3.json
new file mode 100644
index 0000000000000..6f8cf6c9e3da3
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/attachment.spec.ts/support-dragging-attachment-block-directly-3.json
@@ -0,0 +1,117 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "4",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "111"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "5",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "222"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:attachment",
+ "version": 1,
+ "props": {
+ "name": "test-card-1.png",
+ "size": 45801,
+ "type": "image/png",
+ "embed": false,
+ "style": "horizontalThin",
+ "index": "a0",
+ "xywh": "[0,0,0,0]",
+ "lockedBySelf": false,
+ "rotate": 0,
+ "sourceId": "ejImogf-Tb7AuKY-v94uz1zuOJbClqK-tWBxVr_ksGA="
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "6",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "333"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/add-caption-works.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/add-caption-works.json
new file mode 100644
index 0000000000000..d4177165f292d
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/add-caption-works.json
@@ -0,0 +1,72 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": false,
+ "caption": "BlockSuite"
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/change-code-language-can-work-1.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/change-code-language-can-work-1.json
new file mode 100644
index 0000000000000..5a4f767d5c360
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/change-code-language-can-work-1.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": "rust",
+ "wrap": false,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/change-code-language-can-work-2.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/change-code-language-can-work-2.json
new file mode 100644
index 0000000000000..817823dfc02bc
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/change-code-language-can-work-2.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": false,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-1.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-1.json
new file mode 100644
index 0000000000000..817823dfc02bc
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-1.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": false,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-2.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-2.json
new file mode 100644
index 0000000000000..4289de99cebc7
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-2.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": true,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-3.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-3.json
new file mode 100644
index 0000000000000..817823dfc02bc
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/toggle-code-block-wrap-can-work-3.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": false,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-1.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-1.json
new file mode 100644
index 0000000000000..817823dfc02bc
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-1.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": false,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-2.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-2.json
new file mode 100644
index 0000000000000..4289de99cebc7
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-2.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": true,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-3.json b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-3.json
new file mode 100644
index 0000000000000..817823dfc02bc
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/code/crud.spec.ts/undo-code-block-wrap-can-work-3.json
@@ -0,0 +1,57 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:code",
+ "version": 1,
+ "props": {
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "language": null,
+ "wrap": false,
+ "caption": ""
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/link.spec.ts/convert-link-to-embed.json b/blocksuite/tests-legacy/snapshots/link.spec.ts/convert-link-to-embed.json
new file mode 100644
index 0000000000000..f9a5b5abed174
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/link.spec.ts/convert-link-to-embed.json
@@ -0,0 +1,88 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "aaa"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ },
+ {
+ "type": "block",
+ "id": "3",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "a"
+ },
+ {
+ "insert": "linkText",
+ "attributes": {
+ "link": "https://www.youtube.com/watch?v=U6s2pdxebSo"
+ }
+ },
+ {
+ "insert": "a"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/link.spec.ts/create-link-with-paste.json b/blocksuite/tests-legacy/snapshots/link.spec.ts/create-link-with-paste.json
new file mode 100644
index 0000000000000..239dbbb029a45
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/link.spec.ts/create-link-with-paste.json
@@ -0,0 +1,63 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "aaa",
+ "attributes": {
+ "link": "http://affine.pro"
+ }
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/link.spec.ts/should-mock-selection-not-stored.json b/blocksuite/tests-legacy/snapshots/link.spec.ts/should-mock-selection-not-stored.json
new file mode 100644
index 0000000000000..d395cf5b10992
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/link.spec.ts/should-mock-selection-not-stored.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "linkText"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/link.spec.ts/type-character-after-link-should-not-extend-the-link-attributes.json b/blocksuite/tests-legacy/snapshots/link.spec.ts/type-character-after-link-should-not-extend-the-link-attributes.json
new file mode 100644
index 0000000000000..321e38f068b2c
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/link.spec.ts/type-character-after-link-should-not-extend-the-link-attributes.json
@@ -0,0 +1,73 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "title"
+ }
+ ]
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "Hello"
+ },
+ {
+ "insert": "link text",
+ "attributes": {
+ "link": "http://example.com"
+ }
+ },
+ {
+ "insert": "AFTER_LINK"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/link.spec.ts/type-character-in-link-should-not-jump-out-link-node.json b/blocksuite/tests-legacy/snapshots/link.spec.ts/type-character-in-link-should-not-jump-out-link-node.json
new file mode 100644
index 0000000000000..e108d46b3e0ab
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/link.spec.ts/type-character-in-link-should-not-jump-out-link-node.json
@@ -0,0 +1,70 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "title"
+ }
+ ]
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "Hello"
+ },
+ {
+ "insert": "link texIN_LINKt",
+ "attributes": {
+ "link": "http://example.com"
+ }
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/linked-doc-popover-can-show-and-hide-correctly.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/linked-doc-popover-can-show-and-hide-correctly.json
new file mode 100644
index 0000000000000..56500e437ead0
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/linked-doc-popover-can-show-and-hide-correctly.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "@"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-Selected-text-converted-to-linked-page.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-Selected-text-converted-to-linked-page.json
new file mode 100644
index 0000000000000..1ce9b5939c25c
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-Selected-text-converted-to-linked-page.json
@@ -0,0 +1,72 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "1"
+ },
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ },
+ {
+ "insert": "34"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-reference-node-attributes-correctly-1.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-reference-node-attributes-correctly-1.json
new file mode 100644
index 0000000000000..10e0f86b5851f
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-reference-node-attributes-correctly-1.json
@@ -0,0 +1,66 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-reference-node-attributes-correctly-2.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-reference-node-attributes-correctly-2.json
new file mode 100644
index 0000000000000..2d280cd0d1842
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-reference-node-attributes-correctly-2.json
@@ -0,0 +1,56 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-the-cursor-move-correctly-around-reference-node-1.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-the-cursor-move-correctly-around-reference-node-1.json
new file mode 100644
index 0000000000000..5836c751d119f
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-the-cursor-move-correctly-around-reference-node-1.json
@@ -0,0 +1,72 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "14"
+ },
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ },
+ {
+ "insert": "32"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-the-cursor-move-correctly-around-reference-node-2.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-the-cursor-move-correctly-around-reference-node-2.json
new file mode 100644
index 0000000000000..07a9a51ce5c88
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/should-the-cursor-move-correctly-around-reference-node-2.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "1432"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/text-can-be-inserted-as-expected-when-reference-node-is-in-the-start-or-end-of-line.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/text-can-be-inserted-as-expected-when-reference-node-is-in-the-start-or-end-of-line.json
new file mode 100644
index 0000000000000..c7b0111e42e57
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/text-can-be-inserted-as-expected-when-reference-node-is-in-the-start-or-end-of-line.json
@@ -0,0 +1,84 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "1"
+ },
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ },
+ {
+ "insert": "3"
+ },
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ },
+ {
+ "insert": "2"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/text-inserted-in-the-between-of-reference-nodes-should-not-be-extend-attributes.json b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/text-inserted-in-the-between-of-reference-nodes-should-not-be-extend-attributes.json
new file mode 100644
index 0000000000000..c7b0111e42e57
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/linked-page.spec.ts/text-inserted-in-the-between-of-reference-nodes-should-not-be-extend-attributes.json
@@ -0,0 +1,84 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "1"
+ },
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ },
+ {
+ "insert": "3"
+ },
+ {
+ "insert": " ",
+ "attributes": {
+ "reference": {
+ "type": "LinkedPage",
+ "pageId": "3"
+ }
+ }
+ },
+ {
+ "insert": "2"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/paragraph.spec.ts/should-readonly-mode-not-be-able-to-modify-text-1.json b/blocksuite/tests-legacy/snapshots/paragraph.spec.ts/should-readonly-mode-not-be-able-to-modify-text-1.json
new file mode 100644
index 0000000000000..88deb243a5c6f
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/paragraph.spec.ts/should-readonly-mode-not-be-able-to-modify-text-1.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "hello"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/paragraph.spec.ts/should-readonly-mode-not-be-able-to-modify-text-2.json b/blocksuite/tests-legacy/snapshots/paragraph.spec.ts/should-readonly-mode-not-be-able-to-modify-text-2.json
new file mode 100644
index 0000000000000..88deb243a5c6f
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/paragraph.spec.ts/should-readonly-mode-not-be-able-to-modify-text-2.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "hello"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/delete-the-slash-symbol-should-close-the-slash-menu.json b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/delete-the-slash-symbol-should-close-the-slash-menu.json
new file mode 100644
index 0000000000000..2d280cd0d1842
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/delete-the-slash-symbol-should-close-the-slash-menu.json
@@ -0,0 +1,56 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-clean-slash-string-after-soft-enter.json b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-clean-slash-string-after-soft-enter.json
new file mode 100644
index 0000000000000..a8c8a38651f44
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-clean-slash-string-after-soft-enter.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "hello\n"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-style-empty-line-works.json b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-style-empty-line-works.json
new file mode 100644
index 0000000000000..9f601bf1eee26
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-style-empty-line-works.json
@@ -0,0 +1,63 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "hello",
+ "attributes": {
+ "bold": true
+ }
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-style-text-line-works.json b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-style-text-line-works.json
new file mode 100644
index 0000000000000..9f601bf1eee26
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/should-style-text-line-works.json
@@ -0,0 +1,63 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "hello",
+ "attributes": {
+ "bold": true
+ }
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/slash-menu-should-hide-after-click-away.json b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/slash-menu-should-hide-after-click-away.json
new file mode 100644
index 0000000000000..35cc21baf0451
--- /dev/null
+++ b/blocksuite/tests-legacy/snapshots/slash-menu.spec.ts/slash-menu-should-hide-after-click-away.json
@@ -0,0 +1,60 @@
+{
+ "type": "block",
+ "id": "0",
+ "flavour": "affine:page",
+ "version": 2,
+ "props": {
+ "title": {
+ "$blocksuite:internal:text$": true,
+ "delta": []
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "1",
+ "flavour": "affine:note",
+ "version": 1,
+ "props": {
+ "xywh": "[0,0,498,92]",
+ "background": {
+ "dark": "#000000",
+ "light": "#ffffff"
+ },
+ "index": "a0",
+ "lockedBySelf": false,
+ "hidden": false,
+ "displayMode": "both",
+ "edgeless": {
+ "style": {
+ "borderRadius": 8,
+ "borderSize": 4,
+ "borderStyle": "none",
+ "shadowType": "--affine-note-shadow-box"
+ }
+ }
+ },
+ "children": [
+ {
+ "type": "block",
+ "id": "2",
+ "flavour": "affine:paragraph",
+ "version": 1,
+ "props": {
+ "type": "text",
+ "text": {
+ "$blocksuite:internal:text$": true,
+ "delta": [
+ {
+ "insert": "/"
+ }
+ ]
+ },
+ "collapsed": false
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/blocksuite/tests-legacy/utils/asserts.ts b/blocksuite/tests-legacy/utils/asserts.ts
index 6bc474ef767c0..6992b63524e51 100644
--- a/blocksuite/tests-legacy/utils/asserts.ts
+++ b/blocksuite/tests-legacy/utils/asserts.ts
@@ -18,11 +18,6 @@ import type { InlineRootElement } from '@inline/inline-editor.js';
import { expect, type Locator, type Page } from '@playwright/test';
import { COLLECTION_VERSION, PAGE_VERSION } from '@store/consts.js';
import type { BlockModel } from '@store/index.js';
-import type { JSXElement } from '@store/utils/jsx.js';
-import {
- format as prettyFormat,
- plugins as prettyFormatPlugins,
-} from 'pretty-format';
import {
getCanvasElementsCount,
@@ -50,7 +45,6 @@ import {
import {
captureHistory,
getClipboardCustomData,
- getCurrentEditorDocId,
getCurrentThemeCSSPropertyValue,
getEditorLocator,
inlineEditorInnerTextToString,
@@ -633,116 +627,6 @@ export async function assertBlockTypes(page: Page, blockTypes: string[]) {
expect(actual).toEqual(blockTypes);
}
-/**
- * @example
- * ```ts
- * await assertMatchMarkdown(
- * page,
- * `title
- * text1
- * text2`
- * );
- * ```
- * @deprecated experimental, use {@link assertStoreMatchJSX} instead
- */
-export async function assertMatchMarkdown(page: Page, text: string) {
- const jsonDoc = (await page.evaluate(() =>
- window.collection.doc.toJSON()
- )) as Record>;
- const titleNode = jsonDoc['doc:home']['0'] as Record;
-
- const markdownVisitor = (node: Record): string => {
- // TODO use schema
- if (node['sys:flavour'] === 'affine:page') {
- return (node['prop:title'] as Text).toString() ?? '';
- }
- if (!('prop:type' in node)) {
- return '[? unknown node]';
- }
- if (node['prop:type'] === 'text') {
- return node['prop:text'] as string;
- }
- if (node['prop:type'] === 'bulleted') {
- return `- ${node['prop:text']}`;
- }
- // TODO please fix this
- return `[? ${node['prop:type']} node]`;
- };
-
- const INDENT_SIZE = 2;
- const visitNodes = (
- node: Record,
- visitor: (node: Record) => string
- ): string[] => {
- if (!('sys:children' in node) || !Array.isArray(node['sys:children'])) {
- throw new Error("Failed to visit nodes: 'sys:children' is not an array");
- // return visitor(node);
- }
-
- const children = node['sys:children'].map(id => jsonDoc['doc:home'][id]);
- return [
- visitor(node),
- ...children.flatMap(child =>
- visitNodes(child as Record, visitor).map(line => {
- if (node['sys:flavour'] === 'affine:page') {
- // Ad hoc way to remove the title indent
- return line;
- }
-
- return ' '.repeat(INDENT_SIZE) + line;
- })
- ),
- ];
- };
- const visitRet = visitNodes(titleNode, markdownVisitor);
- const actual = visitRet.join('\n');
-
- expect(actual).toEqual(text);
-}
-
-export async function assertStoreMatchJSX(
- page: Page,
- snapshot: string,
- blockId?: string
-) {
- const docId = await getCurrentEditorDocId(page);
- const element = (await page.evaluate(
- ([blockId, docId]) => window.collection.exportJSX(blockId, docId),
- [blockId, docId]
- )) as JSXElement;
-
- // Fix symbol can not be serialized, we need to set $$typeof manually
- // If the function passed to the page.evaluate(pageFunction[, arg]) returns a non-Serializable value,
- // then page.evaluate(pageFunction[, arg]) resolves to undefined.
- // See https://playwright.dev/docs/api/class-page#page-evaluate
- const testSymbol = Symbol.for('react.test.json');
- const markSymbol = (node: JSXElement) => {
- node.$$typeof = testSymbol;
- if (!node.children) {
- return;
- }
- const propText = node.props['prop:text'];
- if (propText && typeof propText === 'object') {
- markSymbol(propText);
- }
- node.children.forEach(child => {
- if (!(typeof child === 'object')) {
- return;
- }
- markSymbol(child);
- });
- };
-
- markSymbol(element);
-
- // See https://github.com/facebook/jest/blob/main/packages/pretty-format
- const formattedJSX = prettyFormat(element, {
- plugins: [prettyFormatPlugins.ReactTestComponent],
- printFunctionName: false,
- });
- expect(formattedJSX, formattedJSX).toEqual(snapshot.trimStart());
-}
-
type MimeType = 'text/plain' | 'blocksuite/x-c+w' | 'text/html';
export function assertClipItems(_page: Page, _key: MimeType, _value: unknown) {