Skip to content
5 changes: 3 additions & 2 deletions packages/collaboration-manager/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ export default {
tsconfig: '<rootDir>/tsconfig.test.json',
},
},
testMatch: [ '<rootDir>/src/**/*.spec.ts' ],
modulePathIgnorePatterns: [ '<rootDir>/.*/__mocks__', '<rootDir>/.*/mocks' ],
testMatch: ['<rootDir>/src/**/*.spec.ts'],
modulePathIgnorePatterns: ['<rootDir>/.*/__mocks__', '<rootDir>/.*/mocks'],
extensionsToTreatAsEsm: ['.ts'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
'^codex-tooltip$': '<rootDir>/test/mocks/codex-tooltip.ts',
},
transform: {
...createDefaultEsmPreset().transform,
Expand Down
106 changes: 71 additions & 35 deletions packages/collaboration-manager/src/CollaborationManager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/no-magic-numbers */
import { createDataKey, IndexBuilder } from '@editorjs/model';
import { createDataKey, EventType, IndexBuilder } from '@editorjs/model';
import { EditorJSModel } from '@editorjs/model';
import type { CoreConfig } from '@editorjs/sdk';
import { CoreEventType, type CoreConfig } from '@editorjs/sdk';
import { beforeAll, jest } from '@jest/globals';
import { BatchedOperation } from './BatchedOperation.js';
import { CollaborationManager } from './CollaborationManager.js';
import { Operation, OperationType } from './Operation.js';
import { UndoRedoManager } from './UndoRedoManager.js';
import { createManager } from '../test/mocks/createManager.js';
import { OTClient } from './client/index.js';

const userId = 'user';
const remoteUserId = 'remote-user';
Expand All @@ -31,7 +32,7 @@ describe('CollaborationManager', () => {
it('should throw an error on unknown operation type', () => {
const model = new EditorJSModel(userId, { identifier: documentId });

const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;

// @ts-expect-error - for test purposes
expect(() => collaborationManager.applyOperation(new Operation('unknown', new IndexBuilder().build(), 'hello'))).toThrow('Unknown operation type');
Expand All @@ -51,7 +52,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 4])
Expand Down Expand Up @@ -92,7 +93,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([3, 5])
Expand Down Expand Up @@ -125,7 +126,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Insert, index, {
Expand Down Expand Up @@ -173,7 +174,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [block],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Delete, index, {
Expand Down Expand Up @@ -202,7 +203,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 5])
Expand Down Expand Up @@ -249,7 +250,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 5])
Expand Down Expand Up @@ -279,7 +280,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const op1 = new Operation(OperationType.Insert, new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 0])
Expand Down Expand Up @@ -329,7 +330,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 3])
Expand Down Expand Up @@ -382,7 +383,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 4])
Expand Down Expand Up @@ -424,7 +425,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([
Expand Down Expand Up @@ -467,7 +468,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 4])
Expand Down Expand Up @@ -510,7 +511,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 4])
Expand Down Expand Up @@ -546,7 +547,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Insert, index, {
Expand Down Expand Up @@ -586,7 +587,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 5])
Expand Down Expand Up @@ -636,7 +637,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 3])
Expand Down Expand Up @@ -689,7 +690,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 3])
Expand Down Expand Up @@ -742,7 +743,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [block],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Delete, index, {
Expand Down Expand Up @@ -778,7 +779,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [block],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Delete, index, {
Expand Down Expand Up @@ -817,7 +818,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [block],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Delete, index, {
Expand Down Expand Up @@ -859,7 +860,7 @@ describe('CollaborationManager', () => {
model.initializeDocument({
blocks: [block],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index = new IndexBuilder().addBlockIndex(0)
.build();
const operation = new Operation(OperationType.Delete, index, {
Expand Down Expand Up @@ -900,7 +901,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index1 = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 0])
Expand Down Expand Up @@ -952,7 +953,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const index1 = new IndexBuilder().addBlockIndex(0)
.addDataKey(createDataKey('text'))
.addTextRange([0, 0])
Expand Down Expand Up @@ -1005,7 +1006,7 @@ describe('CollaborationManager', () => {
},
}],
});
const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;

model.insertText('another-user', 0, createDataKey('text'), 'hello', 0);

Expand Down Expand Up @@ -1045,7 +1046,7 @@ describe('CollaborationManager', () => {
},
}],
});
void new CollaborationManager(config as Required<CoreConfig>, model);
createManager(config as Required<CoreConfig>, model);

model.insertText(userId, 0, createDataKey('text'), 'a', 0);

Expand Down Expand Up @@ -1076,7 +1077,7 @@ describe('CollaborationManager', () => {
}],
});

