8
0
Эх сурвалжийг харах

Improved selection tests.

Maciej Bukowski 8 жил өмнө
parent
commit
ee0b02be65

+ 120 - 124
packages/ckeditor5-engine/tests/model/selection.js

@@ -173,8 +173,75 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'setTo() - setting selection inside element', () => {
-		it( 'should set selection inside an element', () => {
+	describe( 'setTo()', () => {
+		it( 'should set selection to be same as given selection, using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
+
+			const otherSelection = new Selection( [ range1, range2 ], true );
+
+			selection.setTo( otherSelection );
+
+			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
+			expect( selection.isBackward ).to.be.true;
+			expect( selection._setRanges.calledOnce ).to.be.true;
+			spy.restore();
+		} );
+
+		it( 'should set selection on the given Range using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
+
+			selection.setTo( range1 );
+
+			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1 ] );
+			expect( selection.isBackward ).to.be.false;
+			expect( selection._setRanges.calledOnce ).to.be.true;
+			spy.restore();
+		} );
+
+		it( 'should set selection on the given iterable of Ranges using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
+
+			selection.setTo( new Set( [ range1, range2 ] ) );
+
+			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
+			expect( selection.isBackward ).to.be.false;
+			expect( selection._setRanges.calledOnce ).to.be.true;
+			spy.restore();
+		} );
+
+		it( 'should set collapsed selection on the given Position using _setRanges method', () => {
+			const spy = sinon.spy( selection, '_setRanges' );
+			const position = new Position( root, [ 4 ] );
+
+			selection.setTo( position );
+
+			expect( Array.from( selection.getRanges() ).length ).to.equal( 1 );
+			expect( Array.from( selection.getRanges() )[ 0 ].start ).to.deep.equal( position );
+			expect( selection.isBackward ).to.be.false;
+			expect( selection.isCollapsed ).to.be.true;
+			expect( selection._setRanges.calledOnce ).to.be.true;
+			spy.restore();
+		} );
+
+		it( 'should throw an error if added ranges intersects', () => {
+			expect( () => {
+				selection.setTo( [
+					liveRange,
+					new Range(
+						new Position( root, [ 0, 4 ] ),
+						new Position( root, [ 1, 2 ] )
+					)
+				] );
+			} ).to.throw( CKEditorError, /model-selection-range-intersects/ );
+		} );
+
+		it( 'should throw an error when trying to set selection to not selectable', () => {
+			expect( () => {
+				selection.setTo( {} );
+			} ).to.throw( /model-selection-setTo-not-selectable/ );
+		} );
+
+		it( 'should allow setting selection inside an element', () => {
 			const element = new Element( 'p', null, [ new Text( 'foo' ), new Text( 'bar' ) ] );
 
 			selection.setTo( Range.createIn( element ) );
@@ -186,10 +253,8 @@ describe( 'Selection', () => {
 			expect( ranges[ 0 ].end.parent ).to.equal( element );
 			expect( ranges[ 0 ].end.offset ).to.deep.equal( 6 );
 		} );
-	} );
 
