mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-18 09:41:34 +03:00
test: sync provider (#1754)
This commit is contained in:
parent
d8d965b9b8
commit
4dd1490eef
@ -32,7 +32,7 @@ const createAffineWebSocketProvider = (
|
|||||||
blockSuiteWorkspace.id,
|
blockSuiteWorkspace.id,
|
||||||
blockSuiteWorkspace.doc,
|
blockSuiteWorkspace.doc,
|
||||||
{
|
{
|
||||||
params: { token: getLoginStorage()?.token ?? '' },
|
params: { token: getLoginStorage()?.refresh ?? '' },
|
||||||
// @ts-expect-error ignore the type
|
// @ts-expect-error ignore the type
|
||||||
awareness: blockSuiteWorkspace.awarenessStore.awareness,
|
awareness: blockSuiteWorkspace.awarenessStore.awareness,
|
||||||
// we maintain broadcast channel by ourselves
|
// we maintain broadcast channel by ourselves
|
||||||
|
@ -23,5 +23,9 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/ws": "^8.5.4",
|
||||||
|
"ws": "^8.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
166
packages/workspace/src/affine/__tests__/sync.spec.ts
Normal file
166
packages/workspace/src/affine/__tests__/sync.spec.ts
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
import type { Workspace } from '@affine/workspace/affine/api';
|
||||||
|
import {
|
||||||
|
createWorkspaceApis,
|
||||||
|
PermissionType,
|
||||||
|
} from '@affine/workspace/affine/api';
|
||||||
|
import type { LoginResponse } from '@affine/workspace/affine/login';
|
||||||
|
import { loginResponseSchema } from '@affine/workspace/affine/login';
|
||||||
|
import { WebsocketProvider } from '@affine/workspace/affine/sync';
|
||||||
|
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||||
|
import user1 from '@affine-test/fixtures/built-in-user1.json';
|
||||||
|
import user2 from '@affine-test/fixtures/built-in-user2.json';
|
||||||
|
import type { ParagraphBlockModel } from '@blocksuite/blocks/models';
|
||||||
|
import type { Page, Text } from '@blocksuite/store';
|
||||||
|
import { uuidv4, Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||||
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
|
const currentTokenRef = {
|
||||||
|
current: null as LoginResponse | null,
|
||||||
|
};
|
||||||
|
|
||||||
|
vi.stubGlobal('localStorage', {
|
||||||
|
getItem: () => JSON.stringify(currentTokenRef.current),
|
||||||
|
setItem: () => null,
|
||||||
|
});
|
||||||
|
|
||||||
|
let workspaceApis: ReturnType<typeof createWorkspaceApis>;
|
||||||
|
|
||||||
|
let user1Token: LoginResponse;
|
||||||
|
let user2Token: LoginResponse;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
workspaceApis = createWorkspaceApis('http://127.0.0.1:3000/');
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const data = await fetch('http://127.0.0.1:3000/api/user/token', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
type: 'DebugLoginUser',
|
||||||
|
email: user1.email,
|
||||||
|
password: user1.password,
|
||||||
|
}),
|
||||||
|
}).then(r => r.json());
|
||||||
|
loginResponseSchema.parse(data);
|
||||||
|
user1Token = data;
|
||||||
|
const data2 = await fetch('http://127.0.0.1:3000/api/user/token', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
type: 'DebugLoginUser',
|
||||||
|
email: user2.email,
|
||||||
|
password: user2.password,
|
||||||
|
}),
|
||||||
|
}).then(r => r.json());
|
||||||
|
loginResponseSchema.parse(data2);
|
||||||
|
user2Token = data2;
|
||||||
|
});
|
||||||
|
|
||||||
|
const wsUrl = `ws://127.0.0.1:3000/api/sync/`;
|
||||||
|
|
||||||
|
describe('ydoc sync', () => {
|
||||||
|
test(
|
||||||
|
'page',
|
||||||
|
async () => {
|
||||||
|
currentTokenRef.current = user1Token;
|
||||||
|
const list = await workspaceApis.getWorkspaces();
|
||||||
|
const root = list.find(
|
||||||
|
workspace => workspace.permission === PermissionType.Owner
|
||||||
|
) as Workspace;
|
||||||
|
expect(root).toBeDefined();
|
||||||
|
const binary = await workspaceApis.downloadWorkspace(root.id);
|
||||||
|
const workspace1 = createEmptyBlockSuiteWorkspace(
|
||||||
|
root.id,
|
||||||
|
(k: string) => ({ api: '/api/workspace', token: user1Token.token }[k])
|
||||||
|
);
|
||||||
|
const workspace2 = createEmptyBlockSuiteWorkspace(
|
||||||
|
root.id,
|
||||||
|
(k: string) => ({ api: '/api/workspace', token: user2Token.token }[k])
|
||||||
|
);
|
||||||
|
BlockSuiteWorkspace.Y.applyUpdate(workspace1.doc, new Uint8Array(binary));
|
||||||
|
BlockSuiteWorkspace.Y.applyUpdate(workspace2.doc, new Uint8Array(binary));
|
||||||
|
const provider1 = new WebsocketProvider(
|
||||||
|
wsUrl,
|
||||||
|
workspace1.id,
|
||||||
|
workspace1.doc,
|
||||||
|
{
|
||||||
|
// @ts-expect-error ignore the error
|
||||||
|
WebSocketPolyfill: WebSocket,
|
||||||
|
params: { token: user1Token.refresh },
|
||||||
|
// @ts-expect-error ignore the type
|
||||||
|
awareness: workspace1.awarenessStore.awareness,
|
||||||
|
disableBc: true,
|
||||||
|
connect: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const provider2 = new WebsocketProvider(
|
||||||
|
wsUrl,
|
||||||
|
workspace2.id,
|
||||||
|
workspace2.doc,
|
||||||
|
{
|
||||||
|
// @ts-expect-error ignore the error
|
||||||
|
WebSocketPolyfill: WebSocket,
|
||||||
|
params: { token: user2Token.refresh },
|
||||||
|
// @ts-expect-error ignore the type
|
||||||
|
awareness: workspace2.awarenessStore.awareness,
|
||||||
|
disableBc: true,
|
||||||
|
connect: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
provider1.connect();
|
||||||
|
provider2.connect();
|
||||||
|
|
||||||
|
function waitForConnected(provider: WebsocketProvider) {
|
||||||
|
return new Promise<void>(resolve => {
|
||||||
|
provider.once('status', ({ status }: any) => {
|
||||||
|
expect(status).toBe('connected');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
waitForConnected(provider1),
|
||||||
|
waitForConnected(provider2),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const pageId = uuidv4();
|
||||||
|
const page1 = workspace1.createPage(pageId);
|
||||||
|
const pageBlockId = page1.addBlock('affine:page', {
|
||||||
|
title: new page1.Text(''),
|
||||||
|
});
|
||||||
|
page1.addBlock('affine:surface', {}, null);
|
||||||
|
const frameId = page1.addBlock('affine:frame', {}, pageBlockId);
|
||||||
|
const paragraphId = page1.addBlock('affine:paragraph', {}, frameId);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
expect(workspace2.getPage(pageId)).toBeDefined();
|
||||||
|
expect(workspace2.doc.getMap(`space:${pageId}`).toJSON()).toEqual(
|
||||||
|
workspace1.doc.getMap(`space:${pageId}`).toJSON()
|
||||||
|
);
|
||||||
|
const page2 = workspace2.getPage(pageId) as Page;
|
||||||
|
page1.updateBlockById(paragraphId, {
|
||||||
|
text: new page1.Text('hello world'),
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
const paragraph2 = page2.getBlockById(paragraphId) as ParagraphBlockModel;
|
||||||
|
const text = paragraph2.text as Text;
|
||||||
|
expect(text.toString()).toEqual(
|
||||||
|
page1.getBlockById(paragraphId)?.text?.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
provider1.disconnect();
|
||||||
|
provider2.disconnect();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timeout: 30000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
13
yarn.lock
13
yarn.lock
@ -234,6 +234,7 @@ __metadata:
|
|||||||
"@affine/env": "workspace:*"
|
"@affine/env": "workspace:*"
|
||||||
"@blocksuite/blocks": 0.5.0-20230324040005-14417c2
|
"@blocksuite/blocks": 0.5.0-20230324040005-14417c2
|
||||||
"@blocksuite/store": 0.5.0-20230324040005-14417c2
|
"@blocksuite/store": 0.5.0-20230324040005-14417c2
|
||||||
|
"@types/ws": ^8.5.4
|
||||||
firebase: ^9.18.0
|
firebase: ^9.18.0
|
||||||
jotai: ^2.0.3
|
jotai: ^2.0.3
|
||||||
js-base64: ^3.7.5
|
js-base64: ^3.7.5
|
||||||
@ -241,6 +242,7 @@ __metadata:
|
|||||||
lib0: ^0.2.73
|
lib0: ^0.2.73
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
|
ws: ^8.13.0
|
||||||
zod: ^3.21.4
|
zod: ^3.21.4
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
@ -6742,6 +6744,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/ws@npm:^8.5.4":
|
||||||
|
version: 8.5.4
|
||||||
|
resolution: "@types/ws@npm:8.5.4"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "*"
|
||||||
|
checksum: fefbad20d211929bb996285c4e6f699b12192548afedbe4930ab4384f8a94577c9cd421acaad163cacd36b88649509970a05a0b8f20615b30c501ed5269038d1
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/yargs-parser@npm:*":
|
"@types/yargs-parser@npm:*":
|
||||||
version: 21.0.0
|
version: 21.0.0
|
||||||
resolution: "@types/yargs-parser@npm:21.0.0"
|
resolution: "@types/yargs-parser@npm:21.0.0"
|
||||||
@ -19256,7 +19267,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ws@npm:^8.2.3":
|
"ws@npm:^8.13.0, ws@npm:^8.2.3":
|
||||||
version: 8.13.0
|
version: 8.13.0
|
||||||
resolution: "ws@npm:8.13.0"
|
resolution: "ws@npm:8.13.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
Loading…
Reference in New Issue
Block a user