mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-25 20:12:13 +03:00
test: remove deprecated test (#2880)
This commit is contained in:
parent
78b74d5b15
commit
26ac56e163
@ -1,484 +0,0 @@
|
|||||||
/**
|
|
||||||
* @vitest-environment happy-dom
|
|
||||||
*/
|
|
||||||
import 'fake-indexeddb/auto';
|
|
||||||
|
|
||||||
import { readFile } from 'node:fs/promises';
|
|
||||||
|
|
||||||
import { MessageCode } from '@affine/env/constant';
|
|
||||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
|
||||||
import {
|
|
||||||
createWorkspaceResponseSchema,
|
|
||||||
usageResponseSchema,
|
|
||||||
} from '@affine/env/workspace/legacy-cloud';
|
|
||||||
import user1 from '@affine-test/fixtures/built-in-user1.json';
|
|
||||||
import user2 from '@affine-test/fixtures/built-in-user2.json';
|
|
||||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
|
||||||
import { assertExists } from '@blocksuite/global/utils';
|
|
||||||
import type { Page, PageMeta } from '@blocksuite/store';
|
|
||||||
import { Workspace } from '@blocksuite/store';
|
|
||||||
import { faker } from '@faker-js/faker';
|
|
||||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
||||||
import { WebSocket } from 'ws';
|
|
||||||
import { applyUpdate } from 'yjs';
|
|
||||||
|
|
||||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
|
||||||
import { createUserApis, createWorkspaceApis, RequestError } from '../api';
|
|
||||||
import { createStatusApis } from '../api/status';
|
|
||||||
import { KeckProvider } from '../keck';
|
|
||||||
import {
|
|
||||||
createAffineAuth,
|
|
||||||
getLoginStorage,
|
|
||||||
loginResponseSchema,
|
|
||||||
setLoginStorage,
|
|
||||||
} from '../login';
|
|
||||||
|
|
||||||
declare module '@blocksuite/store' {
|
|
||||||
interface PageMeta {
|
|
||||||
isPublic?: boolean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-expect-error
|
|
||||||
globalThis.WebSocket = WebSocket;
|
|
||||||
|
|
||||||
let workspaceApis: ReturnType<typeof createWorkspaceApis>;
|
|
||||||
let userApis: ReturnType<typeof createUserApis>;
|
|
||||||
let affineAuth: ReturnType<typeof createAffineAuth>;
|
|
||||||
let statusApis: ReturnType<typeof createStatusApis>;
|
|
||||||
|
|
||||||
async function initPage(page: Page) {
|
|
||||||
await page.waitForLoaded();
|
|
||||||
// Add page block and surface block at root level
|
|
||||||
const pageBlockId = page.addBlock('affine:page', {
|
|
||||||
title: new page.Text(''),
|
|
||||||
});
|
|
||||||
page.addBlock('affine:surface', {}, pageBlockId);
|
|
||||||
const frameId = page.addBlock('affine:note', {}, pageBlockId);
|
|
||||||
page.addBlock('affine:paragraph', {}, frameId);
|
|
||||||
page.resetHistory();
|
|
||||||
return {
|
|
||||||
pageBlockId,
|
|
||||||
frameId,
|
|
||||||
} as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockUser = {
|
|
||||||
name: faker.name.fullName(),
|
|
||||||
email: faker.internet.email(),
|
|
||||||
password: faker.internet.password(),
|
|
||||||
};
|
|
||||||
|
|
||||||
async function waitForConnected(provider: KeckProvider) {
|
|
||||||
return new Promise<void>(resolve => {
|
|
||||||
provider.once('status', ({ status }: any) => {
|
|
||||||
expect(status).toBe('connected');
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// create a new user for each test, so that each test can be run independently
|
|
||||||
mockUser.name = faker.name.fullName();
|
|
||||||
mockUser.email = faker.internet.email();
|
|
||||||
mockUser.password = faker.internet.password();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
affineAuth = createAffineAuth('http://127.0.0.1:3000/');
|
|
||||||
userApis = createUserApis('http://127.0.0.1:3000/');
|
|
||||||
workspaceApis = createWorkspaceApis('http://127.0.0.1:3000/');
|
|
||||||
statusApis = createStatusApis('http://127.0.0.1:3000/');
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
expect(await statusApis.healthz(), 'health check').toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
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: 'DebugCreateUser',
|
|
||||||
...mockUser,
|
|
||||||
}),
|
|
||||||
}).then(r => r.json());
|
|
||||||
setLoginStorage(data);
|
|
||||||
loginResponseSchema.parse(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface DocumentEventMap {
|
|
||||||
'affine-error': CustomEvent<{
|
|
||||||
code: (typeof MessageCode)[keyof typeof MessageCode];
|
|
||||||
}>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createWorkspace(
|
|
||||||
workspaceApi: typeof workspaceApis,
|
|
||||||
callback?: (workspace: Workspace) => Promise<void>
|
|
||||||
): Promise<string> {
|
|
||||||
const workspace = createEmptyBlockSuiteWorkspace(
|
|
||||||
faker.datatype.uuid(),
|
|
||||||
WorkspaceFlavour.LOCAL
|
|
||||||
);
|
|
||||||
if (callback) {
|
|
||||||
await callback(workspace);
|
|
||||||
}
|
|
||||||
const binary = Workspace.Y.encodeStateAsUpdate(workspace.doc);
|
|
||||||
const data = await workspaceApi.createWorkspace(binary);
|
|
||||||
createWorkspaceResponseSchema.parse(data);
|
|
||||||
return data.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('api', () => {
|
|
||||||
test('built-in mock user', 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);
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('failed', async () => {
|
|
||||||
workspaceApis = createWorkspaceApis('http://127.0.0.1:10086/404/');
|
|
||||||
const listener = vi.fn(
|
|
||||||
(
|
|
||||||
e: CustomEvent<{
|
|
||||||
code: (typeof MessageCode)[keyof typeof MessageCode];
|
|
||||||
}>
|
|
||||||
) => {
|
|
||||||
expect(e.detail.code).toBe(MessageCode.loadListFailed);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
document.addEventListener('affine-error', listener);
|
|
||||||
expect(listener).toBeCalledTimes(0);
|
|
||||||
await workspaceApis.getWorkspaces().catch(e => {
|
|
||||||
expect(e).toBeInstanceOf(RequestError);
|
|
||||||
});
|
|
||||||
expect(listener).toBeCalledTimes(1);
|
|
||||||
document.removeEventListener('affine-error', listener);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('no permission', async () => {
|
|
||||||
await workspaceApis.downloadWorkspace('not-exist').catch(e => {
|
|
||||||
expect(e).toBeInstanceOf(RequestError);
|
|
||||||
expect(e.code).toBe(MessageCode.noPermission);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('blob too large', async () => {
|
|
||||||
await workspaceApis
|
|
||||||
.uploadBlob('test', new ArrayBuffer(1024 * 1024 * 1024 + 1), 'image/png')
|
|
||||||
.catch(e => {
|
|
||||||
expect(e).toBeInstanceOf(RequestError);
|
|
||||||
expect(e.code).toBe(MessageCode.blobTooLarge);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('refresh token', async () => {
|
|
||||||
const storage = getLoginStorage();
|
|
||||||
assertExists(storage);
|
|
||||||
loginResponseSchema.parse(await affineAuth.refreshToken(storage));
|
|
||||||
});
|
|
||||||
|
|
||||||
test(
|
|
||||||
'create workspace',
|
|
||||||
async () => {
|
|
||||||
const id = await createWorkspace(workspaceApis);
|
|
||||||
expect(id).toBeTypeOf('string');
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: 30000,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
'delete workspace',
|
|
||||||
async () => {
|
|
||||||
const id = await createWorkspace(workspaceApis);
|
|
||||||
const response = await workspaceApis.deleteWorkspace({
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
expect(response).toBe(true);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: 30000,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
test('get workspaces', async () => {
|
|
||||||
const id = await createWorkspace(workspaceApis);
|
|
||||||
const response = await workspaceApis.getWorkspaces();
|
|
||||||
expect(response).toBeInstanceOf(Array);
|
|
||||||
expect(response.length).toBe(1);
|
|
||||||
expect(response[0].id).toBe(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
test(
|
|
||||||
'blob',
|
|
||||||
async () => {
|
|
||||||
const workspace = new Workspace({
|
|
||||||
id: 'test',
|
|
||||||
});
|
|
||||||
const path = require.resolve('@affine-test/fixtures/smile.png');
|
|
||||||
const imageBuffer = await readFile(path);
|
|
||||||
const binary = Workspace.Y.encodeStateAsUpdate(workspace.doc);
|
|
||||||
const data = await workspaceApis.createWorkspace(binary);
|
|
||||||
createWorkspaceResponseSchema.parse(data);
|
|
||||||
const workspaceId = data.id;
|
|
||||||
const blobId = await workspaceApis.uploadBlob(
|
|
||||||
workspaceId,
|
|
||||||
imageBuffer,
|
|
||||||
'image/png'
|
|
||||||
);
|
|
||||||
expect(blobId).toBeTypeOf('string');
|
|
||||||
const arrayBuffer = await workspaceApis.getBlob(workspaceId, blobId);
|
|
||||||
expect(arrayBuffer).toBeInstanceOf(ArrayBuffer);
|
|
||||||
expect(arrayBuffer.byteLength).toEqual(imageBuffer.byteLength);
|
|
||||||
expect(Buffer.from(arrayBuffer)).toEqual(imageBuffer);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: 30000,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
'workspace binary',
|
|
||||||
async () => {
|
|
||||||
const id = await createWorkspace(workspaceApis);
|
|
||||||
await workspaceApis.updateWorkspace({
|
|
||||||
id,
|
|
||||||
public: true,
|
|
||||||
});
|
|
||||||
const binary = await workspaceApis.downloadWorkspace(id, false);
|
|
||||||
const publicBinary = await workspaceApis.downloadWorkspace(id, true);
|
|
||||||
expect(binary).toBeInstanceOf(ArrayBuffer);
|
|
||||||
expect(publicBinary).toBeInstanceOf(ArrayBuffer);
|
|
||||||
expect(binary).toEqual(publicBinary);
|
|
||||||
expect(binary.byteLength).toEqual(publicBinary.byteLength);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: 30000,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
test.fails('workspace page binary', async () => {
|
|
||||||
const id = await createWorkspace(workspaceApis, async workspace => {
|
|
||||||
{
|
|
||||||
const page = workspace.createPage('page0');
|
|
||||||
const { frameId } = await initPage(page);
|
|
||||||
page.addBlock(
|
|
||||||
'affine:paragraph',
|
|
||||||
{
|
|
||||||
text: new page.Text('This is page0'),
|
|
||||||
},
|
|
||||||
frameId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const page = workspace.createPage('page1');
|
|
||||||
const { frameId } = await initPage(page);
|
|
||||||
page.addBlock(
|
|
||||||
'affine:paragraph',
|
|
||||||
{
|
|
||||||
text: new page.Text('This is page1'),
|
|
||||||
},
|
|
||||||
frameId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await workspaceApis.updateWorkspace({
|
|
||||||
id,
|
|
||||||
public: true,
|
|
||||||
});
|
|
||||||
let originalPage0Json: any = null;
|
|
||||||
let originalPage1Json: any = null;
|
|
||||||
{
|
|
||||||
const binary = await workspaceApis.downloadWorkspace(id, false);
|
|
||||||
const workspace = new Workspace({
|
|
||||||
id: faker.datatype.uuid(),
|
|
||||||
})
|
|
||||||
.register(AffineSchemas)
|
|
||||||
.register(__unstableSchemas);
|
|
||||||
applyUpdate(workspace.doc, new Uint8Array(binary));
|
|
||||||
const page0 = workspace.getPage('page0') as Page;
|
|
||||||
const page1 = workspace.getPage('page1') as Page;
|
|
||||||
expect(page0).not.toBeUndefined();
|
|
||||||
expect(page1).not.toBeUndefined();
|
|
||||||
originalPage0Json = workspace.doc.share.get(page0.prefixedId)?.toJSON();
|
|
||||||
originalPage1Json = workspace.doc.share.get(page1.prefixedId)?.toJSON();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const workspace = new Workspace({
|
|
||||||
id: faker.datatype.uuid(),
|
|
||||||
})
|
|
||||||
.register(AffineSchemas)
|
|
||||||
.register(__unstableSchemas);
|
|
||||||
const binary = await workspaceApis.downloadPublicWorkspacePage(
|
|
||||||
id,
|
|
||||||
'page0'
|
|
||||||
);
|
|
||||||
applyUpdate(workspace.doc, new Uint8Array(binary));
|
|
||||||
const page0 = workspace.getPage('page0') as Page;
|
|
||||||
expect(page0).not.toBeNull();
|
|
||||||
expect(workspace.getPage('page1')).toBeNull();
|
|
||||||
expect(workspace.doc.share.get(page0.prefixedId)?.toJSON()).toEqual(
|
|
||||||
originalPage0Json
|
|
||||||
);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const workspace = new Workspace({
|
|
||||||
id: faker.datatype.uuid(),
|
|
||||||
})
|
|
||||||
.register(AffineSchemas)
|
|
||||||
.register(__unstableSchemas);
|
|
||||||
const binary = await workspaceApis.downloadPublicWorkspacePage(
|
|
||||||
id,
|
|
||||||
'page1'
|
|
||||||
);
|
|
||||||
applyUpdate(workspace.doc, new Uint8Array(binary));
|
|
||||||
const page1 = workspace.getPage('page1') as Page;
|
|
||||||
expect(workspace.getPage('page0')).toBeNull();
|
|
||||||
expect(page1).not.toBeNull();
|
|
||||||
expect(workspace.doc.share.get(page1.prefixedId)?.toJSON()).toEqual(
|
|
||||||
originalPage1Json
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test(
|
|
||||||
'usage',
|
|
||||||
async () => {
|
|
||||||
const usageResponse = await userApis.getUsage();
|
|
||||||
usageResponseSchema.parse(usageResponse);
|
|
||||||
const id = await createWorkspace(workspaceApis);
|
|
||||||
const path = require.resolve('@affine-test/fixtures/smile.png');
|
|
||||||
const imageBuffer = await readFile(path);
|
|
||||||
const blobId = await workspaceApis.uploadBlob(
|
|
||||||
id,
|
|
||||||
imageBuffer,
|
|
||||||
'image/png'
|
|
||||||
);
|
|
||||||
const buffer = await workspaceApis.getBlob(id, blobId);
|
|
||||||
expect(buffer.byteLength).toEqual(imageBuffer.byteLength);
|
|
||||||
const newUsageResponse = await userApis.getUsage();
|
|
||||||
usageResponseSchema.parse(newUsageResponse);
|
|
||||||
expect(usageResponse.blob_usage.usage).not.equals(
|
|
||||||
newUsageResponse.blob_usage.usage
|
|
||||||
);
|
|
||||||
expect(newUsageResponse.blob_usage.usage).equals(96);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: 30000,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
test.fails(
|
|
||||||
'public page',
|
|
||||||
async () => {
|
|
||||||
const id = await createWorkspace(workspaceApis, async workspace => {
|
|
||||||
const page = workspace.createPage('page0');
|
|
||||||
const { frameId } = await initPage(page);
|
|
||||||
page.addBlock(
|
|
||||||
'affine:paragraph',
|
|
||||||
{
|
|
||||||
text: new page.Text('This is page0'),
|
|
||||||
},
|
|
||||||
frameId
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const binary = await workspaceApis.downloadWorkspace(id, false);
|
|
||||||
const workspace = createEmptyBlockSuiteWorkspace(
|
|
||||||
id,
|
|
||||||
WorkspaceFlavour.LOCAL
|
|
||||||
);
|
|
||||||
Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(binary));
|
|
||||||
const workspace2 = createEmptyBlockSuiteWorkspace(
|
|
||||||
id,
|
|
||||||
WorkspaceFlavour.LOCAL
|
|
||||||
);
|
|
||||||
{
|
|
||||||
const wsUrl = `ws://127.0.0.1:3000/api/sync/`;
|
|
||||||
const provider = new KeckProvider(wsUrl, workspace.id, workspace.doc, {
|
|
||||||
params: { token: getLoginStorage()?.token },
|
|
||||||
awareness: workspace.awarenessStore.awareness,
|
|
||||||
connect: false,
|
|
||||||
});
|
|
||||||
const provider2 = new KeckProvider(
|
|
||||||
wsUrl,
|
|
||||||
workspace2.id,
|
|
||||||
workspace2.doc,
|
|
||||||
{
|
|
||||||
params: { token: getLoginStorage()?.token },
|
|
||||||
awareness: workspace2.awarenessStore.awareness,
|
|
||||||
connect: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
provider.connect();
|
|
||||||
provider2.connect();
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
await waitForConnected(provider),
|
|
||||||
await waitForConnected(provider2),
|
|
||||||
]);
|
|
||||||
const pageId = 'page0';
|
|
||||||
const page = workspace.getPage(pageId) as Page;
|
|
||||||
expect(page).not.toBeNull();
|
|
||||||
expect(page).not.toBeUndefined();
|
|
||||||
workspace.setPageMeta(pageId, {
|
|
||||||
isPublic: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
|
|
||||||
const page2 = workspace2.getPage(pageId) as Page;
|
|
||||||
expect(page2).not.toBeNull();
|
|
||||||
const meta = workspace2.meta.getPageMeta(pageId) as PageMeta;
|
|
||||||
expect(meta.isPublic).toBe(true);
|
|
||||||
|
|
||||||
const binary = await workspaceApis.downloadPublicWorkspacePage(
|
|
||||||
id,
|
|
||||||
pageId
|
|
||||||
);
|
|
||||||
const publicWorkspace = createEmptyBlockSuiteWorkspace(
|
|
||||||
id,
|
|
||||||
WorkspaceFlavour.LOCAL
|
|
||||||
);
|
|
||||||
Workspace.Y.applyUpdate(publicWorkspace.doc, new Uint8Array(binary));
|
|
||||||
const publicPage = publicWorkspace.getPage(pageId) as Page;
|
|
||||||
expect(publicPage).not.toBeNull();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: 30000,
|
|
||||||
retry: 3,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
@ -1,20 +0,0 @@
|
|||||||
import { getDefaultStore } from 'jotai';
|
|
||||||
import { describe, expect, test } from 'vitest';
|
|
||||||
|
|
||||||
import { currentAffineUserAtom } from '../atom';
|
|
||||||
|
|
||||||
describe('atom', () => {
|
|
||||||
test('currentAffineUserAtom', () => {
|
|
||||||
const store = getDefaultStore();
|
|
||||||
const mock = {
|
|
||||||
created_at: 0,
|
|
||||||
exp: 0,
|
|
||||||
email: '',
|
|
||||||
id: '',
|
|
||||||
name: '',
|
|
||||||
avatar_url: '',
|
|
||||||
};
|
|
||||||
store.set(currentAffineUserAtom, mock);
|
|
||||||
expect(store.get(currentAffineUserAtom)).toEqual(mock);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* @vitest-environment happy-dom
|
|
||||||
*/
|
|
||||||
import { describe, expect, test } from 'vitest';
|
|
||||||
|
|
||||||
import type { AccessTokenMessage } from '../login';
|
|
||||||
import {
|
|
||||||
getLoginStorage,
|
|
||||||
isExpired,
|
|
||||||
setLoginStorage,
|
|
||||||
STORAGE_KEY,
|
|
||||||
} from '../login';
|
|
||||||
|
|
||||||
describe('storage', () => {
|
|
||||||
test('should work', () => {
|
|
||||||
setLoginStorage({
|
|
||||||
token: '1',
|
|
||||||
refresh: '2',
|
|
||||||
});
|
|
||||||
const data = localStorage.getItem(STORAGE_KEY);
|
|
||||||
expect(data).toBe('{"token":"1","refresh":"2"}');
|
|
||||||
const login = getLoginStorage();
|
|
||||||
expect(login).toEqual({
|
|
||||||
token: '1',
|
|
||||||
refresh: '2',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('utils', () => {
|
|
||||||
test('isExpired', async () => {
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
|
||||||
expect(isExpired({ exp: now + 1 } as AccessTokenMessage, 0)).toBeFalsy();
|
|
||||||
const promise = new Promise<void>(resolve => {
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(
|
|
||||||
isExpired({ exp: now + 1 } as AccessTokenMessage, 0)
|
|
||||||
).toBeTruthy();
|
|
||||||
resolve();
|
|
||||||
}, 2000);
|
|
||||||
});
|
|
||||||
expect(isExpired({ exp: now - 1 } as AccessTokenMessage, 0)).toBeTruthy();
|
|
||||||
await promise;
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,184 +0,0 @@
|
|||||||
/**
|
|
||||||
* @vitest-environment happy-dom
|
|
||||||
*/
|
|
||||||
import 'fake-indexeddb/auto';
|
|
||||||
|
|
||||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
|
||||||
import type { Workspace } from '@affine/env/workspace/legacy-cloud';
|
|
||||||
import { PermissionType } from '@affine/env/workspace/legacy-cloud';
|
|
||||||
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';
|
|
||||||
|
|
||||||
import type { LoginResponse } from '../../affine/login';
|
|
||||||
import { loginResponseSchema } from '../../affine/login';
|
|
||||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
|
||||||
import { createWorkspaceApis } from '../api';
|
|
||||||
import { KeckProvider } from '../keck';
|
|
||||||
|
|
||||||
declare module '@blocksuite/store' {
|
|
||||||
interface PageMeta {
|
|
||||||
foo: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-expect-error
|
|
||||||
globalThis.WebSocket = WebSocket;
|
|
||||||
|
|
||||||
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,
|
|
||||||
WorkspaceFlavour.AFFINE,
|
|
||||||
{
|
|
||||||
workspaceApis,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const workspace2 = createEmptyBlockSuiteWorkspace(
|
|
||||||
root.id,
|
|
||||||
WorkspaceFlavour.AFFINE,
|
|
||||||
{
|
|
||||||
workspaceApis,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
BlockSuiteWorkspace.Y.applyUpdate(workspace1.doc, new Uint8Array(binary));
|
|
||||||
BlockSuiteWorkspace.Y.applyUpdate(workspace2.doc, new Uint8Array(binary));
|
|
||||||
const provider1 = new KeckProvider(wsUrl, workspace1.id, workspace1.doc, {
|
|
||||||
params: { token: user1Token.token },
|
|
||||||
awareness: workspace1.awarenessStore.awareness,
|
|
||||||
// @ts-expect-error
|
|
||||||
disableBc: true,
|
|
||||||
connect: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const provider2 = new KeckProvider(wsUrl, workspace2.id, workspace2.doc, {
|
|
||||||
params: { token: user2Token.token },
|
|
||||||
awareness: workspace2.awarenessStore.awareness,
|
|
||||||
// @ts-expect-error
|
|
||||||
disableBc: true,
|
|
||||||
connect: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
provider1.connect();
|
|
||||||
provider2.connect();
|
|
||||||
|
|
||||||
function waitForConnected(provider: KeckProvider) {
|
|
||||||
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({ id: pageId });
|
|
||||||
await page1.waitForLoaded();
|
|
||||||
const pageBlockId = page1.addBlock('affine:page', {
|
|
||||||
title: new page1.Text(''),
|
|
||||||
});
|
|
||||||
page1.addBlock('affine:surface', {}, pageBlockId);
|
|
||||||
const frameId = page1.addBlock('affine:note', {}, 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;
|
|
||||||
await page2.waitForLoaded();
|
|
||||||
page1.updateBlock(
|
|
||||||
page1.getBlockById(paragraphId) as ParagraphBlockModel,
|
|
||||||
{
|
|
||||||
text: new page1.Text('hello world'),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
workspace1.meta.setPageMeta(pageId, {
|
|
||||||
foo: 'bar',
|
|
||||||
});
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
const pageMeta = workspace2.meta.getPageMeta(pageId);
|
|
||||||
expect(pageMeta).toBeDefined();
|
|
||||||
expect(pageMeta?.foo).toBe('bar');
|
|
||||||
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,
|
|
||||||
retry: 3,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user