test: sync provider (#1754)

This commit is contained in:
Himself65 2023-03-30 03:22:26 -05:00 committed by GitHub
parent d8d965b9b8
commit 4dd1490eef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 183 additions and 2 deletions

View File

@ -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

View File

@ -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"
} }
} }

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

View File

@ -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: