Преглед изворни кода

Added: Implemented destroy chain for EditingController->observers->dom events.

Szymon Cofalik пре 9 година
родитељ
комит
5fec43d122
26 измењених фајлова са 133 додато и 49 уклоњено
  1. 1 0
      packages/ckeditor5-engine/src/controller/editingcontroller.js
  2. 6 0
      packages/ckeditor5-engine/src/view/document.js
  3. 5 1
      packages/ckeditor5-engine/src/view/observer/domeventobserver.js
  4. 6 0
      packages/ckeditor5-engine/src/view/observer/mutationobserver.js
  5. 10 0
      packages/ckeditor5-engine/src/view/observer/observer.js
  6. 12 5
      packages/ckeditor5-engine/src/view/observer/selectionobserver.js
  7. 12 7
      packages/ckeditor5-engine/tests/controller/editingcontroller.js
  8. 4 0
      packages/ckeditor5-engine/tests/conversion/buildmodelconverter.js
  9. 4 0
      packages/ckeditor5-engine/tests/conversion/model-selection-to-view-converters.js
  10. 4 0
      packages/ckeditor5-engine/tests/conversion/view-selection-to-model-converters.js
  11. 8 0
      packages/ckeditor5-engine/tests/dev-utils/view.js
  12. 19 31
      packages/ckeditor5-engine/tests/view/document/document.js
  13. 6 0
      packages/ckeditor5-engine/tests/view/document/integration.js
  14. 1 2
      packages/ckeditor5-engine/tests/view/document/jumpoverinlinefiller.js
  15. 4 2
      packages/ckeditor5-engine/tests/view/domconverter/domconverter.js
  16. 4 0
      packages/ckeditor5-engine/tests/view/observer/clickobserver.js
  17. 1 0
      packages/ckeditor5-engine/tests/view/observer/domeventdata.js
  18. 4 1
      packages/ckeditor5-engine/tests/view/observer/domeventobserver.js
  19. 4 0
      packages/ckeditor5-engine/tests/view/observer/fakeselectionobserver.js
  20. 4 0
      packages/ckeditor5-engine/tests/view/observer/focusobserver.js
  21. 4 0
      packages/ckeditor5-engine/tests/view/observer/keyobserver.js
  22. 1 0
      packages/ckeditor5-engine/tests/view/observer/mutationobserver.js
  23. 1 0
      packages/ckeditor5-engine/tests/view/observer/selectionobserver.js
  24. 2 0
      packages/ckeditor5-engine/tests/view/position.js
  25. 2 0
      packages/ckeditor5-engine/tests/view/selection.js
  26. 4 0
      packages/ckeditor5-engine/tests/view/treewalker.js

+ 1 - 0
packages/ckeditor5-engine/src/controller/editingcontroller.js

@@ -141,6 +141,7 @@ export default class EditingController {
 	 * Removes all event listeners attached by the EditingController.
 	 */
 	destroy() {
+		this.view.destroy();
 		this._listenter.stopListening();
 	}
 }

+ 6 - 0
packages/ckeditor5-engine/src/view/document.js

@@ -303,6 +303,12 @@ export default class Document {
 			observer.enable();
 		}
 	}
+
+	destroy() {
+		for ( let observer of this._observers.values() ) {
+			observer.destroy();
+		}
+	}
 }
 
 mix( Document, ObservableMixin );

+ 5 - 1
packages/ckeditor5-engine/src/view/observer/domeventobserver.js

@@ -56,7 +56,11 @@ export default class DomEventObserver extends Observer {
 		const types = typeof this.domEventType == 'string' ? [ this.domEventType ] : this.domEventType;
 
 		types.forEach( type => {
-			domElement.addEventListener( type, domEvent => this.isEnabled && this.onDomEvent( domEvent ) );
+			this.listenTo( domElement, type, ( eventInfo, domEvent ) => {
+				if ( this.isEnabled ) {
+					this.onDomEvent( domEvent );
+				}
+			} );
 		} );
 	}
 

+ 6 - 0
packages/ckeditor5-engine/src/view/observer/mutationobserver.js

@@ -112,6 +112,12 @@ export default class MutationObserver extends Observer {
 		this._mutationObserver.disconnect();
 	}
 
+	destroy() {
+		super.destroy();
+
+		this._mutationObserver.disconnect();
+	}
+
 	/**
 	 * Handles mutations. Deduplicates, mark view elements to sync, fire event and call render.
 	 *

+ 10 - 0
packages/ckeditor5-engine/src/view/observer/observer.js

@@ -3,6 +3,9 @@
  * For licensing, see LICENSE.md.
  */
 
