summaryrefslogtreecommitdiff
path: root/spec/frontend/ide/lib/diff/controller_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ide/lib/diff/controller_spec.js')
-rw-r--r--spec/frontend/ide/lib/diff/controller_spec.js215
1 files changed, 215 insertions, 0 deletions
diff --git a/spec/frontend/ide/lib/diff/controller_spec.js b/spec/frontend/ide/lib/diff/controller_spec.js
new file mode 100644
index 00000000000..0b33a4c6ad6
--- /dev/null
+++ b/spec/frontend/ide/lib/diff/controller_spec.js
@@ -0,0 +1,215 @@
+import { Range } from 'monaco-editor';
+import Editor from '~/ide/lib/editor';
+import ModelManager from '~/ide/lib/common/model_manager';
+import DecorationsController from '~/ide/lib/decorations/controller';
+import DirtyDiffController, { getDiffChangeType, getDecorator } from '~/ide/lib/diff/controller';
+import { computeDiff } from '~/ide/lib/diff/diff';
+import { file } from '../../helpers';
+
+describe('Multi-file editor library dirty diff controller', () => {
+ let editorInstance;
+ let controller;
+ let modelManager;
+ let decorationsController;
+ let model;
+
+ beforeEach(() => {
+ editorInstance = Editor.create();
+ editorInstance.createInstance(document.createElement('div'));
+
+ modelManager = new ModelManager();
+ decorationsController = new DecorationsController(editorInstance);
+
+ model = modelManager.addModel(file('path'));
+
+ controller = new DirtyDiffController(modelManager, decorationsController);
+ });
+
+ afterEach(() => {
+ controller.dispose();
+ model.dispose();
+ decorationsController.dispose();
+ editorInstance.dispose();
+ });
+
+ describe('getDiffChangeType', () => {
+ ['added', 'removed', 'modified'].forEach(type => {
+ it(`returns ${type}`, () => {
+ const change = {
+ [type]: true,
+ };
+
+ expect(getDiffChangeType(change)).toBe(type);
+ });
+ });
+ });
+
+ describe('getDecorator', () => {
+ ['added', 'removed', 'modified'].forEach(type => {
+ it(`returns with linesDecorationsClassName for ${type}`, () => {
+ const change = {
+ [type]: true,
+ };
+
+ expect(getDecorator(change).options.linesDecorationsClassName).toBe(
+ `dirty-diff dirty-diff-${type}`,
+ );
+ });
+
+ it('returns with line numbers', () => {
+ const change = {
+ lineNumber: 1,
+ endLineNumber: 2,
+ [type]: true,
+ };
+
+ const { range } = getDecorator(change);
+
+ expect(range.startLineNumber).toBe(1);
+ expect(range.endLineNumber).toBe(2);
+ expect(range.startColumn).toBe(1);
+ expect(range.endColumn).toBe(1);
+ });
+ });
+ });
+
+ describe('attachModel', () => {
+ it('adds change event callback', () => {
+ jest.spyOn(model, 'onChange').mockImplementation(() => {});
+
+ controller.attachModel(model);
+
+ expect(model.onChange).toHaveBeenCalled();
+ });
+
+ it('adds dispose event callback', () => {
+ jest.spyOn(model, 'onDispose').mockImplementation(() => {});
+
+ controller.attachModel(model);
+
+ expect(model.onDispose).toHaveBeenCalled();
+ });
+
+ it('calls throttledComputeDiff on change', () => {
+ jest.spyOn(controller, 'throttledComputeDiff').mockImplementation(() => {});
+
+ controller.attachModel(model);
+
+ model.getModel().setValue('123');
+
+ expect(controller.throttledComputeDiff).toHaveBeenCalled();
+ });
+
+ it('caches model', () => {
+ controller.attachModel(model);
+
+ expect(controller.models.has(model.url)).toBe(true);
+ });
+ });
+
+ describe('computeDiff', () => {
+ it('posts to worker', () => {
+ jest.spyOn(controller.dirtyDiffWorker, 'postMessage').mockImplementation(() => {});
+
+ controller.computeDiff(model);
+
+ expect(controller.dirtyDiffWorker.postMessage).toHaveBeenCalledWith({
+ path: model.path,
+ originalContent: '',
+ newContent: '',
+ });
+ });
+ });
+
+ describe('reDecorate', () => {
+ it('calls computeDiff when no decorations are cached', () => {
+ jest.spyOn(controller, 'computeDiff').mockImplementation(() => {});
+
+ controller.reDecorate(model);
+
+ expect(controller.computeDiff).toHaveBeenCalledWith(model);
+ });
+
+ it('calls decorate when decorations are cached', () => {
+ jest.spyOn(controller.decorationsController, 'decorate').mockImplementation(() => {});
+
+ controller.decorationsController.decorations.set(model.url, 'test');
+
+ controller.reDecorate(model);
+
+ expect(controller.decorationsController.decorate).toHaveBeenCalledWith(model);
+ });
+ });
+
+ describe('decorate', () => {
+ it('adds decorations into decorations controller', () => {
+ jest.spyOn(controller.decorationsController, 'addDecorations').mockImplementation(() => {});
+
+ controller.decorate({ data: { changes: [], path: model.path } });
+
+ expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith(
+ model,
+ 'dirtyDiff',
+ expect.anything(),
+ );
+ });
+
+ it('adds decorations into editor', () => {
+ const spy = jest.spyOn(controller.decorationsController.editor.instance, 'deltaDecorations');
+
+ controller.decorate({
+ data: { changes: computeDiff('123', '1234'), path: model.path },
+ });
+
+ expect(spy).toHaveBeenCalledWith(
+ [],
+ [
+ {
+ range: new Range(1, 1, 1, 1),
+ options: {
+ isWholeLine: true,
+ linesDecorationsClassName: 'dirty-diff dirty-diff-modified',
+ },
+ },
+ ],
+ );
+ });
+ });
+
+ describe('dispose', () => {
+ it('calls disposable dispose', () => {
+ jest.spyOn(controller.disposable, 'dispose');
+
+ controller.dispose();
+
+ expect(controller.disposable.dispose).toHaveBeenCalled();
+ });
+
+ it('terminates worker', () => {
+ jest.spyOn(controller.dirtyDiffWorker, 'terminate');
+
+ controller.dispose();
+
+ expect(controller.dirtyDiffWorker.terminate).toHaveBeenCalled();
+ });
+
+ it('removes worker event listener', () => {
+ jest.spyOn(controller.dirtyDiffWorker, 'removeEventListener');
+
+ controller.dispose();
+
+ expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith(
+ 'message',
+ expect.anything(),
+ );
+ });
+
+ it('clears cached models', () => {
+ controller.attachModel(model);
+
+ model.dispose();
+
+ expect(controller.models.size).toBe(0);
+ });
+ });
+});