controller_spec.js 4.86 KB
Newer Older
Phil Hughes's avatar
Phil Hughes committed
1
/* global monaco */
2 3 4 5 6 7
import monacoLoader from '~/ide/monaco_loader';
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';
Phil Hughes's avatar
Phil Hughes committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
import { file } from '../../helpers';

describe('Multi-file editor library dirty diff controller', () => {
  let editorInstance;
  let controller;
  let modelManager;
  let decorationsController;
  let model;

  beforeEach((done) => {
    monacoLoader(['vs/editor/editor.main'], () => {
      editorInstance = editor.create(monaco);
      editorInstance.createInstance(document.createElement('div'));

      modelManager = new ModelManager(monaco);
      decorationsController = new DecorationsController(editorInstance);

      model = modelManager.addModel(file());

      controller = new DirtyDiffController(modelManager, decorationsController);

      done();
    });
  });

  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).range;

        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', () => {
      spyOn(model, 'onChange');

      controller.attachModel(model);

      expect(model.onChange).toHaveBeenCalled();
    });

    it('calls throttledComputeDiff on change', () => {
      spyOn(controller, 'throttledComputeDiff');

      controller.attachModel(model);

      model.getModel().setValue('123');

      expect(controller.throttledComputeDiff).toHaveBeenCalled();
    });
  });

  describe('computeDiff', () => {
    it('posts to worker', () => {
      spyOn(controller.dirtyDiffWorker, 'postMessage');

      controller.computeDiff(model);

      expect(controller.dirtyDiffWorker.postMessage).toHaveBeenCalledWith({
        path: model.path,
        originalContent: '',
        newContent: '',
      });
    });
  });

  describe('reDecorate', () => {
    it('calls decorations controller decorate', () => {
      spyOn(controller.decorationsController, 'decorate');

      controller.reDecorate(model);

      expect(controller.decorationsController.decorate).toHaveBeenCalledWith(model);
    });
  });

  describe('decorate', () => {
    it('adds decorations into decorations controller', () => {
      spyOn(controller.decorationsController, 'addDecorations');

      controller.decorate({ data: { changes: [], path: 'path' } });

      expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith('path', 'dirtyDiff', jasmine.anything());
    });

    it('adds decorations into editor', () => {
      const spy = spyOn(controller.decorationsController.editor.instance, 'deltaDecorations');

      controller.decorate({ data: { changes: computeDiff('123', '1234'), path: 'path' } });

      expect(spy).toHaveBeenCalledWith([], [{
        range: new monaco.Range(
          1, 1, 1, 1,
        ),
        options: {
          isWholeLine: true,
          linesDecorationsClassName: 'dirty-diff dirty-diff-modified',
        },
      }]);
    });
  });

  describe('dispose', () => {
    it('calls disposable dispose', () => {
      spyOn(controller.disposable, 'dispose').and.callThrough();

      controller.dispose();

      expect(controller.disposable.dispose).toHaveBeenCalled();
    });

    it('terminates worker', () => {
      spyOn(controller.dirtyDiffWorker, 'terminate').and.callThrough();

      controller.dispose();

      expect(controller.dirtyDiffWorker.terminate).toHaveBeenCalled();
    });

    it('removes worker event listener', () => {
      spyOn(controller.dirtyDiffWorker, 'removeEventListener').and.callThrough();

      controller.dispose();

      expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith('message', jasmine.anything());
    });
  });
});