+import DomEmitterMixin from '../../../utils/dom/emittermixin.js';
+import mix from '../../../utils/mix.js';
+
 /**
  * Abstract base observer class. Observers are classes which observe changes on DOM elements, do the preliminary
  * processing and fire events on the {@link engine.view.Document} objects. Observers can also add features to the view,
@@ -59,6 +62,11 @@ export default class Observer {
 		this.isEnabled = false;
 	}
 
+	destroy() {
+		this.disable();
+		this.stopListening();
+	}
+
 	/**
 	 * Starts observing the given root element.
 	 *
@@ -67,3 +75,5 @@ export default class Observer {
 	 * @param {String} name The name of the root element.
 	 */
 }
+
+mix( Observer, DomEmitterMixin );

+ 12 - 5
packages/ckeditor5-engine/src/view/observer/selectionobserver.js

@@ -3,11 +3,10 @@
  * For licensing, see LICENSE.md.
  */
 
-/* global setInterval */
+/* global setInterval, clearInterval */
 
 import Observer from './observer.js';
 import MutationObserver from './mutationobserver.js';
-
 import log from '../../../utils/log.js';
 
 /**
@@ -70,6 +69,8 @@ export default class SelectionObserver extends Observer {
 		 */
 		this._documents = new WeakSet();
 
