/** * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. */ import History from 'ckeditor5/engine/model/history.js'; import Delta from 'ckeditor5/engine/model/delta/delta.js'; import Operation from 'ckeditor5/engine/model/operation/operation.js'; import CKEditorError from 'ckeditor5/utils/ckeditorerror.js'; describe( 'History', () => { let history; beforeEach( () => { history = new History(); } ); describe( 'constructor()', () => { it( 'should create an empty History instance', () => { expect( Array.from( history.getDeltas() ).length ).to.equal( 0 ); } ); } ); describe( 'addDelta', () => { it( 'should save delta in the history', () => { let delta = new Delta(); delta.addOperation( new Operation( 0 ) ); history.addDelta( delta ); const deltas = Array.from( history.getDeltas() ); expect( deltas.length ).to.equal( 1 ); expect( deltas[ 0 ] ).to.equal( delta ); } ); it( 'should save each delta only once', () => { let delta = new Delta(); delta.addOperation( new Operation( 0 ) ); history.addDelta( delta ); history.addDelta( delta ); const deltas = Array.from( history.getDeltas() ); expect( deltas.length ).to.equal( 1 ); expect( deltas[ 0 ] ).to.equal( delta ); } ); it( 'should save multiple deltas and keep their order', () => { let deltas = getDeltaSet(); for ( let delta of deltas ) { history.addDelta( delta ); } const historyDeltas = Array.from( history.getDeltas() ); expect( historyDeltas ).to.deep.equal( deltas ); } ); it( 'should skip deltas that does not have operations', () => { let delta = new Delta(); history.addDelta( delta ); expect( Array.from( history.getDeltas() ).length ).to.equal( 0 ); } ); } ); describe( 'getDelta', () => { it( 'should return array with one delta with given base version', () => { let delta = getDelta( 0 ); history.addDelta( delta ); const historyDelta = history.getDelta( 0 ); expect( historyDelta ).to.deep.equal( [ delta ] ); } ); it( 'should return array with all updated deltas of delta with given base version', () => { let delta = getDelta( 0 ); history.addDelta( delta ); let deltas = getDeltaSet(); history.updateDelta( 0, deltas ); const historyDelta = history.getDelta( 0 ); expect( historyDelta ).to.deep.equal( deltas ); } ); it( 'should return null if delta has not been found in history', () => { expect( history.getDelta( -1 ) ).to.be.null; expect( history.getDelta( 2 ) ).to.be.null; expect( history.getDelta( 20 ) ).to.be.null; } ); it( 'should return null if delta has been removed by removeDelta', () => { let delta = getDelta( 0 ); history.addDelta( delta ); history.removeDelta( 0 ); expect( history.getDelta( 0 ) ).to.be.null; } ); } ); describe( 'getDeltas', () => { let deltas; beforeEach( () => { deltas = getDeltaSet(); for ( let delta of deltas ) { history.addDelta( delta ); } } ); it( 'should return only history deltas from given base version', () => { const historyDeltas = Array.from( history.getDeltas( 3 ) ); expect( historyDeltas ).to.deep.equal( deltas.slice( 1 ) ); } ); it( 'should return only history deltas to given base version', () => { const historyDeltas = Array.from( history.getDeltas( 3, 6 ) ); expect( historyDeltas ).to.deep.equal( deltas.slice( 1, 2 ) ); } ); it( 'should return empty (finished) iterator if given history point is too high or negative', () => { expect( Array.from( history.getDeltas( 20 ) ).length ).to.equal( 0 ); expect( Array.from( history.getDeltas( -1 ) ).length ).to.equal( 0 ); } ); it( 'should throw if given history point is "inside" delta', () => { expect( () => { Array.from( history.getDeltas( 2 ) ); } ).to.throw( CKEditorError, /model-history-wrong-version/ ); } ); } ); describe( 'updateDelta', () => { it( 'should substitute delta from history by given deltas', () => { history.addDelta( getDelta( 0 ) ); const deltas = getDeltaSet(); history.updateDelta( 0, deltas ); const historyDeltas = Array.from( history.getDeltas() ); expect( historyDeltas ).to.deep.equal( deltas ); } ); it( 'should substitute all updated deltas by new deltas', () => { history.addDelta( getDelta( 0 ) ); // Change original single delta to three deltas generated by `getDeltaSet`. // All those deltas should now be seen under base version 0. history.updateDelta( 0, getDeltaSet() ); const deltas = getDeltaSet(); // Change all three deltas from base version 0 to new set of deltas. history.updateDelta( 0, deltas ); const historyDeltas = Array.from( history.getDeltas() ); expect( historyDeltas ).to.deep.equal( deltas ); } ); it( 'should do nothing if deltas for given base version has not been found in history', () => { history.addDelta( getDelta( 0 ) ); history.removeDelta( 0 ); const deltas = getDeltaSet(); history.updateDelta( 0, deltas ); expect( Array.from( history.getDeltas() ).length ).to.equal( 0 ); } ); } ); describe( 'removeDelta', () => { it( 'should remove deltas that do not have graveyard related operations', () => { for ( let delta of getDeltaSet() ) { history.addDelta( delta ); } history.removeDelta( 3 ); const deltas = Array.from( history.getDeltas() ); expect( deltas.length ).to.equal( 2 ); } ); it( 'should remove multiple updated deltas', () => { let delta = getDelta( 0 ); history.addDelta( delta ); let updatedDeltas = getDeltaSet( 0 ); history.updateDelta( 0, updatedDeltas ); history.removeDelta( 0 ); const deltas = Array.from( history.getDeltas() ); expect( deltas.length ).to.equal( 0 ); } ); it( 'should do nothing if deltas for given base version has not been found in history', () => { const deltas = getDeltaSet(); for ( let delta of deltas ) { history.addDelta( delta ); } history.removeDelta( 12 ); expect( Array.from( history.getDeltas() ) ).to.deep.equal( deltas ); } ); } ); } ); function getDeltaSet() { const deltas = []; deltas.push( getDelta( 0 ) ); deltas.push( getDelta( 3 ) ); deltas.push( getDelta( 6 ) ); return deltas; } function getDelta( baseVersion ) { const delta = new Delta(); for ( let i = 0; i < 3; i++ ) { delta.addOperation( new Operation( i + baseVersion ) ); } return delta; }