test(server): use mocker (#12435)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **Tests**
  - Refactored test setup for the database-backed document reader to improve modularity and clarity.
  - Simplified database initialization and cleanup in tests.
  - Updated mocks and assertions to align with the new test structure.
  - Maintained existing test coverage and logic.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
fengmk2
2025-05-22 04:25:20 +00:00
parent 573c2faf76
commit c525ca24fd

View File

@@ -1,67 +1,54 @@
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
import { mock } from 'node:test'; import { mock } from 'node:test';
import { User, Workspace } from '@prisma/client'; import test from 'ava';
import ava, { TestFn } from 'ava';
import { applyUpdate, Doc as YDoc } from 'yjs'; import { applyUpdate, Doc as YDoc } from 'yjs';
import { createTestingApp, type TestingApp } from '../../../__tests__/utils'; import { createModule } from '../../../__tests__/create-module';
import { Mockers } from '../../../__tests__/mocks';
import { Models } from '../../../models'; import { Models } from '../../../models';
import { WorkspaceBlobStorage } from '../../storage/wrappers/blob'; import { DocReader, DocStorageModule, PgWorkspaceDocStorageAdapter } from '..';
import { DocReader, PgWorkspaceDocStorageAdapter } from '..';
import { DatabaseDocReader } from '../reader'; import { DatabaseDocReader } from '../reader';
const test = ava as TestFn<{ const module = await createModule({
models: Models; imports: [DocStorageModule],
app: TestingApp;
docReader: DocReader;
adapter: PgWorkspaceDocStorageAdapter;
blobStorage: WorkspaceBlobStorage;
}>;
test.before(async t => {
const app = await createTestingApp();
t.context.models = app.get(Models);
t.context.docReader = app.get(DocReader);
t.context.adapter = app.get(PgWorkspaceDocStorageAdapter);
t.context.blobStorage = app.get(WorkspaceBlobStorage);
t.context.app = app;
}); });
const docReader = module.get(DocReader);
const adapter = module.get(PgWorkspaceDocStorageAdapter);
const models = module.get(Models);
let user: User; const user = await module.create(Mockers.User);
let workspace: Workspace;
test.beforeEach(async t => {
await t.context.app.initTestingDB();
user = await t.context.models.user.create({
email: 'test@affine.pro',
});
workspace = await t.context.models.workspace.create(user.id);
});
test.afterEach.always(() => { test.afterEach.always(() => {
mock.reset(); mock.reset();
}); });
test.after.always(async t => { test.after.always(async () => {
await t.context.app.close(); await module.close();
});
test('should be database reader', async t => {
t.true(docReader instanceof DatabaseDocReader);
}); });
test('should return null when doc not found', async t => { test('should return null when doc not found', async t => {
const { docReader } = t.context; const workspace = await module.create(Mockers.Workspace, {
owner: user,
});
const docId = randomUUID(); const docId = randomUUID();
const doc = await docReader.getDoc(workspace.id, docId); const doc = await docReader.getDoc(workspace.id, docId);
t.is(doc, null); t.is(doc, null);
}); });
test('should return doc when found', async t => { test('should return doc when found', async t => {
const { docReader } = t.context; const workspace = await module.create(Mockers.Workspace, {
t.true(docReader instanceof DatabaseDocReader); owner: user,
});
const docId = randomUUID(); const docId = randomUUID();
const timestamp = Date.now(); const timestamp = Date.now();
await t.context.models.doc.createUpdates([ await models.doc.createUpdates([
{ {
spaceId: workspace.id, spaceId: workspace.id,
docId, docId,
@@ -79,7 +66,10 @@ test('should return doc when found', async t => {
}); });
test('should return doc diff', async t => { test('should return doc diff', async t => {
const { docReader } = t.context; const workspace = await module.create(Mockers.Workspace, {
owner: user,
});
const docId = randomUUID(); const docId = randomUUID();
const timestamp = Date.now(); const timestamp = Date.now();
let updates: Buffer[] = []; let updates: Buffer[] = [];
@@ -94,7 +84,7 @@ test('should return doc diff', async t => {
text.insert(5, ' '); text.insert(5, ' ');
text.insert(11, '!'); text.insert(11, '!');
await t.context.models.doc.createUpdates( await models.doc.createUpdates(
updates.map((update, index) => ({ updates.map((update, index) => ({
spaceId: workspace.id, spaceId: workspace.id,
docId, docId,
@@ -108,6 +98,7 @@ test('should return doc diff', async t => {
const doc2 = new YDoc(); const doc2 = new YDoc();
const diff = await docReader.getDocDiff(workspace.id, docId); const diff = await docReader.getDocDiff(workspace.id, docId);
t.truthy(diff); t.truthy(diff);
t.truthy(diff!.missing); t.truthy(diff!.missing);
t.truthy(diff!.state); t.truthy(diff!.state);
@@ -116,6 +107,7 @@ test('should return doc diff', async t => {
// nothing changed // nothing changed
const diff2 = await docReader.getDocDiff(workspace.id, docId, diff!.state); const diff2 = await docReader.getDocDiff(workspace.id, docId, diff!.state);
t.truthy(diff2); t.truthy(diff2);
t.truthy(diff2!.missing); t.truthy(diff2!.missing);
t.deepEqual(diff2!.missing, new Uint8Array([0, 0])); t.deepEqual(diff2!.missing, new Uint8Array([0, 0]));
@@ -125,7 +117,7 @@ test('should return doc diff', async t => {
// add new content on doc1 // add new content on doc1
text.insert(12, '@'); text.insert(12, '@');
await t.context.models.doc.createUpdates( await models.doc.createUpdates(
updates.map((update, index) => ({ updates.map((update, index) => ({
spaceId: workspace.id, spaceId: workspace.id,
docId, docId,
@@ -136,6 +128,7 @@ test('should return doc diff', async t => {
); );
const diff3 = await docReader.getDocDiff(workspace.id, docId, diff2!.state); const diff3 = await docReader.getDocDiff(workspace.id, docId, diff2!.state);
t.truthy(diff3); t.truthy(diff3);
t.truthy(diff3!.missing); t.truthy(diff3!.missing);
t.truthy(diff3!.state); t.truthy(diff3!.state);
@@ -144,8 +137,11 @@ test('should return doc diff', async t => {
}); });
test('should get doc content', async t => { test('should get doc content', async t => {
const workspace = await module.create(Mockers.Workspace, {
owner: user,
});
const docId = randomUUID(); const docId = randomUUID();
const { docReader } = t.context;
const doc = new YDoc(); const doc = new YDoc();
const text = doc.getText('content'); const text = doc.getText('content');
@@ -159,16 +155,19 @@ test('should get doc content', async t => {
text.insert(5, 'world'); text.insert(5, 'world');
text.insert(5, ' '); text.insert(5, ' ');
await t.context.adapter.pushDocUpdates(workspace.id, docId, updates, user.id); await adapter.pushDocUpdates(workspace.id, docId, updates, user.id);
const docContent = await docReader.getDocContent(workspace.id, docId); const docContent = await docReader.getDocContent(workspace.id, docId);
// TODO(@fengmk2): should create a test ydoc with blocks // TODO(@fengmk2): should create a test ydoc with blocks
t.is(docContent, null); t.is(docContent, null);
}); });
test('should get workspace content with default avatar', async t => { test('should get workspace content with default avatar', async t => {
const { docReader } = t.context; const workspace = await module.create(Mockers.Workspace, {
t.true(docReader instanceof DatabaseDocReader); owner: user,
name: '',
});
const doc = new YDoc(); const doc = new YDoc();
const text = doc.getText('content'); const text = doc.getText('content');
@@ -182,12 +181,7 @@ test('should get workspace content with default avatar', async t => {
text.insert(5, 'world'); text.insert(5, 'world');
text.insert(5, ' '); text.insert(5, ' ');
await t.context.adapter.pushDocUpdates( await adapter.pushDocUpdates(workspace.id, workspace.id, updates, user.id);
workspace.id,
workspace.id,
updates,
user.id
);
mock.method(docReader, 'parseWorkspaceContent', () => ({ mock.method(docReader, 'parseWorkspaceContent', () => ({
name: 'Test Workspace', name: 'Test Workspace',
@@ -195,6 +189,7 @@ test('should get workspace content with default avatar', async t => {
})); }));
const workspaceContent = await docReader.getWorkspaceContent(workspace.id); const workspaceContent = await docReader.getWorkspaceContent(workspace.id);
t.truthy(workspaceContent); t.truthy(workspaceContent);
t.deepEqual(workspaceContent, { t.deepEqual(workspaceContent, {
id: workspace.id, id: workspace.id,
@@ -205,8 +200,10 @@ test('should get workspace content with default avatar', async t => {
}); });
test('should get workspace content with custom avatar', async t => { test('should get workspace content with custom avatar', async t => {
const { docReader, blobStorage } = t.context; const workspace = await module.create(Mockers.Workspace, {
t.true(docReader instanceof DatabaseDocReader); owner: user,
name: '',
});
const doc = new YDoc(); const doc = new YDoc();
const text = doc.getText('content'); const text = doc.getText('content');
@@ -220,19 +217,9 @@ test('should get workspace content with custom avatar', async t => {
text.insert(5, 'world'); text.insert(5, 'world');
text.insert(5, ' '); text.insert(5, ' ');
await t.context.adapter.pushDocUpdates( await adapter.pushDocUpdates(workspace.id, workspace.id, updates, user.id);
workspace.id,
workspace.id,
updates,
user.id
);
const avatarKey = randomUUID(); const avatarKey = randomUUID();
await blobStorage.put(
workspace.id,
avatarKey,
Buffer.from('mock avatar image data here')
);
mock.method(docReader, 'parseWorkspaceContent', () => ({ mock.method(docReader, 'parseWorkspaceContent', () => ({
name: 'Test Workspace', name: 'Test Workspace',
@@ -240,6 +227,7 @@ test('should get workspace content with custom avatar', async t => {
})); }));
const workspaceContent = await docReader.getWorkspaceContent(workspace.id); const workspaceContent = await docReader.getWorkspaceContent(workspace.id);
t.truthy(workspaceContent); t.truthy(workspaceContent);
t.deepEqual(workspaceContent, { t.deepEqual(workspaceContent, {
id: workspace.id, id: workspace.id,
@@ -247,17 +235,20 @@ test('should get workspace content with custom avatar', async t => {
avatarKey, avatarKey,
avatarUrl: `http://localhost:3010/api/workspaces/${workspace.id}/blobs/${avatarKey}`, avatarUrl: `http://localhost:3010/api/workspaces/${workspace.id}/blobs/${avatarKey}`,
}); });
// should save to database // should save to database
const workspace2 = await t.context.models.workspace.get(workspace.id); const workspace2 = await models.workspace.get(workspace.id);
t.truthy(workspace2); t.truthy(workspace2);
t.is(workspace2!.name, 'Test Workspace'); t.is(workspace2!.name, 'Test Workspace');
t.is(workspace2!.avatarKey, avatarKey); t.is(workspace2!.avatarKey, avatarKey);
// read from database // read from database
await t.context.models.workspace.update(workspace.id, { await models.workspace.update(workspace.id, {
name: 'Test Workspace 2', name: 'Test Workspace 2',
}); });
const workspaceContent2 = await docReader.getWorkspaceContent(workspace.id); const workspaceContent2 = await docReader.getWorkspaceContent(workspace.id);
t.truthy(workspaceContent2); t.truthy(workspaceContent2);
t.deepEqual(workspaceContent2, { t.deepEqual(workspaceContent2, {
id: workspace.id, id: workspace.id,