+		this._clearInfiniteLoopInterval = setInterval( () => this._clearInfiniteLoop(), 2000 );
+
 		/**
 		 * Private property to store the last selection, to check if the code does not enter infinite loop.
 		 *
@@ -103,13 +104,19 @@ export default class SelectionObserver extends Observer {
 			return;
 		}
 
-		domDocument.addEventListener( 'selectionchange', () => this._handleSelectionChange( domDocument ) );
-
-		setInterval( () => this._clearInfiniteLoop(), 2000 );
+		this.listenTo( domDocument, 'selectionchange', () => {
+			this._handleSelectionChange( domDocument );
+		} );
 
 		this._documents.add( domDocument );
 	}
 
+	destroy() {
+		super.destroy();
+
+		clearInterval( this._clearInfiniteLoopInterval );
+	}
+
 	/**
 	 * Selection change listener. {@link engine.view.observer.MutationObserver#flush Flush} mutations, check if
 	 * selection changes and fires {@link engine.view.Document#selectionChange} event.

+ 12 - 7
packages/ckeditor5-engine/tests/controller/editingcontroller.js

@@ -28,18 +28,16 @@ import { getData as getViewData } from 'ckeditor5/engine/dev-utils/view.js';
 
 describe( 'EditingController', () => {
 	describe( 'constructor()', () => {
-		let model, editing;
-
-		beforeEach( () => {
-			model = new ModelDocument();
-			editing = new EditingController( model );
-		} );
-
 		it( 'should create controller with properties', () => {
+			const model = new ModelDocument();
+			const editing = new EditingController( model );
+
 			expect( editing ).to.have.property( 'model' ).that.equals( model );
 			expect( editing ).to.have.property( 'view' ).that.is.instanceof( ViewDocument );
 			expect( editing ).to.have.property( 'mapper' ).that.is.instanceof( Mapper );
 			expect( editing ).to.have.property( 'modelToView' ).that.is.instanceof( ModelConversionDispatcher );
+
+			editing.destroy();
 		} );
 	} );
 
@@ -54,6 +52,10 @@ describe( 'EditingController', () => {
 			editing = new EditingController( model );
 		} );
 
+		afterEach( () => {
+			editing.destroy();
+		} );
+
 		it( 'should create root', () => {
 			const domRoot = createElement( document, 'div', null, createElement( document, 'p' ) );
 
@@ -128,6 +130,7 @@ describe( 'EditingController', () => {
 		after( () => {
 			document.body.removeChild( domRoot );
 			listener.stopListening();
+			editing.destroy();
 		} );
 
 		beforeEach( () => {
@@ -274,6 +277,8 @@ describe( 'EditingController', () => {
 			} );
 
 			expect( spy.called ).to.be.false;
+
+			editing.destroy();
 		} );
 	} );
 } );

+ 4 - 0
packages/ckeditor5-engine/tests/conversion/buildmodelconverter.js

@@ -92,6 +92,10 @@ describe( 'Model converter builder', () => {
 		dispatcher.on( 'remove', remove() );
 	} );
 
+	afterEach( () => {
+		viewDoc.destroy();
+	} );
+
 	describe( 'model element to view element conversion', () => {
 		it( 'using passed view element name', () => {
 			buildModelConverter().for( dispatcher ).fromElement( 'paragraph' ).toElement( 'p' );

+ 4 - 0
packages/ckeditor5-engine/tests/conversion/model-selection-to-view-converters.js

@@ -63,6 +63,10 @@ beforeEach( () => {
 	dispatcher.on( 'selection', convertCollapsedSelection(), { priority: 'low' } );
 } );
 
+afterEach( () => {
+	viewDoc.destroy();
+} );
+
 describe( 'default converters', () => {
 	beforeEach( () => {
 		// Selection converters for selection attributes.

+ 4 - 0
packages/ckeditor5-engine/tests/conversion/view-selection-to-model-converters.js

@@ -40,6 +40,10 @@ describe( 'convertSelectionChange', () => {
 		convertSelection = convertSelectionChange( model, mapper );
 	} );
 
+	afterEach( () => {
+		view.destroy();
+	} );
+
 	it( 'should convert collapsed selection', () => {
 		const viewSelection = new ViewSelection();
 		viewSelection.addRange( ViewRange.createFromParentsAndOffsets(

+ 8 - 0
packages/ckeditor5-engine/tests/dev-utils/view.js

@@ -47,6 +47,8 @@ describe( 'view test utils', () => {
 				expect( stringifyOptions ).to.have.property( 'showType' ).that.equals( false );
 				expect( stringifyOptions ).to.have.property( 'showPriority' ).that.equals( false );
 				expect( stringifyOptions ).to.have.property( 'ignoreRoot' ).that.equals( true );
+
+				viewDocument.destroy();
 			} );
 
 			it( 'should use stringify method with selection', () => {
@@ -67,6 +69,8 @@ describe( 'view test utils', () => {
 				expect( stringifyOptions ).to.have.property( 'showType' ).that.equals( false );
 				expect( stringifyOptions ).to.have.property( 'showPriority' ).that.equals( false );
 				expect( stringifyOptions ).to.have.property( 'ignoreRoot' ).that.equals( true );
+
+				viewDocument.destroy();
 			} );
 
 			it( 'should throw an error when passing invalid document', () => {
@@ -91,6 +95,8 @@ describe( 'view test utils', () => {
 				expect( args[ 0 ] ).to.equal( data );
 				expect( args[ 1 ] ).to.be.an( 'object' );
 				expect( args[ 1 ].rootElement ).to.equal( viewDocument.getRoot() );
+
+				viewDocument.destroy();
 			} );
 
 			it( 'should use parse method with selection', () => {
@@ -106,6 +112,8 @@ describe( 'view test utils', () => {
 				expect( args[ 0 ] ).to.equal( data );
 				expect( args[ 1 ] ).to.be.an( 'object' );
 				expect( args[ 1 ].rootElement ).to.equal( viewDocument.getRoot() );
+
+				viewDocument.destroy();
 			} );
 
 			it( 'should throw an error when passing invalid document', () => {

+ 19 - 31
packages/ckeditor5-engine/tests/view/document/document.js

@@ -25,7 +25,7 @@ testUtils.createSinonSandbox();
 
 describe( 'Document', () => {
 	const DEFAULT_OBSERVERS_COUNT = 5;
-	let ObserverMock, ObserverMockGlobalCount, instantiated, enabled, domRoot;
+	let ObserverMock, ObserverMockGlobalCount, instantiated, enabled, domRoot, viewDocument;
 
 	before( () => {
 		domRoot = createElement( document, 'div', {
@@ -65,12 +65,16 @@ describe( 'Document', () => {
 				enabled++;
 			}
 		};
+
+		viewDocument = new Document();
+	} );
+
+	afterEach( () => {
+		viewDocument.destroy();
 	} );
 
 	describe( 'constructor()', () => {
 		it( 'should create Document with all properties', () => {
-			const viewDocument = new Document();
-
 			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
 			expect( count( viewDocument.roots ) ).to.equal( 0 );
 			expect( viewDocument ).to.have.property( 'renderer' ).that.is.instanceOf( Renderer );
@@ -79,8 +83,6 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should add default observers', () => {
-			const viewDocument = new Document();
-
 			expect( count( viewDocument._observers ) ).to.equal( DEFAULT_OBSERVERS_COUNT );
 			expect( viewDocument.getObserver( MutationObserver ) ).to.be.instanceof( MutationObserver );
 			expect( viewDocument.getObserver( SelectionObserver ) ).to.be.instanceof( SelectionObserver );
@@ -96,7 +98,6 @@ describe( 'Document', () => {
 			const domDiv = document.createElement( 'div' );
 			domDiv.appendChild( domP );
 
-			const viewDocument = new Document();
 			const ret = viewDocument.createRoot( domDiv );
 
 			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
@@ -115,7 +116,10 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should call observe on each observer', () => {
-			const viewDocument = new Document( document.createElement( 'div' ) );
+			// The variable will be overwritten.
+			viewDocument.destroy();
+
+			viewDocument = new Document( document.createElement( 'div' ) );
 			viewDocument.renderer.render = sinon.spy();
 
 			const domDiv1 = document.createElement( 'div' );
@@ -135,8 +139,6 @@ describe( 'Document', () => {
 
 		it( 'should create "main" root by default', () => {
 			const domDiv = document.createElement( 'div' );
-
-			const viewDocument = new Document();
 			const ret = viewDocument.createRoot( domDiv );
 
 			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
@@ -152,8 +154,6 @@ describe( 'Document', () => {
 
 		it( 'should create root with given name', () => {
 			const domDiv = document.createElement( 'div' );
-
-			const viewDocument = new Document();
 			const ret = viewDocument.createRoot( domDiv, 'header' );
 
 			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
@@ -168,7 +168,6 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should create root without attaching DOM element', () => {
-			const viewDocument = new Document();
 			const ret = viewDocument.createRoot( 'div' );
 
 			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
@@ -180,8 +179,6 @@ describe( 'Document', () => {
 	describe( 'attachDomRoot', () => {
 		it( 'should create root without attach DOM element to the view element', () => {
 			const domDiv = document.createElement( 'div' );
-
-			const viewDocument = new Document();
 			const viewRoot = viewDocument.createRoot( 'div' );
 
 			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
@@ -201,8 +198,6 @@ describe( 'Document', () => {
 
 		it( 'should create root without attach DOM element to the view element with given name', () => {
 			const domH1 = document.createElement( 'h1' );
-
-			const viewDocument = new Document();
 			viewDocument.createRoot( 'DIV' );
 			const viewH1 = viewDocument.createRoot( 'h1', 'header' );
 
@@ -225,7 +220,6 @@ describe( 'Document', () => {
 
 	describe( 'getRoot', () => {
 		it( 'should return "main" root', () => {
-			const viewDocument = new Document();
 			viewDocument.createRoot( document.createElement( 'div' ) );
 
 			expect( count( viewDocument.roots ) ).to.equal( 1 );
@@ -234,7 +228,6 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should return named root', () => {
-			const viewDocument = new Document();
 			viewDocument.createRoot( document.createElement( 'h1' ), 'header' );
 
 			expect( count( viewDocument.roots ) ).to.equal( 1 );
@@ -244,13 +237,18 @@ describe( 'Document', () => {
 	} );
 
 	describe( 'addObserver', () => {
-		let viewDocument;
-
 		beforeEach( () => {
+			// The variable will be overwritten.
+			viewDocument.destroy();
+
 			viewDocument = new Document( document.createElement( 'div' ) );
 			viewDocument.renderer.render = sinon.spy();
 		} );
 
+		afterEach( () => {
+			viewDocument.destroy();
+		} );
+
 		it( 'should be instantiated and enabled on adding', () => {
 			const observerMock = viewDocument.addObserver( ObserverMock );
 
@@ -316,8 +314,6 @@ describe( 'Document', () => {
 
 	describe( 'getObserver', () => {
 		it( 'should return observer it it is added', () => {
-			const viewDocument = new Document();
-
 			const addedObserverMock = viewDocument.addObserver( ObserverMock );
 			const getObserverMock = viewDocument.getObserver( ObserverMock );
 
@@ -326,7 +322,6 @@ describe( 'Document', () => {
 		} );
 
 		it( 'should return undefined if observer is not added', () => {
-			const viewDocument = new Document();
 			const getObserverMock = viewDocument.getObserver( ObserverMock );
 
 			expect( getObserverMock ).to.be.undefined;
@@ -335,8 +330,6 @@ describe( 'Document', () => {
 
 	describe( 'disableObservers', () => {
 		it( 'should disable observers', () => {
-			const viewDocument = new Document();
-
 			const addedObserverMock = viewDocument.addObserver( ObserverMock );
 
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
@@ -351,8 +344,6 @@ describe( 'Document', () => {
 
 	describe( 'enableObservers', () => {
 		it( 'should enable observers', () => {
-			const viewDocument = new Document();
-
 			const addedObserverMock = viewDocument.addObserver( ObserverMock );
 
 			viewDocument.disableObservers();
@@ -369,8 +360,6 @@ describe( 'Document', () => {
 
 	describe( 'isFocused', () => {
 		it( 'should change renderer.isFocused too', () => {
-			const viewDocument = new Document();
-
 			expect( viewDocument.isFocused ).to.equal( false );
 			expect( viewDocument.renderer.isFocused ).to.equal( false );
 
@@ -382,10 +371,9 @@ describe( 'Document', () => {
 	} );
 
 	describe( 'focus', () => {
-		let viewDocument, domEditable, viewEditable;
+		let domEditable, viewEditable;
 
 		beforeEach( () => {
-			viewDocument = new Document();
 			domEditable = document.createElement( 'div' );
 			domEditable.setAttribute( 'contenteditable', 'true' );
 			document.body.appendChild( domEditable );

+ 6 - 0
packages/ckeditor5-engine/tests/view/document/integration.js

@@ -25,6 +25,8 @@ describe( 'Document integration', () => {
 
 		expect( domDiv.childNodes.length ).to.equal( 1 );
 		expect( isBlockFiller( domDiv.childNodes[ 0 ], BR_FILLER ) ).to.be.true;
+
+		viewDocument.destroy();
 	} );
 
 	it( 'should render changes in the Document', () => {
@@ -38,6 +40,8 @@ describe( 'Document integration', () => {
 
 		expect( domDiv.childNodes.length ).to.equal( 1 );
 		expect( domDiv.childNodes[ 0 ].tagName ).to.equal( 'P' );
+
+		viewDocument.destroy();
 	} );
 
 	it( 'should render attribute changes', () => {
@@ -58,5 +62,7 @@ describe( 'Document integration', () => {
 
 		expect( domRoot.childNodes.length ).to.equal( 1 );
 		expect( domRoot.childNodes[ 0 ].getAttribute( 'class' ) ).to.equal( 'bar' );
+
+		viewDocument.destroy();
 	} );
 } );

+ 1 - 2
packages/ckeditor5-engine/tests/view/document/jumpoverinlinefiller.js

@@ -33,8 +33,7 @@ describe( 'Document', () => {
 	} );
 
 	afterEach( () => {
-		// There's no destroy() method yet, so let's at least kill the observers.
-		viewDocument.disableObservers();
+		viewDocument.destroy();
 
 		domRoot.parentElement.removeChild( domRoot );
 	} );

+ 4 - 2
packages/ckeditor5-engine/tests/view/domconverter/domconverter.js

@@ -33,10 +33,11 @@ describe( 'DomConverter', () => {
 	} );
 
 	describe( 'focus', () => {
-		let viewEditable, domEditable;
+		let viewEditable, domEditable, viewDocument;
 
 		beforeEach( () => {
-			viewEditable = new ViewEditable( new ViewDocument(), 'div' );
+			viewDocument = new ViewDocument();
+			viewEditable = new ViewEditable( viewDocument, 'div' );
 			domEditable = document.createElement( 'div' );
 			converter.bindElements( domEditable, viewEditable );
 			domEditable.setAttribute( 'contenteditable', 'true' );
@@ -45,6 +46,7 @@ describe( 'DomConverter', () => {
 
 		afterEach( () => {
 			document.body.removeChild( domEditable );
+			viewDocument.destroy();
 		} );
 
 		it( 'should call focus on corresponding DOM editable', () => {

+ 4 - 0
packages/ckeditor5-engine/tests/view/observer/clickobserver.js

@@ -17,6 +17,10 @@ describe( 'ClickObserver', () => {
 		observer = viewDocument.addObserver( ClickObserver );
 	} );
 
+	afterEach( () => {
+		viewDocument.destroy();
+	} );
+
 	it( 'should define domEventType', () => {
 		expect( observer.domEventType ).to.equal( 'click' );
 	} );

+ 1 - 0
packages/ckeditor5-engine/tests/view/observer/domeventdata.js

@@ -35,6 +35,7 @@ describe( 'DomEventData', () => {
 
 	afterEach( () => {
 		domRoot.parentElement.removeChild( domRoot );
+		viewDocument.destroy();
 	} );
 
 	describe( 'constructor()', () => {

+ 4 - 1
packages/ckeditor5-engine/tests/view/observer/domeventobserver.js

@@ -41,6 +41,10 @@ describe( 'DomEventObserver', () => {
 		viewDocument = new ViewDocument();
 	} );
 
+	afterEach( () => {
+		viewDocument.destroy();
+	} );
+
 	describe( 'constructor()', () => {
 		it( 'should create Observer with properties', () => {
 			const observer = new DomEventObserver( viewDocument );
@@ -107,7 +111,6 @@ describe( 'DomEventObserver', () => {
 	it( 'should fire event if observer is disabled and re-enabled', () => {
 		const domElement = document.createElement( 'p' );
 		const domEvent = new MouseEvent( 'click' );
-		const viewDocument = new ViewDocument();
 		const evtSpy = sinon.spy();
 
 		viewDocument.createRoot( domElement, 'root' );

+ 4 - 0
packages/ckeditor5-engine/tests/view/observer/fakeselectionobserver.js

@@ -36,6 +36,10 @@ describe( 'FakeSelectionObserver', () => {
 		viewDocument.selection.setFake();
 	} );
 
+	afterEach( () => {
+		viewDocument.destroy();
+	} );
+
 	it( 'should do nothing if selection is not fake', () => {
 		viewDocument.selection.setFake( false );
 

+ 4 - 0
packages/ckeditor5-engine/tests/view/observer/focusobserver.js

@@ -18,6 +18,10 @@ describe( 'FocusObserver', () => {
 		observer = viewDocument.getObserver( FocusObserver );
 	} );
 
+	afterEach( () => {
+		viewDocument.destroy();
+	} );
+
 	it( 'should define domEventType', () => {
 		expect( observer.domEventType ).to.deep.equal( [ 'focus', 'blur' ] );
 	} );

+ 4 - 0
packages/ckeditor5-engine/tests/view/observer/keyobserver.js

@@ -18,6 +18,10 @@ describe( 'KeyObserver', () => {
 		observer = viewDocument.getObserver( KeyObserver );
 	} );
 
+	afterEach( () => {
+		viewDocument.destroy();
+	} );
+
 	it( 'should define domEventType', () => {
 		expect( observer.domEventType ).to.equal( 'keydown' );
 	} );

+ 1 - 0
packages/ckeditor5-engine/tests/view/observer/mutationobserver.js

@@ -41,6 +41,7 @@ describe( 'MutationObserver', () => {
 		mutationObserver.disable();
 
 		domRoot.parentElement.removeChild( domRoot );
+		viewDocument.destroy();
 	} );
 
 	it( 'should handle typing', () => {

+ 1 - 0
packages/ckeditor5-engine/tests/view/observer/selectionobserver.js

@@ -56,6 +56,7 @@ describe( 'SelectionObserver', () => {
 		domRoot.parentElement.removeChild( domRoot );
 
 		selectionObserver.disable();
+		viewDocument.destroy();
 	} );
 
 	it( 'should fire selectionChange when it is the only change', ( done ) => {

+ 2 - 0
packages/ckeditor5-engine/tests/view/position.js

@@ -463,6 +463,8 @@ describe( 'Position', () => {
 			const position = new Position( p, 0 );
 
 			expect( position.editableElement ).to.equal( editable );
+
+			document.destroy();
 		} );
 	} );
 } );

+ 2 - 0
packages/ckeditor5-engine/tests/view/selection.js

@@ -706,6 +706,8 @@ describe( 'Selection', () => {
 			selection.addRange( Range.createFromParentsAndOffsets( element, 0, element, 0 ) );
 
 			expect( selection.editableElement ).to.equal( root );
+
+			viewDocument.destroy();
 		} );
 	} );
 

+ 4 - 0
packages/ckeditor5-engine/tests/view/treewalker.js

@@ -53,6 +53,10 @@ describe( 'TreeWalker', () => {
 		rootEnding = new Position( root, 2 );
 	} );
 
+	afterEach( () => {
+		doc.destroy();
+	} );
+
 	describe( 'constructor()', () => {
 		it( 'should throw if neither boundaries nor starting position is set', () => {
 			expect( () => {