-	describe( 'setTo() - setting selection on item', () => {
-		it( 'should set selection on an item', () => {
+		it( 'should allow setting selection on an item', () => {
 			const textNode1 = new Text( 'foo' );
 			const textNode2 = new Text( 'bar' );
 			const textNode3 = new Text( 'baz' );
@@ -204,79 +269,79 @@ describe( 'Selection', () => {
 			expect( ranges[ 0 ].end.parent ).to.equal( element );
 			expect( ranges[ 0 ].end.offset ).to.deep.equal( 6 );
 		} );
-	} );
 
-	describe( 'setTo() - setting selection to position or item', () => {
-		it( 'fires change:range', () => {
-			const spy = sinon.spy();
+		describe( 'setting selection to position or item', () => {
+			it( 'should fire change:range', () => {
+				const spy = sinon.spy();
 
-			selection.on( 'change:range', spy );
+				selection.on( 'change:range', spy );
 
-			selection.setTo( root );
+				selection.setTo( root );
 
-			expect( spy.calledOnce ).to.be.true;
-		} );
+				expect( spy.calledOnce ).to.be.true;
+			} );
 
-		it( 'sets selection at the 0 offset if second parameter not passed', () => {
-			selection.setTo( root );
+			it( 'should set selection at the 0 offset if second parameter not passed', () => {
+				selection.setTo( root );
 
-			expect( selection ).to.have.property( 'isCollapsed', true );
+				expect( selection ).to.have.property( 'isCollapsed', true );
 
-			const focus = selection.focus;
-			expect( focus ).to.have.property( 'parent', root );
-			expect( focus ).to.have.property( 'offset', 0 );
-		} );
+				const focus = selection.focus;
+				expect( focus ).to.have.property( 'parent', root );
+				expect( focus ).to.have.property( 'offset', 0 );
+			} );
 
-		it( 'sets selection at given offset in given parent', () => {
-			selection.setTo( root, 3 );
+			it( 'should set selection at given offset in given parent', () => {
+				selection.setTo( root, 3 );
 
-			expect( selection ).to.have.property( 'isCollapsed', true );
+				expect( selection ).to.have.property( 'isCollapsed', true );
 
-			const focus = selection.focus;
-			expect( focus ).to.have.property( 'parent', root );
-			expect( focus ).to.have.property( 'offset', 3 );
-		} );
+				const focus = selection.focus;
+				expect( focus ).to.have.property( 'parent', root );
+				expect( focus ).to.have.property( 'offset', 3 );
+			} );
 
-		it( 'sets selection at the end of the given parent', () => {
-			selection.setTo( root, 'end' );
+			it( 'should set selection at the end of the given parent', () => {
+				selection.setTo( root, 'end' );
 
-			expect( selection ).to.have.property( 'isCollapsed', true );
+				expect( selection ).to.have.property( 'isCollapsed', true );
 
-			const focus = selection.focus;
-			expect( focus ).to.have.property( 'parent', root );
-			expect( focus ).to.have.property( 'offset', root.maxOffset );
-		} );
+				const focus = selection.focus;
+				expect( focus ).to.have.property( 'parent', root );
+				expect( focus ).to.have.property( 'offset', root.maxOffset );
+			} );
 
-		it( 'sets selection before the specified element', () => {
-			selection.setTo( root.getChild( 1 ), 'before' );
+			it( 'should set selection before the specified element', () => {
+				selection.setTo( root.getChild( 1 ), 'before' );
 
-			expect( selection ).to.have.property( 'isCollapsed', true );
+				expect( selection ).to.have.property( 'isCollapsed', true );
 
-			const focus = selection.focus;
-			expect( focus ).to.have.property( 'parent', root );
-			expect( focus ).to.have.property( 'offset', 1 );
-		} );
+				const focus = selection.focus;
+				expect( focus ).to.have.property( 'parent', root );
+				expect( focus ).to.have.property( 'offset', 1 );
+			} );
 
-		it( 'sets selection after the specified element', () => {
-			selection.setTo( root.getChild( 1 ), 'after' );
+			it( 'should set selection after the specified element', () => {
+				selection.setTo( root.getChild( 1 ), 'after' );
 
-			expect( selection ).to.have.property( 'isCollapsed', true );
+				expect( selection ).to.have.property( 'isCollapsed', true );
 
-			const focus = selection.focus;
-			expect( focus ).to.have.property( 'parent', root );
-			expect( focus ).to.have.property( 'offset', 2 );
-		} );
+				const focus = selection.focus;
+				expect( focus ).to.have.property( 'parent', root );
+				expect( focus ).to.have.property( 'offset', 2 );
+			} );
 
-		it( 'sets selection at the specified position', () => {
-			const pos = Position.createFromParentAndOffset( root, 3 );
+			it( 'should set selection at the specified position', () => {
+				const pos = Position.createFromParentAndOffset( root, 3 );
 
-			selection.setTo( pos );
+				selection.setTo( pos );
 
-			expect( selection ).to.have.property( 'isCollapsed', true );
+				expect( selection ).to.have.property( 'isCollapsed', true );
 
-			const focus = selection.focus;
-			expect( focus ).to.have.property( 'parent', root );
-			expect( focus ).to.have.property( 'offset', 3 );
+				const focus = selection.focus;
+				expect( focus ).to.have.property( 'parent', root );
+				expect( focus ).to.have.property( 'offset', 3 );
+			} );
 		} );
 	} );
 
@@ -569,75 +634,6 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'setTo()', () => {
-		it( 'should set selection to be same as given selection, using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
-
-			const otherSelection = new Selection( [ range1, range2 ], true );
-
-			selection.setTo( otherSelection );
-
-			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
-			expect( selection.isBackward ).to.be.true;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
-
-		it( 'should set selection on the given Range using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
-
-			selection.setTo( range1 );
-
-			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1 ] );
-			expect( selection.isBackward ).to.be.false;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
-
-		it( 'should set selection on the given iterable of Ranges using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
-
-			selection.setTo( new Set( [ range1, range2 ] ) );
-
-			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
-			expect( selection.isBackward ).to.be.false;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
-
-		it( 'should set collapsed selection on the given Position using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
-			const position = new Position( root, [ 4 ] );
-
-			selection.setTo( position );
-
-			expect( Array.from( selection.getRanges() ).length ).to.equal( 1 );
-			expect( Array.from( selection.getRanges() )[ 0 ].start ).to.deep.equal( position );
-			expect( selection.isBackward ).to.be.false;
-			expect( selection.isCollapsed ).to.be.true;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
-
-		it( 'should throw an error if added ranges intersects', () => {
-			expect( () => {
-				selection.setTo( [
-					liveRange,
-					new Range(
-						new Position( root, [ 0, 4 ] ),
-						new Position( root, [ 1, 2 ] )
-					)
-				] );
-			} ).to.throw( CKEditorError, /model-selection-range-intersects/ );
-		} );
-
-		it( 'should throw an error when trying to set selection to not selectable', () => {
-			expect( () => {
-				selection.setTo( {} );
-			} ).to.throw( /model-selection-setTo-not-selectable/ );
-		} );
-	} );
-
 	describe( 'getFirstRange()', () => {
 		it( 'should return null if no ranges were added', () => {
 			expect( selection.getFirstRange() ).to.be.null;

+ 159 - 157
packages/ckeditor5-engine/tests/view/selection.js

@@ -533,27 +533,6 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'setTo - removeAllRanges', () => {
-		it( 'should remove all ranges and fire change event', done => {
-			selection.setTo( [ range1, range2 ] );
-
-			selection.once( 'change', () => {
-				expect( selection.rangeCount ).to.equal( 0 );
-				done();
-			} );
-
-			selection.setTo( null );
-		} );
-
-		it( 'should do nothing when no ranges are present', () => {
-			const fireSpy = sinon.spy( selection, 'fire' );
-			selection.setTo( null );
-
-			fireSpy.restore();
-			expect( fireSpy.notCalled ).to.be.true;
-		} );
-	} );
-
 	describe( '_setRanges()', () => {
 		it( 'should throw an error when range is invalid', () => {
 			expect( () => {
@@ -587,193 +566,216 @@ describe( 'Selection', () => {
 	} );
 
 	describe( 'setTo()', () => {
-		it( 'should set selection ranges from the given selection', () => {
-			selection.setTo( range1 );
+		describe( 'simple scenarios', () => {
+			it( 'should set selection ranges from the given selection', () => {
+				selection.setTo( range1 );
 
-			const otherSelection = new Selection( [ range2, range3 ], true );
+				const otherSelection = new Selection( [ range2, range3 ], true );
 
-			selection.setTo( otherSelection );
+				selection.setTo( otherSelection );
 
-			expect( selection.rangeCount ).to.equal( 2 );
-			expect( selection._ranges[ 0 ].isEqual( range2 ) ).to.be.true;
-			expect( selection._ranges[ 0 ] ).is.not.equal( range2 );
-			expect( selection._ranges[ 1 ].isEqual( range3 ) ).to.be.true;
-			expect( selection._ranges[ 1 ] ).is.not.equal( range3 );
-
-			expect( selection.anchor.isEqual( range3.end ) ).to.be.true;
-		} );
+				expect( selection.rangeCount ).to.equal( 2 );
+				expect( selection._ranges[ 0 ].isEqual( range2 ) ).to.be.true;
+				expect( selection._ranges[ 0 ] ).is.not.equal( range2 );
+				expect( selection._ranges[ 1 ].isEqual( range3 ) ).to.be.true;
+				expect( selection._ranges[ 1 ] ).is.not.equal( range3 );
 
-		it( 'should set selection on the given Range using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
+				expect( selection.anchor.isEqual( range3.end ) ).to.be.true;
+			} );
 
-			selection.setTo( range1 );
+			it( 'should set selection on the given Range using _setRanges method', () => {
+				const spy = sinon.spy( selection, '_setRanges' );
 
-			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1 ] );
-			expect( selection.isBackward ).to.be.false;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
+				selection.setTo( range1 );
 
-		it( 'should set selection on the given iterable of Ranges using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
+				expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1 ] );
+				expect( selection.isBackward ).to.be.false;
+				expect( selection._setRanges.calledOnce ).to.be.true;
+				spy.restore();
+			} );
 
-			selection.setTo( new Set( [ range1, range2 ] ) );
+			it( 'should set selection on the given iterable of Ranges using _setRanges method', () => {
+				const spy = sinon.spy( selection, '_setRanges' );
 
-			expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
-			expect( selection.isBackward ).to.be.false;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
+				selection.setTo( new Set( [ range1, range2 ] ) );
 
-		it( 'should set collapsed selection on the given Position using _setRanges method', () => {
-			const spy = sinon.spy( selection, '_setRanges' );
+				expect( Array.from( selection.getRanges() ) ).to.deep.equal( [ range1, range2 ] );
+				expect( selection.isBackward ).to.be.false;
+				expect( selection._setRanges.calledOnce ).to.be.true;
+				spy.restore();
+			} );
 
-			selection.setTo( range1.start );
+			it( 'should set collapsed selection on the given Position using _setRanges method', () => {
+				const spy = sinon.spy( selection, '_setRanges' );
 
-			expect( Array.from( selection.getRanges() ).length ).to.equal( 1 );
-			expect( Array.from( selection.getRanges() )[ 0 ].start ).to.deep.equal( range1.start );
-			expect( selection.isBackward ).to.be.false;
-			expect( selection.isCollapsed ).to.be.true;
-			expect( selection._setRanges.calledOnce ).to.be.true;
-			spy.restore();
-		} );
+				selection.setTo( range1.start );
 
-		it( 'should fire change event', done => {
-			selection.on( 'change', () => {
-				expect( selection.rangeCount ).to.equal( 1 );
-				expect( selection.getFirstRange().isEqual( range1 ) ).to.be.true;
-				done();
+				expect( Array.from( selection.getRanges() ).length ).to.equal( 1 );
+				expect( Array.from( selection.getRanges() )[ 0 ].start ).to.deep.equal( range1.start );
+				expect( selection.isBackward ).to.be.false;
+				expect( selection.isCollapsed ).to.be.true;
+				expect( selection._setRanges.calledOnce ).to.be.true;
+				spy.restore();
 			} );
 
-			const otherSelection = new Selection( [ range1 ] );
+			it( 'should fire change event', done => {
+				selection.on( 'change', () => {
+					expect( selection.rangeCount ).to.equal( 1 );
+					expect( selection.getFirstRange().isEqual( range1 ) ).to.be.true;
+					done();
+				} );
 
-			selection.setTo( otherSelection );
-		} );
+				const otherSelection = new Selection( [ range1 ] );
 
-		it( 'should set fake state and label', () => {
-			const otherSelection = new Selection();
-			const label = 'foo bar baz';
-			otherSelection.setFake( true, { label } );
-			selection.setTo( otherSelection );
+				selection.setTo( otherSelection );
+			} );
 
-			expect( selection.isFake ).to.be.true;
-			expect( selection.fakeSelectionLabel ).to.equal( label );
-		} );
+			it( 'should set fake state and label', () => {
+				const otherSelection = new Selection();
+				const label = 'foo bar baz';
+				otherSelection.setFake( true, { label } );
+				selection.setTo( otherSelection );
 
-		it( 'should throw an error when trying to set to not selectable', () => {
-			const otherSelection = new Selection();
+				expect( selection.isFake ).to.be.true;
+				expect( selection.fakeSelectionLabel ).to.equal( label );
+			} );
 
-			expect( () => {
-				otherSelection.setTo( {} );
-			} ).to.throw( /view-selection-setTo-not-selectable/ );
-		} );
-	} );
+			it( 'should throw an error when trying to set to not selectable', () => {
+				const otherSelection = new Selection();
 
-	describe( 'setTo - set collapsed at', () => {
-		beforeEach( () => {
-			selection.setTo( [ range1, range2 ] );
+				expect( () => {
+					otherSelection.setTo( {} );
+				} ).to.throw( /view-selection-setTo-not-selectable/ );
+			} );
 		} );
 
-		it( 'should collapse selection at position', () => {
-			const position = new Position( el, 4 );
+		describe( 'setting collapsed selection', () => {
+			beforeEach( () => {
+				selection.setTo( [ range1, range2 ] );
+			} );
 
-			selection.setTo( position );
-			const range = selection.getFirstRange();
+			it( 'should collapse selection at position', () => {
+				const position = new Position( el, 4 );
 
-			expect( range.start.parent ).to.equal( el );
-			expect( range.start.offset ).to.equal( 4 );
-			expect( range.start.isEqual( range.end ) ).to.be.true;
-		} );
+				selection.setTo( position );
+				const range = selection.getFirstRange();
 
-		it( 'should collapse selection at node and offset', () => {
-			const foo = new Text( 'foo' );
-			const p = new Element( 'p', null, foo );
+				expect( range.start.parent ).to.equal( el );
+				expect( range.start.offset ).to.equal( 4 );
+				expect( range.start.isEqual( range.end ) ).to.be.true;
+			} );
 
-			selection.setTo( foo );
-			let range = selection.getFirstRange();
+			it( 'should collapse selection at node and offset', () => {
+				const foo = new Text( 'foo' );
+				const p = new Element( 'p', null, foo );
 
-			expect( range.start.parent ).to.equal( foo );
-			expect( range.start.offset ).to.equal( 0 );
-			expect( range.start.isEqual( range.end ) ).to.be.true;
+				selection.setTo( foo );
+				let range = selection.getFirstRange();
 
-			selection.setTo( p, 1 );
-			range = selection.getFirstRange();
+				expect( range.start.parent ).to.equal( foo );
+				expect( range.start.offset ).to.equal( 0 );
+				expect( range.start.isEqual( range.end ) ).to.be.true;
 
-			expect( range.start.parent ).to.equal( p );
-			expect( range.start.offset ).to.equal( 1 );
-			expect( range.start.isEqual( range.end ) ).to.be.true;
-		} );
+				selection.setTo( p, 1 );
+				range = selection.getFirstRange();
 
-		it( 'should collapse selection at node and flag', () => {
-			const foo = new Text( 'foo' );
-			const p = new Element( 'p', null, foo );
+				expect( range.start.parent ).to.equal( p );
+				expect( range.start.offset ).to.equal( 1 );
+				expect( range.start.isEqual( range.end ) ).to.be.true;
+			} );
 
-			selection.setTo( foo, 'end' );
-			let range = selection.getFirstRange();
+			it( 'should collapse selection at node and flag', () => {
+				const foo = new Text( 'foo' );
+				const p = new Element( 'p', null, foo );
 
-			expect( range.start.parent ).to.equal( foo );
-			expect( range.start.offset ).to.equal( 3 );
-			expect( range.start.isEqual( range.end ) ).to.be.true;
+				selection.setTo( foo, 'end' );
+				let range = selection.getFirstRange();
 
-			selection.setTo( foo, 'before' );
-			range = selection.getFirstRange();
+				expect( range.start.parent ).to.equal( foo );
+				expect( range.start.offset ).to.equal( 3 );
+				expect( range.start.isEqual( range.end ) ).to.be.true;
 
-			expect( range.start.parent ).to.equal( p );
-			expect( range.start.offset ).to.equal( 0 );
-			expect( range.start.isEqual( range.end ) ).to.be.true;
+				selection.setTo( foo, 'before' );
+				range = selection.getFirstRange();
 
-			selection.setTo( foo, 'after' );
-			range = selection.getFirstRange();
+				expect( range.start.parent ).to.equal( p );
+				expect( range.start.offset ).to.equal( 0 );
+				expect( range.start.isEqual( range.end ) ).to.be.true;
 
-			expect( range.start.parent ).to.equal( p );
-			expect( range.start.offset ).to.equal( 1 );
-			expect( range.start.isEqual( range.end ) ).to.be.true;
-		} );
-	} );
+				selection.setTo( foo, 'after' );
+				range = selection.getFirstRange();
 
-	describe( 'setTo - collapse at start', () => {
-		it( 'should collapse to start position and fire change event', done => {
-			selection.setTo( [ range1, range2, range3 ] );
-			selection.once( 'change', () => {
-				expect( selection.rangeCount ).to.equal( 1 );
-				expect( selection.isCollapsed ).to.be.true;
-				expect( selection._ranges[ 0 ].start.isEqual( range2.start ) ).to.be.true;
-				done();
+				expect( range.start.parent ).to.equal( p );
+				expect( range.start.offset ).to.equal( 1 );
+				expect( range.start.isEqual( range.end ) ).to.be.true;
 			} );
-
-			selection.setTo( selection.getFirstPosition() );
 		} );
 
-		it( 'should do nothing if no ranges present', () => {
-			const fireSpy = sinon.spy( selection, 'fire' );
+		describe( 'setting collapsed selection at start', () => {
+			it( 'should collapse to start position and fire change event', done => {
+				selection.setTo( [ range1, range2, range3 ] );
+				selection.once( 'change', () => {
+					expect( selection.rangeCount ).to.equal( 1 );
+					expect( selection.isCollapsed ).to.be.true;
+					expect( selection._ranges[ 0 ].start.isEqual( range2.start ) ).to.be.true;
+					done();
+				} );
+
+				selection.setTo( selection.getFirstPosition() );
+			} );
+
+			it( 'should do nothing if no ranges present', () => {
+				const fireSpy = sinon.spy( selection, 'fire' );
 
-			selection.setTo( selection.getFirstPosition() );
+				selection.setTo( selection.getFirstPosition() );
 
-			fireSpy.restore();
-			expect( fireSpy.notCalled ).to.be.true;
+				fireSpy.restore();
+				expect( fireSpy.notCalled ).to.be.true;
+			} );
 		} );
-	} );
 
-	describe( 'setTo - collapse to end', () => {
-		it( 'should collapse to end position and fire change event', done => {
-			selection.setTo( [ range1, range2, range3 ] );
-			selection.once( 'change', () => {
-				expect( selection.rangeCount ).to.equal( 1 );
-				expect( selection.isCollapsed ).to.be.true;
-				expect( selection._ranges[ 0 ].end.isEqual( range3.end ) ).to.be.true;
-				done();
+		describe( 'setting collapsed selection to end', () => {
+			it( 'should collapse to end position and fire change event', done => {
+				selection.setTo( [ range1, range2, range3 ] );
+				selection.once( 'change', () => {
+					expect( selection.rangeCount ).to.equal( 1 );
+					expect( selection.isCollapsed ).to.be.true;
+					expect( selection._ranges[ 0 ].end.isEqual( range3.end ) ).to.be.true;
+					done();
+				} );
+
+				selection.setTo( selection.getLastPosition() );
 			} );
 
-			selection.setTo( selection.getLastPosition() );
+			it( 'should do nothing if no ranges present', () => {
+				const fireSpy = sinon.spy( selection, 'fire' );
+
+				selection.setTo( selection.getLastPosition() );
+
+				fireSpy.restore();
+				expect( fireSpy.notCalled ).to.be.true;
+			} );
 		} );
 
-		it( 'should do nothing if no ranges present', () => {
-			const fireSpy = sinon.spy( selection, 'fire' );
+		describe( 'removing all ranges', () => {
+			it( 'should remove all ranges and fire change event', done => {
+				selection.setTo( [ range1, range2 ] );
+
+				selection.once( 'change', () => {
+					expect( selection.rangeCount ).to.equal( 0 );
+					done();
+				} );
 
-			selection.setTo( selection.getLastPosition() );
+				selection.setTo( null );
+			} );
 
-			fireSpy.restore();
-			expect( fireSpy.notCalled ).to.be.true;
+			it( 'should do nothing when no ranges are present', () => {
+				const fireSpy = sinon.spy( selection, 'fire' );
+				selection.setTo( null );
+
+				fireSpy.restore();
+				expect( fireSpy.notCalled ).to.be.true;
+			} );
 		} );
 	} );