const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;

// Create local operation
const localIndex = new IndexBuilder().addBlockIndex(0)
Expand Down Expand Up @@ -1135,7 +1136,7 @@ describe('CollaborationManager', () => {
}],
});

const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;

model.insertText(userId, 0, createDataKey('text'), 'world', 0);
jest.advanceTimersByTime(500);
Expand Down Expand Up @@ -1176,8 +1177,8 @@ describe('CollaborationManager', () => {
}],
});

const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const remoteCollaborationManager = new CollaborationManager(remoteConfig as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const remoteCollaborationManager = createManager(remoteConfig as Required<CoreConfig>, model).manager;

// Char-by-char insert text 'hello' from local user
const localText = 'hello';
Expand Down Expand Up @@ -1244,8 +1245,8 @@ describe('CollaborationManager', () => {
}],
});

const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const remoteCollaborationManager = new CollaborationManager(remoteConfig as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;
const remoteCollaborationManager = createManager(remoteConfig as Required<CoreConfig>, model).manager;

// Isert line 'hello' from local user
const localIndex = new IndexBuilder().addBlockIndex(0)
Expand Down Expand Up @@ -1305,7 +1306,7 @@ describe('CollaborationManager', () => {
}],
});

const collaborationManager = new CollaborationManager(config as Required<CoreConfig>, model);
const collaborationManager = createManager(config as Required<CoreConfig>, model).manager;

// Create local delete operation
const localIndex = new IndexBuilder().addBlockIndex(0)
Expand Down Expand Up @@ -1342,4 +1343,39 @@ describe('CollaborationManager', () => {
});
});
});

describe('destroy', () => {
it('should unsubscribe model and core event listeners', () => {
const model = new EditorJSModel(userId, { identifier: documentId });
const removeModelListenerSpy = jest.spyOn(model, 'removeEventListener');
const { manager, eventBus } = createManager(config as Required<CoreConfig>, model);
const removeEventBusListenerSpy = jest.spyOn(eventBus, 'removeEventListener');

manager.destroy();

expect(removeModelListenerSpy).toHaveBeenCalledWith(EventType.Changed, expect.any(Function));
expect(removeEventBusListenerSpy).toHaveBeenCalledWith(`core:${CoreEventType.Undo}`, expect.any(Function));
expect(removeEventBusListenerSpy).toHaveBeenCalledWith(`core:${CoreEventType.Redo}`, expect.any(Function));
expect(removeEventBusListenerSpy).toHaveBeenCalledWith(`core:${CoreEventType.Ready}`, expect.any(Function));
});

it('should close ot client connection', async () => {
const model = new EditorJSModel(userId, { identifier: documentId });
const { manager, eventBus } = createManager({
...config,
collaborationServer: 'ws://test-collab.invalid/document',
} as Required<CoreConfig>, model);

eventBus.dispatchEvent(new CustomEvent(`core:${CoreEventType.Ready}`));
await Promise.resolve();

const closeSpy = jest.spyOn(OTClient.prototype, 'close');

manager.destroy();
await Promise.resolve();

expect(closeSpy).toHaveBeenCalledTimes(1);
closeSpy.mockRestore();
});
});
});
Loading
Loading