Selaa lähdekoodia

Refactored observers' tests.

Szymon Kupś 8 vuotta sitten
vanhempi
sitoutus
beace28de5
31 muutettua tiedostoa jossa 412 lisäystä ja 409 poistoa
  1. 12 0
      packages/ckeditor5-engine/src/view/document.js
  2. 2 2
      packages/ckeditor5-engine/src/view/observer/clickobserver.js
  3. 6 4
      packages/ckeditor5-engine/src/view/observer/domeventdata.js
  4. 3 3
      packages/ckeditor5-engine/src/view/observer/domeventobserver.js
  5. 3 3
      packages/ckeditor5-engine/src/view/observer/fakeselectionobserver.js
  6. 5 4
      packages/ckeditor5-engine/src/view/observer/focusobserver.js
  7. 2 2
      packages/ckeditor5-engine/src/view/observer/keyobserver.js
  8. 2 2
      packages/ckeditor5-engine/src/view/observer/mouseobserver.js
  9. 5 5
      packages/ckeditor5-engine/src/view/observer/mutationobserver.js
  10. 5 3
      packages/ckeditor5-engine/src/view/observer/observer.js
  11. 6 14
      packages/ckeditor5-engine/src/view/observer/selectionobserver.js
  12. 3 0
      packages/ckeditor5-engine/src/view/renderer.js
  13. 1 1
      packages/ckeditor5-engine/src/view/uielement.js
  14. 15 25
      packages/ckeditor5-engine/src/view/view.js
  15. 2 2
      packages/ckeditor5-engine/tests/view/document.js
  16. 0 83
      packages/ckeditor5-engine/tests/view/document/integration.js
  17. 0 1
      packages/ckeditor5-engine/tests/view/domconverter/domconverter.js
  18. 6 5
      packages/ckeditor5-engine/tests/view/observer/clickobserver.js
  19. 9 7
      packages/ckeditor5-engine/tests/view/observer/domeventdata.js
  20. 25 24
      packages/ckeditor5-engine/tests/view/observer/domeventobserver.js
  21. 7 6
      packages/ckeditor5-engine/tests/view/observer/fakeselectionobserver.js
  22. 20 18
      packages/ckeditor5-engine/tests/view/observer/focusobserver.js
  23. 6 5
      packages/ckeditor5-engine/tests/view/observer/keyobserver.js
  24. 6 5
      packages/ckeditor5-engine/tests/view/observer/mouseobserver.js
  25. 29 28
      packages/ckeditor5-engine/tests/view/observer/mutationobserver.js
  26. 4 3
      packages/ckeditor5-engine/tests/view/observer/observer.js
  27. 19 18
      packages/ckeditor5-engine/tests/view/observer/selectionobserver.js
  28. 25 23
      packages/ckeditor5-engine/tests/view/renderer.js
  29. 18 17
      packages/ckeditor5-engine/tests/view/view/jumpoverinlinefiller.js
  30. 11 10
      packages/ckeditor5-engine/tests/view/view/jumpoveruielement.js
  31. 155 86
      packages/ckeditor5-engine/tests/view/view/view.js

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

@@ -67,6 +67,18 @@ export default class Document {
 		 * @member {Boolean} #isReadOnly
 		 * @member {Boolean} #isReadOnly
 		 */
 		 */
 		this.set( 'isReadOnly', false );
 		this.set( 'isReadOnly', false );
+
+		/**
+		 * True if document is focused.
+		 *
+		 * This property is updated by the {@link module:engine/view/observer/focusobserver~FocusObserver}.
+		 * If the {@link module:engine/view/observer/focusobserver~FocusObserver} is disabled this property will not change.
+		 *
+		 * @readonly
+		 * @observable
+		 * @member {Boolean} module:engine/view/document~Document#isFocused
+		 */
+		this.set( 'isFocused', false );
 	}
 	}
 
 
 	/**
 	/**

+ 2 - 2
packages/ckeditor5-engine/src/view/observer/clickobserver.js

@@ -19,8 +19,8 @@ import DomEventObserver from './domeventobserver';
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  */
  */
 export default class ClickObserver extends DomEventObserver {
 export default class ClickObserver extends DomEventObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.domEventType = 'click';
 		this.domEventType = 'click';
 	}
 	}

+ 6 - 4
packages/ckeditor5-engine/src/view/observer/domeventdata.js

@@ -16,18 +16,20 @@ import extend from '@ckeditor/ckeditor5-utils/src/lib/lodash/extend';
  */
  */
 export default class DomEventData {
 export default class DomEventData {
 	/**
 	/**
-	 * @param {module:engine/view/document~Document} document The instance of the tree view Document.
+	 * @param {module:engine/view/view~view} view The instance of the tree view controller.
 	 * @param {Event} domEvent The DOM event.
 	 * @param {Event} domEvent The DOM event.
 	 * @param {Object} [additionalData] Additional properties that the instance should contain.
 	 * @param {Object} [additionalData] Additional properties that the instance should contain.
 	 */
 	 */
-	constructor( document, domEvent, additionalData ) {
+	constructor( view, domEvent, additionalData ) {
+		this.view = view;
+
 		/**
 		/**
 		 * The instance of the document.
 		 * The instance of the document.
 		 *
 		 *
 		 * @readonly
 		 * @readonly
 		 * @member {module:engine/view/document~Document} module:engine/view/observer/observer~Observer.DomEvent#view
 		 * @member {module:engine/view/document~Document} module:engine/view/observer/observer~Observer.DomEvent#view
 		 */
 		 */
-		this.document = document;
+		this.document = view.document;
 
 
 		/**
 		/**
 		 * The DOM event.
 		 * The DOM event.
@@ -55,7 +57,7 @@ export default class DomEventData {
 	 * @type module:engine/view/element~Element
 	 * @type module:engine/view/element~Element
 	 */
 	 */
 	get target() {
 	get target() {
-		return this.document.domConverter.mapDomToView( this.domTarget );
+		return this.view.domConverter.mapDomToView( this.domTarget );
 	}
 	}
 
 
 	/**
 	/**

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

@@ -55,8 +55,8 @@ export default class DomEventObserver extends Observer {
 	/**
 	/**
 	 * @inheritDoc
 	 * @inheritDoc
 	 */
 	 */
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		/**
 		/**
 		 * If set to `true` DOM events will be listened on the capturing phase.
 		 * If set to `true` DOM events will be listened on the capturing phase.
@@ -93,7 +93,7 @@ export default class DomEventObserver extends Observer {
 	 */
 	 */
 	fire( eventType, domEvent, additionalData ) {
 	fire( eventType, domEvent, additionalData ) {
 		if ( this.isEnabled ) {
 		if ( this.isEnabled ) {
-			this.document.fire( eventType, new DomEventData( this.document, domEvent, additionalData ) );
+			this.document.fire( eventType, new DomEventData( this.view, domEvent, additionalData ) );
 		}
 		}
 	}
 	}
 }
 }

+ 3 - 3
packages/ckeditor5-engine/src/view/observer/fakeselectionobserver.js

@@ -25,10 +25,10 @@ export default class FakeSelectionObserver extends Observer {
 	/**
 	/**
 	 * Creates new FakeSelectionObserver instance.
 	 * Creates new FakeSelectionObserver instance.
 	 *
 	 *
-	 * @param {module:engine/view/document~Document} document
+	 * @param {module:engine/view/view~View} view
 	 */
 	 */
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		/**
 		/**
 		 * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.
 		 * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.

+ 5 - 4
packages/ckeditor5-engine/src/view/observer/focusobserver.js

@@ -22,11 +22,12 @@ import DomEventObserver from './domeventobserver';
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  */
  */
 export default class FocusObserver extends DomEventObserver {
 export default class FocusObserver extends DomEventObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.domEventType = [ 'focus', 'blur' ];
 		this.domEventType = [ 'focus', 'blur' ];
 		this.useCapture = true;
 		this.useCapture = true;
+		const document = this.document;
 
 
 		document.on( 'focus', () => {
 		document.on( 'focus', () => {
 			document.isFocused = true;
 			document.isFocused = true;
@@ -36,7 +37,7 @@ export default class FocusObserver extends DomEventObserver {
 			// overwrite new DOM selection with selection from the view.
 			// overwrite new DOM selection with selection from the view.
 			// See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.
 			// See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.
 			// Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.
 			// Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.
-			this._renderTimeoutId = setTimeout( () => document.render(), 50 );
+			this._renderTimeoutId = setTimeout( () => view.render(), 50 );
 		} );
 		} );
 
 
 		document.on( 'blur', ( evt, data ) => {
 		document.on( 'blur', ( evt, data ) => {
@@ -46,7 +47,7 @@ export default class FocusObserver extends DomEventObserver {
 				document.isFocused = false;
 				document.isFocused = false;
 
 
 				// Re-render the document to update view elements.
 				// Re-render the document to update view elements.
-				document.render();
+				view.render();
 			}
 			}
 		} );
 		} );
 
 

+ 2 - 2
packages/ckeditor5-engine/src/view/observer/keyobserver.js

@@ -18,8 +18,8 @@ import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  */
  */
 export default class KeyObserver extends DomEventObserver {
 export default class KeyObserver extends DomEventObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.domEventType = [ 'keydown', 'keyup' ];
 		this.domEventType = [ 'keydown', 'keyup' ];
 	}
 	}

+ 2 - 2
packages/ckeditor5-engine/src/view/observer/mouseobserver.js

@@ -19,8 +19,8 @@ import DomEventObserver from './domeventobserver';
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  * @extends module:engine/view/observer/domeventobserver~DomEventObserver
  */
  */
 export default class MouseObserver extends DomEventObserver {
 export default class MouseObserver extends DomEventObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.domEventType = 'mousedown';
 		this.domEventType = 'mousedown';
 	}
 	}

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

@@ -31,8 +31,8 @@ import isEqualWith from '@ckeditor/ckeditor5-utils/src/lib/lodash/isEqualWith';
  * @extends module:engine/view/observer/observer~Observer
  * @extends module:engine/view/observer/observer~Observer
  */
  */
 export default class MutationObserver extends Observer {
 export default class MutationObserver extends Observer {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		/**
 		/**
 		 * Native mutation observer config.
 		 * Native mutation observer config.
@@ -52,14 +52,14 @@ export default class MutationObserver extends Observer {
 		 *
 		 *
 		 * @member {module:engine/view/domconverter~DomConverter}
 		 * @member {module:engine/view/domconverter~DomConverter}
 		 */
 		 */
-		this.domConverter = document.domConverter;
+		this.domConverter = view.domConverter;
 
 
 		/**
 		/**
 		 * Reference to the {@link module:engine/view/document~Document#renderer}.
 		 * Reference to the {@link module:engine/view/document~Document#renderer}.
 		 *
 		 *
 		 * @member {module:engine/view/renderer~Renderer}
 		 * @member {module:engine/view/renderer~Renderer}
 		 */
 		 */
-		this.renderer = document.renderer;
+		this.renderer = view.renderer;
 
 
 		/**
 		/**
 		 * Observed DOM elements.
 		 * Observed DOM elements.
@@ -249,7 +249,7 @@ export default class MutationObserver extends Observer {
 
 
 		// If nothing changes on `mutations` event, at this point we have "dirty DOM" (changed) and de-synched
 		// If nothing changes on `mutations` event, at this point we have "dirty DOM" (changed) and de-synched
 		// view (which has not been changed). In order to "reset DOM" we render the view again.
 		// view (which has not been changed). In order to "reset DOM" we render the view again.
-		this.document.render();
+		this.view.render();
 
 
 		function sameNodes( child1, child2 ) {
 		function sameNodes( child1, child2 ) {
 			// First level of comparison (array of children vs array of children) – use the Lodash's default behavior.
 			// First level of comparison (array of children vs array of children) – use the Lodash's default behavior.

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

@@ -21,16 +21,18 @@ export default class Observer {
 	/**
 	/**
 	 * Creates an instance of the observer.
 	 * Creates an instance of the observer.
 	 *
 	 *
-	 * @param {module:engine/view/document~Document} document
+	 * @param {module:engine/view/view~View} view
 	 */
 	 */
-	constructor( document ) {
+	constructor( view ) {
+		this.view = view;
+
 		/**
 		/**
 		 * Reference to the {@link module:engine/view/document~Document} object.
 		 * Reference to the {@link module:engine/view/document~Document} object.
 		 *
 		 *
 		 * @readonly
 		 * @readonly
 		 * @member {module:engine/view/document~Document}
 		 * @member {module:engine/view/document~Document}
 		 */
 		 */
-		this.document = document;
+		this.document = view.document;
 
 
 		/**
 		/**
 		 * State of the observer. If it is disabled events will not be fired.
 		 * State of the observer. If it is disabled events will not be fired.

+ 6 - 14
packages/ckeditor5-engine/src/view/observer/selectionobserver.js

@@ -27,8 +27,8 @@ import debounce from '@ckeditor/ckeditor5-utils/src/lib/lodash/debounce';
  * @extends module:engine/view/observer/observer~Observer
  * @extends module:engine/view/observer/observer~Observer
  */
  */
 export default class SelectionObserver extends Observer {
 export default class SelectionObserver extends Observer {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		/**
 		/**
 		 * Instance of the mutation observer. Selection observer calls
 		 * Instance of the mutation observer. Selection observer calls
@@ -39,15 +39,7 @@ export default class SelectionObserver extends Observer {
 		 * @member {module:engine/view/observer/mutationobserver~MutationObserver}
 		 * @member {module:engine/view/observer/mutationobserver~MutationObserver}
 		 * module:engine/view/observer/selectionobserver~SelectionObserver#mutationObserver
 		 * module:engine/view/observer/selectionobserver~SelectionObserver#mutationObserver
 		 */
 		 */
-		this.mutationObserver = document.getObserver( MutationObserver );
-
-		/**
-		 * Reference to the {@link module:engine/view/document~Document} object.
-		 *
-		 * @readonly
-		 * @member {module:engine/view/document~Document} module:engine/view/observer/selectionobserver~SelectionObserver#document
-		 */
-		this.document = document;
+		this.mutationObserver = view.getObserver( MutationObserver );
 
 
 		/**
 		/**
 		 * Reference to the view {@link module:engine/view/selection~Selection} object used to compare new selection with it.
 		 * Reference to the view {@link module:engine/view/selection~Selection} object used to compare new selection with it.
@@ -55,7 +47,7 @@ export default class SelectionObserver extends Observer {
 		 * @readonly
 		 * @readonly
 		 * @member {module:engine/view/selection~Selection} module:engine/view/observer/selectionobserver~SelectionObserver#selection
 		 * @member {module:engine/view/selection~Selection} module:engine/view/observer/selectionobserver~SelectionObserver#selection
 		 */
 		 */
-		this.selection = document.selection;
+		this.selection = this.document.selection;
 
 
 		/* eslint-disable max-len */
 		/* eslint-disable max-len */
 		/**
 		/**
@@ -65,7 +57,7 @@ export default class SelectionObserver extends Observer {
 		 * @member {module:engine/view/domconverter~DomConverter} module:engine/view/observer/selectionobserver~SelectionObserver#domConverter
 		 * @member {module:engine/view/domconverter~DomConverter} module:engine/view/observer/selectionobserver~SelectionObserver#domConverter
 		 */
 		 */
 		/* eslint-enable max-len */
 		/* eslint-enable max-len */
-		this.domConverter = document.domConverter;
+		this.domConverter = view.domConverter;
 
 
 		/**
 		/**
 		 * Set of documents which have added "selectionchange" listener to avoid adding listener twice to the same
 		 * Set of documents which have added "selectionchange" listener to avoid adding listener twice to the same
@@ -172,7 +164,7 @@ export default class SelectionObserver extends Observer {
 		if ( this.selection.isSimilar( newViewSelection ) ) {
 		if ( this.selection.isSimilar( newViewSelection ) ) {
 			// If selection was equal and we are at this point of algorithm, it means that it was incorrect.
 			// If selection was equal and we are at this point of algorithm, it means that it was incorrect.
 			// Just re-render it, no need to fire any events, etc.
 			// Just re-render it, no need to fire any events, etc.
-			this.document.render();
+			this.view.render();
 		} else {
 		} else {
 			const data = {
 			const data = {
 				oldSelection: this.selection,
 				oldSelection: this.selection,

+ 3 - 0
packages/ckeditor5-engine/src/view/renderer.js

@@ -109,6 +109,9 @@ export default class Renderer {
 		 * @type {null|HTMLElement}
 		 * @type {null|HTMLElement}
 		 */
 		 */
 		this._fakeSelectionContainer = null;
 		this._fakeSelectionContainer = null;
+
+		// TODO: document rend er event.
+		this.decorate( 'render' );
 	}
 	}
 
 
 	/**
 	/**

+ 1 - 1
packages/ckeditor5-engine/src/view/uielement.js

@@ -93,7 +93,7 @@ export default class UIElement extends Element {
  * @param {module:engine/view/view~View} view View controller to which the quirks handling will be injected.
  * @param {module:engine/view/view~View} view View controller to which the quirks handling will be injected.
  */
  */
 export function injectUiElementHandling( view ) {
 export function injectUiElementHandling( view ) {
-	view.on( 'keydown', ( evt, data ) => jumpOverUiElement( evt, data, view.domConverter ) );
+	view.document.on( 'keydown', ( evt, data ) => jumpOverUiElement( evt, data, view.domConverter ) );
 }
 }
 
 
 // Returns `null` because block filler is not needed for UIElements.
 // Returns `null` because block filler is not needed for UIElements.

+ 15 - 25
packages/ckeditor5-engine/src/view/view.js

@@ -31,7 +31,10 @@ export default class View {
 		this._writer = new Writer();
 		this._writer = new Writer();
 
 
 		// TODO: check docs
 		// TODO: check docs
-		// TODO: move render event description to this file.
+		// TODO: move change event description to this file.
+		// TODO: check import path
+		// TODO: check where render() is used and eventually switch to change() where possible
+		// TODO: observers docs fixes
 
 
 		/**
 		/**
 		 * Instance of the {@link module:engine/view/domconverter~DomConverter domConverter} use by
 		 * Instance of the {@link module:engine/view/domconverter~DomConverter domConverter} use by
@@ -49,8 +52,8 @@ export default class View {
 		 * @readonly
 		 * @readonly
 		 * @member {module:engine/view/renderer~Renderer} module:engine/view/view~View#renderer
 		 * @member {module:engine/view/renderer~Renderer} module:engine/view/view~View#renderer
 		 */
 		 */
-		this._renderer = new Renderer( this.domConverter, this.document.selection );
-		this._renderer.bind( 'isFocused' ).to( this.document );
+		this.renderer = new Renderer( this.domConverter, this.document.selection );
+		this.renderer.bind( 'isFocused' ).to( this.document );
 
 
 		/**
 		/**
 		 * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.
 		 * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.
@@ -68,18 +71,6 @@ export default class View {
 		 */
 		 */
 		this._observers = new Map();
 		this._observers = new Map();
 
 
-		/**
-		 * True if view is focused.
-		 *
-		 * This property is updated by the {@link module:engine/view/observer/focusobserver~FocusObserver}.
-		 * If the {@link module:engine/view/observer/focusobserver~FocusObserver} is disabled this property will not change.
-		 *
-		 * @readonly
-		 * @observable
-		 * @member {Boolean} module:engine/view/document~Document#isFocused
-		 */
-		this.set( 'isFocused', false );
-
 		// Add default observers.
 		// Add default observers.
 		this.addObserver( MutationObserver );
 		this.addObserver( MutationObserver );
 		this.addObserver( SelectionObserver );
 		this.addObserver( SelectionObserver );
@@ -113,12 +104,12 @@ export default class View {
 
 
 		this.domRoots.set( name, domRoot );
 		this.domRoots.set( name, domRoot );
 		this.domConverter.bindElements( domRoot, viewRoot );
 		this.domConverter.bindElements( domRoot, viewRoot );
-		this._renderer.markToSync( 'children', viewRoot );
-		this._renderer.domDocuments.add( domRoot.ownerDocument );
+		this.renderer.markToSync( 'children', viewRoot );
+		this.renderer.domDocuments.add( domRoot.ownerDocument );
 
 
-		viewRoot.on( 'change:children', ( evt, node ) => this._renderer.markToSync( 'children', node ) );
-		viewRoot.on( 'change:attributes', ( evt, node ) => this._renderer.markToSync( 'attributes', node ) );
-		viewRoot.on( 'change:text', ( evt, node ) => this._renderer.markToSync( 'text', node ) );
+		viewRoot.on( 'change:children', ( evt, node ) => this.renderer.markToSync( 'children', node ) );
+		viewRoot.on( 'change:attributes', ( evt, node ) => this.renderer.markToSync( 'attributes', node ) );
+		viewRoot.on( 'change:text', ( evt, node ) => this.renderer.markToSync( 'text', node ) );
 
 
 		for ( const observer of this._observers.values() ) {
 		for ( const observer of this._observers.values() ) {
 			observer.observe( domRoot, name );
 			observer.observe( domRoot, name );
@@ -217,7 +208,7 @@ export default class View {
 	 */
 	 */
 	focus() {
 	focus() {
 		if ( !this.document.isFocused ) {
 		if ( !this.document.isFocused ) {
-			const editable = this.doocument.selection.editableElement;
+			const editable = this.document.selection.editableElement;
 
 
 			if ( editable ) {
 			if ( editable ) {
 				this.domConverter.focus( editable );
 				this.domConverter.focus( editable );
@@ -278,7 +269,6 @@ export default class View {
 			observer.destroy();
 			observer.destroy();
 		}
 		}
 
 
-		this.document.destroy();
 		this.stopListening();
 		this.stopListening();
 	}
 	}
 
 
@@ -291,9 +281,9 @@ export default class View {
 	_render() {
 	_render() {
 		this._renderingInProgress = true;
 		this._renderingInProgress = true;
 
 
-		this.document.disableObservers();
-		this._renderer.render();
-		this.document.enableObservers();
+		this.disableObservers();
+		this.renderer.render();
+		this.enableObservers();
 
 
 		this._renderingInProgress = false;
 		this._renderingInProgress = false;
 	}
 	}

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

@@ -6,10 +6,10 @@
 /* globals document */
 /* globals document */
 
 
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
-import Document from '../../../src/view/document';
+import Document from '../../src/view/document';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import count from '@ckeditor/ckeditor5-utils/src/count';
-import createViewRoot from '../_utils/createroot';
+import createViewRoot from './_utils/createroot';
 
 
 testUtils.createSinonSandbox();
 testUtils.createSinonSandbox();
 
 

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

@@ -1,83 +0,0 @@
-/**
- * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* globals document */
-
-import RootEditableElement from '../../../src/view/rooteditableelement';
-import Document from '../../../src/view/document';
-import ViewElement from '../../../src/view/element';
-import { isBlockFiller, BR_FILLER } from '../../../src/view/filler';
-
-import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
-
-describe( 'Document integration', () => {
-	it( 'should remove content of the DOM', () => {
-		const domDiv = createElement( document, 'div', { id: 'editor' }, [
-			createElement( document, 'p' ),
-			createElement( document, 'p' )
-		] );
-
-		const viewDocument = new Document();
-
-		createRoot( 'div', 'main', viewDocument );
-		viewDocument.attachDomRoot( domDiv );
-		viewDocument.render();
-
-		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', () => {
-		const domDiv = document.createElement( 'div' );
-
-		const viewDocument = new Document();
-		createRoot( 'div', 'main', viewDocument );
-		viewDocument.attachDomRoot( domDiv );
-
-		viewDocument.getRoot().appendChildren( new ViewElement( 'p' ) );
-		viewDocument.render();
-
-		expect( domDiv.childNodes.length ).to.equal( 1 );
-		expect( domDiv.childNodes[ 0 ].tagName ).to.equal( 'P' );
-
-		viewDocument.destroy();
-	} );
-
-	it( 'should render attribute changes', () => {
-		const domRoot = document.createElement( 'div' );
-
-		const viewDocument = new Document();
-		const viewRoot = createRoot( 'div', 'main', viewDocument );
-
-		viewDocument.attachDomRoot( domRoot );
-
-		const viewP = new ViewElement( 'p', { class: 'foo' } );
-		viewRoot.appendChildren( viewP );
-		viewDocument.render();
-
-		expect( domRoot.childNodes.length ).to.equal( 1 );
-		expect( domRoot.childNodes[ 0 ].getAttribute( 'class' ) ).to.equal( 'foo' );
-
-		viewP.setAttribute( 'class', 'bar' );
-		viewDocument.render();
-
-		expect( domRoot.childNodes.length ).to.equal( 1 );
-		expect( domRoot.childNodes[ 0 ].getAttribute( 'class' ) ).to.equal( 'bar' );
-
-		viewDocument.destroy();
-	} );
-} );
-
-function createRoot( name, rootName, viewDoc ) {
-	const viewRoot = new RootEditableElement( name );
-
-	viewRoot.rootName = rootName;
-	viewRoot.document = viewDoc;
-	viewDoc.roots.add( viewRoot );
-
-	return viewRoot;
-}

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

@@ -53,7 +53,6 @@ describe( 'DomConverter', () => {
 		afterEach( () => {
 		afterEach( () => {
 			converter.unbindDomElement( domEditable );
 			converter.unbindDomElement( domEditable );
 			document.body.removeChild( domEditableParent );
 			document.body.removeChild( domEditableParent );
-			viewDocument.destroy();
 
 
 			document.body.focus();
 			document.body.focus();
 		} );
 		} );

+ 6 - 5
packages/ckeditor5-engine/tests/view/observer/clickobserver.js

@@ -6,18 +6,19 @@
 /* globals document */
 /* globals document */
 
 
 import ClickObserver from '../../../src/view/observer/clickobserver';
 import ClickObserver from '../../../src/view/observer/clickobserver';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 
 
 describe( 'ClickObserver', () => {
 describe( 'ClickObserver', () => {
-	let viewDocument, observer;
+	let view, viewDocument, observer;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
-		observer = viewDocument.addObserver( ClickObserver );
+		view = new View();
+		viewDocument = view.document;
+		observer = view.addObserver( ClickObserver );
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should define domEventType', () => {
 	it( 'should define domEventType', () => {

+ 9 - 7
packages/ckeditor5-engine/tests/view/observer/domeventdata.js

@@ -6,31 +6,33 @@
 /* globals document */
 /* globals document */
 
 
 import DomEventData from '../../../src/view/observer/domeventdata';
 import DomEventData from '../../../src/view/observer/domeventdata';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 
 
 describe( 'DomEventData', () => {
 describe( 'DomEventData', () => {
-	let viewDocument, viewBody, domRoot;
+	let view, viewDocument, viewBody, domRoot;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 
 
 		domRoot = document.createElement( 'div' );
 		domRoot = document.createElement( 'div' );
 		domRoot.innerHTML = '<div contenteditable="true" id="main"></div><div contenteditable="true" id="additional"></div>';
 		domRoot.innerHTML = '<div contenteditable="true" id="main"></div><div contenteditable="true" id="additional"></div>';
 		document.body.appendChild( domRoot );
 		document.body.appendChild( domRoot );
 
 
-		viewBody = viewDocument.domConverter.domToView( document.body, { bind: true } );
+		viewBody = view.domConverter.domToView( document.body, { bind: true } );
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
 		domRoot.parentElement.removeChild( domRoot );
 		domRoot.parentElement.removeChild( domRoot );
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	describe( 'constructor()', () => {
 	describe( 'constructor()', () => {
 		it( 'sets properties', () => {
 		it( 'sets properties', () => {
 			const domEvt = { target: document.body };
 			const domEvt = { target: document.body };
-			const data = new DomEventData( viewDocument, domEvt, { foo: 1, bar: true } );
+			const data = new DomEventData( view, domEvt, { foo: 1, bar: true } );
 
 
+			expect( data ).to.have.property( 'view', view );
 			expect( data ).to.have.property( 'document', viewDocument );
 			expect( data ).to.have.property( 'document', viewDocument );
 			expect( data ).to.have.property( 'domEvent', domEvt );
 			expect( data ).to.have.property( 'domEvent', domEvt );
 			expect( data ).to.have.property( 'domTarget', document.body );
 			expect( data ).to.have.property( 'domTarget', document.body );
@@ -43,7 +45,7 @@ describe( 'DomEventData', () => {
 	describe( 'target', () => {
 	describe( 'target', () => {
 		it( 'returns bound element', () => {
 		it( 'returns bound element', () => {
 			const domEvt = { target: document.body };
 			const domEvt = { target: document.body };
-			const data = new DomEventData( viewDocument, domEvt );
+			const data = new DomEventData( view, domEvt );
 
 
 			expect( data ).to.have.property( 'target', viewBody );
 			expect( data ).to.have.property( 'target', viewBody );
 		} );
 		} );

+ 25 - 24
packages/ckeditor5-engine/tests/view/observer/domeventobserver.js

@@ -7,13 +7,13 @@
 
 
 import DomEventObserver from '../../../src/view/observer/domeventobserver';
 import DomEventObserver from '../../../src/view/observer/domeventobserver';
 import Observer from '../../../src/view/observer/observer';
 import Observer from '../../../src/view/observer/observer';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import UIElement from '../../../src/view/uielement';
 import UIElement from '../../../src/view/uielement';
 import createViewRoot from '../_utils/createroot';
 import createViewRoot from '../_utils/createroot';
 
 
 class ClickObserver extends DomEventObserver {
 class ClickObserver extends DomEventObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.domEventType = 'click';
 		this.domEventType = 'click';
 	}
 	}
@@ -24,8 +24,8 @@ class ClickObserver extends DomEventObserver {
 }
 }
 
 
 class MultiObserver extends DomEventObserver {
 class MultiObserver extends DomEventObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.domEventType = [ 'evt1', 'evt2' ];
 		this.domEventType = [ 'evt1', 'evt2' ];
 	}
 	}
@@ -36,22 +36,23 @@ class MultiObserver extends DomEventObserver {
 }
 }
 
 
 class ClickCapturingObserver extends ClickObserver {
 class ClickCapturingObserver extends ClickObserver {
-	constructor( document ) {
-		super( document );
+	constructor( view ) {
+		super( view );
 
 
 		this.useCapture = true;
 		this.useCapture = true;
 	}
 	}
 }
 }
 
 
 describe( 'DomEventObserver', () => {
 describe( 'DomEventObserver', () => {
-	let viewDocument;
+	let view, viewDocument;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	describe( 'constructor()', () => {
 	describe( 'constructor()', () => {
@@ -68,8 +69,8 @@ describe( 'DomEventObserver', () => {
 		const evtSpy = sinon.spy();
 		const evtSpy = sinon.spy();
 
 
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domElement );
-		viewDocument.addObserver( ClickObserver );
+		view.attachDomRoot( domElement );
+		view.addObserver( ClickObserver );
 		viewDocument.on( 'click', evtSpy );
 		viewDocument.on( 'click', evtSpy );
 
 
 		domElement.dispatchEvent( domEvent );
 		domElement.dispatchEvent( domEvent );
@@ -91,8 +92,8 @@ describe( 'DomEventObserver', () => {
 		const evtSpy2 = sinon.spy();
 		const evtSpy2 = sinon.spy();
 
 
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domElement );
-		viewDocument.addObserver( MultiObserver );
+		view.attachDomRoot( domElement );
+		view.addObserver( MultiObserver );
 		viewDocument.on( 'evt1', evtSpy1 );
 		viewDocument.on( 'evt1', evtSpy1 );
 		viewDocument.on( 'evt2', evtSpy2 );
 		viewDocument.on( 'evt2', evtSpy2 );
 
 
@@ -109,8 +110,8 @@ describe( 'DomEventObserver', () => {
 		const evtSpy = sinon.spy();
 		const evtSpy = sinon.spy();
 
 
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domElement );
-		const testObserver = viewDocument.addObserver( ClickObserver );
+		view.attachDomRoot( domElement );
+		const testObserver = view.addObserver( ClickObserver );
 		viewDocument.on( 'click', evtSpy );
 		viewDocument.on( 'click', evtSpy );
 
 
 		testObserver.disable();
 		testObserver.disable();
@@ -126,8 +127,8 @@ describe( 'DomEventObserver', () => {
 		const evtSpy = sinon.spy();
 		const evtSpy = sinon.spy();
 
 
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domElement );
-		const testObserver = viewDocument.addObserver( ClickObserver );
+		view.attachDomRoot( domElement );
+		const testObserver = view.addObserver( ClickObserver );
 		viewDocument.on( 'click', evtSpy );
 		viewDocument.on( 'click', evtSpy );
 
 
 		testObserver.disable();
 		testObserver.disable();
@@ -149,8 +150,8 @@ describe( 'DomEventObserver', () => {
 		const domEvent = new MouseEvent( 'click' );
 		const domEvent = new MouseEvent( 'click' );
 		domElement.appendChild( childDomElement );
 		domElement.appendChild( childDomElement );
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domElement );
-		viewDocument.addObserver( ClickCapturingObserver );
+		view.attachDomRoot( domElement );
+		view.addObserver( ClickCapturingObserver );
 
 
 		viewDocument.on( 'click', ( evt, domEventData ) => {
 		viewDocument.on( 'click', ( evt, domEventData ) => {
 			expect( domEventData.domEvent.eventPhase ).to.equal( domEventData.domEvent.CAPTURING_PHASE );
 			expect( domEventData.domEvent.eventPhase ).to.equal( domEventData.domEvent.CAPTURING_PHASE );
@@ -175,14 +176,14 @@ describe( 'DomEventObserver', () => {
 		beforeEach( () => {
 		beforeEach( () => {
 			domRoot = document.createElement( 'div' );
 			domRoot = document.createElement( 'div' );
 			const viewRoot = createViewRoot( viewDocument );
 			const viewRoot = createViewRoot( viewDocument );
-			viewDocument.attachDomRoot( domRoot );
+			view.attachDomRoot( domRoot );
 			uiElement = new MyUIElement( 'p' );
 			uiElement = new MyUIElement( 'p' );
 			viewRoot.appendChildren( uiElement );
 			viewRoot.appendChildren( uiElement );
-			viewDocument.render();
+			view.render();
 
 
 			domEvent = new MouseEvent( 'click', { bubbles: true } );
 			domEvent = new MouseEvent( 'click', { bubbles: true } );
 			evtSpy = sinon.spy();
 			evtSpy = sinon.spy();
-			viewDocument.addObserver( ClickObserver );
+			view.addObserver( ClickObserver );
 			viewDocument.on( 'click', evtSpy );
 			viewDocument.on( 'click', evtSpy );
 		} );
 		} );
 
 
@@ -209,7 +210,7 @@ describe( 'DomEventObserver', () => {
 
 
 	describe( 'fire', () => {
 	describe( 'fire', () => {
 		it( 'should do nothing if observer is disabled', () => {
 		it( 'should do nothing if observer is disabled', () => {
-			const testObserver = new ClickObserver( viewDocument );
+			const testObserver = new ClickObserver( view );
 			const fireSpy = sinon.spy( viewDocument, 'fire' );
 			const fireSpy = sinon.spy( viewDocument, 'fire' );
 
 
 			testObserver.disable();
 			testObserver.disable();

+ 7 - 6
packages/ckeditor5-engine/tests/view/observer/fakeselectionobserver.js

@@ -7,14 +7,14 @@
 
 
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import FakeSelectionObserver from '../../../src/view/observer/fakeselectionobserver';
 import FakeSelectionObserver from '../../../src/view/observer/fakeselectionobserver';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import DomEventData from '../../../src/view/observer/domeventdata';
 import DomEventData from '../../../src/view/observer/domeventdata';
 import createViewRoot from '../_utils/createroot';
 import createViewRoot from '../_utils/createroot';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 import { setData, stringify } from '../../../src/dev-utils/view';
 import { setData, stringify } from '../../../src/dev-utils/view';
 
 
 describe( 'FakeSelectionObserver', () => {
 describe( 'FakeSelectionObserver', () => {
-	let observer, viewDocument, root, domRoot;
+	let observer, view, viewDocument, root, domRoot;
 
 
 	before( () => {
 	before( () => {
 		domRoot = createElement( document, 'div', {
 		domRoot = createElement( document, 'div', {
@@ -28,15 +28,16 @@ describe( 'FakeSelectionObserver', () => {
 	} );
 	} );
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 		root = createViewRoot( viewDocument );
 		root = createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domRoot );
-		observer = viewDocument.getObserver( FakeSelectionObserver );
+		view.attachDomRoot( domRoot );
+		observer = view.getObserver( FakeSelectionObserver );
 		viewDocument.selection.setFake();
 		viewDocument.selection.setFake();
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should do nothing if selection is not fake', () => {
 	it( 'should do nothing if selection is not fake', () => {

+ 20 - 18
packages/ckeditor5-engine/tests/view/observer/focusobserver.js

@@ -5,21 +5,22 @@
 
 
 /* globals document */
 /* globals document */
 import FocusObserver from '../../../src/view/observer/focusobserver';
 import FocusObserver from '../../../src/view/observer/focusobserver';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import ViewRange from '../../../src/view/range';
 import ViewRange from '../../../src/view/range';
 import createViewRoot from '../_utils/createroot';
 import createViewRoot from '../_utils/createroot';
 import { setData } from '../../../src/dev-utils/view';
 import { setData } from '../../../src/dev-utils/view';
 
 
 describe( 'FocusObserver', () => {
 describe( 'FocusObserver', () => {
-	let viewDocument, observer;
+	let view, viewDocument, observer;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
-		observer = viewDocument.getObserver( FocusObserver );
+		view = new View();
+		viewDocument = view.document;
+		observer = view.getObserver( FocusObserver );
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should define domEventType', () => {
 	it( 'should define domEventType', () => {
@@ -58,7 +59,7 @@ describe( 'FocusObserver', () => {
 		} );
 		} );
 
 
 		it( 'should render document after blurring', () => {
 		it( 'should render document after blurring', () => {
-			const renderSpy = sinon.spy( viewDocument, 'render' );
+			const renderSpy = sinon.spy( view, 'render' );
 
 
 			observer.onDomEvent( { type: 'blur', target: document.body } );
 			observer.onDomEvent( { type: 'blur', target: document.body } );
 
 
@@ -74,7 +75,7 @@ describe( 'FocusObserver', () => {
 			domHeader = document.createElement( 'h1' );
 			domHeader = document.createElement( 'h1' );
 
 
 			viewMain = createViewRoot( viewDocument );
 			viewMain = createViewRoot( viewDocument );
-			viewDocument.attachDomRoot( domMain );
+			view.attachDomRoot( domMain );
 		} );
 		} );
 
 
 		it( 'should set isFocused to true on focus', () => {
 		it( 'should set isFocused to true on focus', () => {
@@ -118,7 +119,7 @@ describe( 'FocusObserver', () => {
 		} );
 		} );
 
 
 		it( 'should delay rendering by 50ms', () => {
 		it( 'should delay rendering by 50ms', () => {
-			const renderSpy = sinon.spy( viewDocument, 'render' );
+			const renderSpy = sinon.spy( view, 'render' );
 			const clock = sinon.useFakeTimers();
 			const clock = sinon.useFakeTimers();
 
 
 			observer.onDomEvent( { type: 'focus', target: domMain } );
 			observer.onDomEvent( { type: 'focus', target: domMain } );
@@ -130,7 +131,7 @@ describe( 'FocusObserver', () => {
 		} );
 		} );
 
 
 		it( 'should not call render if destroyed', () => {
 		it( 'should not call render if destroyed', () => {
-			const renderSpy = sinon.spy( viewDocument, 'render' );
+			const renderSpy = sinon.spy( view, 'render' );
 			const clock = sinon.useFakeTimers();
 			const clock = sinon.useFakeTimers();
 
 
 			observer.onDomEvent( { type: 'focus', target: domMain } );
 			observer.onDomEvent( { type: 'focus', target: domMain } );
@@ -150,11 +151,12 @@ describe( 'FocusObserver', () => {
 			domRoot = document.createElement( 'div' );
 			domRoot = document.createElement( 'div' );
 			document.body.appendChild( domRoot );
 			document.body.appendChild( domRoot );
 
 
-			viewDocument = new ViewDocument();
+			view = new View();
+			viewDocument = view.document;
 			createViewRoot( viewDocument );
 			createViewRoot( viewDocument );
-			viewDocument.attachDomRoot( domRoot );
+			view.attachDomRoot( domRoot );
 
 
-			observer = viewDocument.getObserver( FocusObserver );
+			observer = view.getObserver( FocusObserver );
 		} );
 		} );
 
 
 		it( 'should always render document after selectionChange event', done => {
 		it( 'should always render document after selectionChange event', done => {
@@ -162,12 +164,12 @@ describe( 'FocusObserver', () => {
 			const renderSpy = sinon.spy();
 			const renderSpy = sinon.spy();
 
 
 			setData( viewDocument, '<div contenteditable="true">foo bar</div>' );
 			setData( viewDocument, '<div contenteditable="true">foo bar</div>' );
-			viewDocument.render();
+			view.render();
 
 
 			viewDocument.on( 'selectionChange', selectionChangeSpy );
 			viewDocument.on( 'selectionChange', selectionChangeSpy );
-			viewDocument.on( 'render', renderSpy, { priority: 'low' } );
+			view.renderer.on( 'render', renderSpy, { priority: 'low' } );
 
 
-			viewDocument.on( 'render', () => {
+			view.renderer.on( 'render', () => {
 				sinon.assert.callOrder( selectionChangeSpy, renderSpy );
 				sinon.assert.callOrder( selectionChangeSpy, renderSpy );
 				done();
 				done();
 			}, { priority: 'low' } );
 			}, { priority: 'low' } );
@@ -183,13 +185,13 @@ describe( 'FocusObserver', () => {
 			const renderSpy = sinon.spy();
 			const renderSpy = sinon.spy();
 
 
 			setData( viewDocument, '<div contenteditable="true">foo bar</div>' );
 			setData( viewDocument, '<div contenteditable="true">foo bar</div>' );
-			viewDocument.render();
+			view.render();
 			const domEditable = domRoot.childNodes[ 0 ];
 			const domEditable = domRoot.childNodes[ 0 ];
 
 
 			viewDocument.on( 'selectionChange', selectionChangeSpy );
 			viewDocument.on( 'selectionChange', selectionChangeSpy );
-			viewDocument.on( 'render', renderSpy, { priority: 'low' } );
+			view.renderer.on( 'render', renderSpy, { priority: 'low' } );
 
 
-			viewDocument.on( 'render', () => {
+			view.renderer.on( 'render', () => {
 				sinon.assert.notCalled( selectionChangeSpy );
 				sinon.assert.notCalled( selectionChangeSpy );
 				sinon.assert.called( renderSpy );
 				sinon.assert.called( renderSpy );
 
 

+ 6 - 5
packages/ckeditor5-engine/tests/view/observer/keyobserver.js

@@ -6,19 +6,20 @@
 /* globals document */
 /* globals document */
 
 
 import KeyObserver from '../../../src/view/observer/keyobserver';
 import KeyObserver from '../../../src/view/observer/keyobserver';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
 import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
 
 
 describe( 'KeyObserver', () => {
 describe( 'KeyObserver', () => {
-	let viewDocument, observer;
+	let view, viewDocument, observer;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
-		observer = viewDocument.getObserver( KeyObserver );
+		view = new View();
+		viewDocument = view.document;
+		observer = view.getObserver( KeyObserver );
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should define domEventType', () => {
 	it( 'should define domEventType', () => {

+ 6 - 5
packages/ckeditor5-engine/tests/view/observer/mouseobserver.js

@@ -6,18 +6,19 @@
 /* globals document */
 /* globals document */
 
 
 import MouseObserver from '../../../src/view/observer/mouseobserver';
 import MouseObserver from '../../../src/view/observer/mouseobserver';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 
 
 describe( 'MouseObserver', () => {
 describe( 'MouseObserver', () => {
-	let viewDocument, observer;
+	let view, viewDocument, observer;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		viewDocument = new ViewDocument();
-		observer = viewDocument.addObserver( MouseObserver );
+		view = new View();
+		viewDocument = view.document;
+		observer = view.addObserver( MouseObserver );
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should define domEventType', () => {
 	it( 'should define domEventType', () => {

+ 29 - 28
packages/ckeditor5-engine/tests/view/observer/mutationobserver.js

@@ -5,30 +5,31 @@
 
 
 /* globals document */
 /* globals document */
 
 
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import MutationObserver from '../../../src/view/observer/mutationobserver';
 import MutationObserver from '../../../src/view/observer/mutationobserver';
 import UIElement from '../../../src/view/uielement';
 import UIElement from '../../../src/view/uielement';
 import createViewRoot from '../_utils/createroot';
 import createViewRoot from '../_utils/createroot';
 import { parse } from '../../../src/dev-utils/view';
 import { parse } from '../../../src/dev-utils/view';
 
 
 describe( 'MutationObserver', () => {
 describe( 'MutationObserver', () => {
-	let domEditor, viewDocument, viewRoot, mutationObserver, lastMutations, domRoot;
+	let view, domEditor, viewDocument, viewRoot, mutationObserver, lastMutations, domRoot;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
 		domRoot = document.createElement( 'div' );
 		domRoot = document.createElement( 'div' );
 		domRoot.innerHTML = '<div contenteditable="true" id="main"></div><div contenteditable="true" id="additional"></div>';
 		domRoot.innerHTML = '<div contenteditable="true" id="main"></div><div contenteditable="true" id="additional"></div>';
 		document.body.appendChild( domRoot );
 		document.body.appendChild( domRoot );
 
 
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 		domEditor = document.getElementById( 'main' );
 		domEditor = document.getElementById( 'main' );
 		lastMutations = null;
 		lastMutations = null;
 
 
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domEditor );
+		view.attachDomRoot( domEditor );
 		viewDocument.selection.removeAllRanges();
 		viewDocument.selection.removeAllRanges();
 		document.getSelection().removeAllRanges();
 		document.getSelection().removeAllRanges();
 
 
-		mutationObserver = viewDocument.getObserver( MutationObserver );
+		mutationObserver = view.getObserver( MutationObserver );
 
 
 		viewDocument.on( 'mutations', ( evt, mutations ) => {
 		viewDocument.on( 'mutations', ( evt, mutations ) => {
 			lastMutations = mutations;
 			lastMutations = mutations;
@@ -38,14 +39,14 @@ describe( 'MutationObserver', () => {
 
 
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
 		mutationObserver.disable();
 		mutationObserver.disable();
 
 
 		domRoot.parentElement.removeChild( domRoot );
 		domRoot.parentElement.removeChild( domRoot );
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should handle typing', () => {
 	it( 'should handle typing', () => {
@@ -65,7 +66,7 @@ describe( 'MutationObserver', () => {
 		const additional = document.getElementById( 'additional' );
 		const additional = document.getElementById( 'additional' );
 		mutationObserver.disable();
 		mutationObserver.disable();
 		createViewRoot( viewDocument, 'div', 'additional' );
 		createViewRoot( viewDocument, 'div', 'additional' );
-		viewDocument.attachDomRoot( additional, 'additional' );
+		view.attachDomRoot( additional, 'additional' );
 
 
 		additional.textContent = 'foobar';
 		additional.textContent = 'foobar';
 		mutationObserver.flush();
 		mutationObserver.flush();
@@ -97,7 +98,7 @@ describe( 'MutationObserver', () => {
 	it( 'should handle unbold', () => {
 	it( 'should handle unbold', () => {
 		viewRoot.removeChildren( 0, viewRoot.childCount );
 		viewRoot.removeChildren( 0, viewRoot.childCount );
 		viewRoot.appendChildren( parse( '<container:p><attribute:b>foo</attribute:b></container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p><attribute:b>foo</attribute:b></container:p>' ) );
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 0 ];
 		const domP = domEditor.childNodes[ 0 ];
 		const domB = domP.childNodes[ 0 ];
 		const domB = domP.childNodes[ 0 ];
@@ -200,13 +201,13 @@ describe( 'MutationObserver', () => {
 
 
 		// Prepare AdditionalEditor
 		// Prepare AdditionalEditor
 		createViewRoot( viewDocument, 'div', 'additional' );
 		createViewRoot( viewDocument, 'div', 'additional' );
-		viewDocument.attachDomRoot( domAdditionalEditor, 'additional' );
+		view.attachDomRoot( domAdditionalEditor, 'additional' );
 
 
 		viewDocument.getRoot( 'additional' ).appendChildren(
 		viewDocument.getRoot( 'additional' ).appendChildren(
 			parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
 			parse( '<container:p>foo</container:p><container:p>bar</container:p>' ) );
 
 
 		// Render AdditionalEditor (first editor has been rendered in the beforeEach function)
 		// Render AdditionalEditor (first editor has been rendered in the beforeEach function)
-		viewDocument.render();
+		view.render();
 
 
 		domEditor.childNodes[ 0 ].childNodes[ 0 ].data = 'foom';
 		domEditor.childNodes[ 0 ].childNodes[ 0 ].data = 'foom';
 		domAdditionalEditor.childNodes[ 0 ].childNodes[ 0 ].data = 'foom';
 		domAdditionalEditor.childNodes[ 0 ].childNodes[ 0 ].data = 'foom';
@@ -224,12 +225,12 @@ describe( 'MutationObserver', () => {
 	} );
 	} );
 
 
 	it( 'should fire children mutation if the mutation occurred in the inline filler', () => {
 	it( 'should fire children mutation if the mutation occurred in the inline filler', () => {
-		const { view, selection } = parse( '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
+		const { view: viewContainer, selection } = parse( '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
 
-		viewRoot.appendChildren( view );
+		viewRoot.appendChildren( viewContainer );
 		viewDocument.selection.setTo( selection );
 		viewDocument.selection.setTo( selection );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const inlineFiller = domEditor.childNodes[ 2 ].childNodes[ 1 ].childNodes[ 0 ];
 		const inlineFiller = domEditor.childNodes[ 2 ].childNodes[ 1 ].childNodes[ 0 ];
 		inlineFiller.data += 'x';
 		inlineFiller.data += 'x';
@@ -242,19 +243,19 @@ describe( 'MutationObserver', () => {
 	} );
 	} );
 
 
 	it( 'should have no inline filler in mutation', () => {
 	it( 'should have no inline filler in mutation', () => {
-		const { view, selection } = parse( '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
+		const { view: viewContainer, selection } = parse( '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 
 
-		viewRoot.appendChildren( view );
+		viewRoot.appendChildren( viewContainer );
 		viewDocument.selection.setTo( selection );
 		viewDocument.selection.setTo( selection );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		let inlineFiller = domEditor.childNodes[ 2 ].childNodes[ 1 ].childNodes[ 0 ];
 		let inlineFiller = domEditor.childNodes[ 2 ].childNodes[ 1 ].childNodes[ 0 ];
 		inlineFiller.data += 'x';
 		inlineFiller.data += 'x';
 
 
-		view.getChild( 1 ).appendChildren( parse( 'x' ) );
+		viewContainer.getChild( 1 ).appendChildren( parse( 'x' ) );
 		mutationObserver.flush();
 		mutationObserver.flush();
-		viewDocument.render();
+		view.render();
 
 
 		inlineFiller = domEditor.childNodes[ 2 ].childNodes[ 1 ].childNodes[ 0 ];
 		inlineFiller = domEditor.childNodes[ 2 ].childNodes[ 1 ].childNodes[ 0 ];
 		inlineFiller.data += 'y';
 		inlineFiller.data += 'y';
@@ -270,7 +271,7 @@ describe( 'MutationObserver', () => {
 	it( 'should have no block filler in mutation', () => {
 	it( 'should have no block filler in mutation', () => {
 		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.removeChild( domP.childNodes[ 0 ] );
 		domP.removeChild( domP.childNodes[ 0 ] );
@@ -289,7 +290,7 @@ describe( 'MutationObserver', () => {
 	it( 'should ignore mutation with bogus br inserted on the end of the empty paragraph', () => {
 	it( 'should ignore mutation with bogus br inserted on the end of the empty paragraph', () => {
 		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.appendChild( document.createElement( 'br' ) );
 		domP.appendChild( document.createElement( 'br' ) );
@@ -302,7 +303,7 @@ describe( 'MutationObserver', () => {
 	it( 'should ignore mutation with bogus br inserted on the end of the paragraph with text', () => {
 	it( 'should ignore mutation with bogus br inserted on the end of the paragraph with text', () => {
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.appendChild( document.createElement( 'br' ) );
 		domP.appendChild( document.createElement( 'br' ) );
@@ -315,7 +316,7 @@ describe( 'MutationObserver', () => {
 	it( 'should ignore mutation with bogus br inserted on the end of the paragraph while processing text mutations', () => {
 	it( 'should ignore mutation with bogus br inserted on the end of the paragraph while processing text mutations', () => {
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.childNodes[ 0 ].data = 'foo ';
 		domP.childNodes[ 0 ].data = 'foo ';
@@ -332,7 +333,7 @@ describe( 'MutationObserver', () => {
 	it( 'should ignore child mutations which resulted in no changes – when element contains elements', () => {
 	it( 'should ignore child mutations which resulted in no changes – when element contains elements', () => {
 		viewRoot.appendChildren( parse( '<container:p><container:x></container:x></container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p><container:x></container:x></container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		const domY = document.createElement( 'y' );
 		const domY = document.createElement( 'y' );
@@ -366,7 +367,7 @@ describe( 'MutationObserver', () => {
 	it( 'should not ignore mutation with br inserted not on the end of the paragraph', () => {
 	it( 'should not ignore mutation with br inserted not on the end of the paragraph', () => {
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.insertBefore( document.createElement( 'br' ), domP.childNodes[ 0 ] );
 		domP.insertBefore( document.createElement( 'br' ), domP.childNodes[ 0 ] );
@@ -385,7 +386,7 @@ describe( 'MutationObserver', () => {
 	it( 'should not ignore mutation inserting element different than br on the end of the empty paragraph', () => {
 	it( 'should not ignore mutation inserting element different than br on the end of the empty paragraph', () => {
 		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.appendChild( document.createElement( 'span' ) );
 		domP.appendChild( document.createElement( 'span' ) );
@@ -403,7 +404,7 @@ describe( 'MutationObserver', () => {
 	it( 'should not ignore mutation inserting element different than br on the end of the paragraph with text', () => {
 	it( 'should not ignore mutation inserting element different than br on the end of the paragraph with text', () => {
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		const domP = domEditor.childNodes[ 2 ];
 		const domP = domEditor.childNodes[ 2 ];
 		domP.appendChild( document.createElement( 'span' ) );
 		domP.appendChild( document.createElement( 'span' ) );
@@ -433,7 +434,7 @@ describe( 'MutationObserver', () => {
 			const uiElement = new MyUIElement( 'div' );
 			const uiElement = new MyUIElement( 'div' );
 			viewRoot.appendChildren( uiElement );
 			viewRoot.appendChildren( uiElement );
 
 
-			viewDocument.render();
+			view.render();
 		} );
 		} );
 
 
 		it( 'should not collect text mutations from UIElement', () => {
 		it( 'should not collect text mutations from UIElement', () => {

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

@@ -4,15 +4,16 @@
  */
  */
 
 
 import Observer from '../../../src/view/observer/observer';
 import Observer from '../../../src/view/observer/observer';
+import View from '../../../src/view/view';
 
 
 describe( 'Observer', () => {
 describe( 'Observer', () => {
 	describe( 'constructor()', () => {
 	describe( 'constructor()', () => {
 		it( 'should create Observer with properties', () => {
 		it( 'should create Observer with properties', () => {
-			const viewDocument = {};
-			const observer = new Observer( viewDocument );
+			const view = new View();
+			const observer = new Observer( view );
 
 
 			expect( observer ).to.be.an.instanceof( Observer );
 			expect( observer ).to.be.an.instanceof( Observer );
-			expect( observer ).to.have.property( 'document' ).that.equals( viewDocument );
+			expect( observer ).to.have.property( 'document' ).that.equals( view.document );
 			expect( observer ).to.have.property( 'isEnabled' ).that.is.false;
 			expect( observer ).to.have.property( 'isEnabled' ).that.is.false;
 		} );
 		} );
 	} );
 	} );

+ 19 - 18
packages/ckeditor5-engine/tests/view/observer/selectionobserver.js

@@ -8,7 +8,7 @@
 import ViewRange from '../../../src/view/range';
 import ViewRange from '../../../src/view/range';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import ViewSelection from '../../../src/view/selection';
 import ViewSelection from '../../../src/view/selection';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import SelectionObserver from '../../../src/view/observer/selectionobserver';
 import SelectionObserver from '../../../src/view/observer/selectionobserver';
 import FocusObserver from '../../../src/view/observer/focusobserver';
 import FocusObserver from '../../../src/view/observer/focusobserver';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 import log from '@ckeditor/ckeditor5-utils/src/log';
@@ -18,7 +18,7 @@ import { parse } from '../../../src/dev-utils/view';
 testUtils.createSinonSandbox();
 testUtils.createSinonSandbox();
 
 
 describe( 'SelectionObserver', () => {
 describe( 'SelectionObserver', () => {
-	let viewDocument, viewRoot, selectionObserver, domRoot, domMain, domDocument;
+	let view, viewDocument, viewRoot, selectionObserver, domRoot, domMain, domDocument;
 
 
 	beforeEach( done => {
 	beforeEach( done => {
 		domDocument = document;
 		domDocument = document;
@@ -27,11 +27,12 @@ describe( 'SelectionObserver', () => {
 		domMain = domRoot.childNodes[ 0 ];
 		domMain = domRoot.childNodes[ 0 ];
 		domDocument.body.appendChild( domRoot );
 		domDocument.body.appendChild( domRoot );
 
 
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domMain );
+		view.attachDomRoot( domMain );
 
 
-		selectionObserver = viewDocument.getObserver( SelectionObserver );
+		selectionObserver = view.getObserver( SelectionObserver );
 
 
 		viewRoot = viewDocument.getRoot();
 		viewRoot = viewDocument.getRoot();
 
 
@@ -39,7 +40,7 @@ describe( 'SelectionObserver', () => {
 			'<container:p>xxx<ui:span></ui:span></container:p>' +
 			'<container:p>xxx<ui:span></ui:span></container:p>' +
 			'<container:p>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy</container:p>' ) );
 			'<container:p>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy</container:p>' ) );
 
 
-		viewDocument.render();
+		view.render();
 
 
 		viewDocument.selection.removeAllRanges();
 		viewDocument.selection.removeAllRanges();
 		domDocument.getSelection().removeAllRanges();
 		domDocument.getSelection().removeAllRanges();
@@ -56,7 +57,7 @@ describe( 'SelectionObserver', () => {
 	afterEach( () => {
 	afterEach( () => {
 		domRoot.parentElement.removeChild( domRoot );
 		domRoot.parentElement.removeChild( domRoot );
 
 
-		viewDocument.destroy();
+		view.destroy();
 	} );
 	} );
 
 
 	it( 'should fire selectionChange when it is the only change', done => {
 	it( 'should fire selectionChange when it is the only change', done => {
@@ -86,7 +87,7 @@ describe( 'SelectionObserver', () => {
 	it( 'should add only one listener to one document', done => {
 	it( 'should add only one listener to one document', done => {
 		// Add second roots to ensure that listener is added once.
 		// Add second roots to ensure that listener is added once.
 		createViewRoot( viewDocument, 'div', 'additional' );
 		createViewRoot( viewDocument, 'div', 'additional' );
-		viewDocument.attachDomRoot( domDocument.getElementById( 'additional' ), 'additional' );
+		view.attachDomRoot( domDocument.getElementById( 'additional' ), 'additional' );
 
 
 		viewDocument.on( 'selectionChange', () => {
 		viewDocument.on( 'selectionChange', () => {
 			done();
 			done();
@@ -104,11 +105,11 @@ describe( 'SelectionObserver', () => {
 
 
 		const viewBar = viewDocument.getRoot().getChild( 1 ).getChild( 0 );
 		const viewBar = viewDocument.getRoot().getChild( 1 ).getChild( 0 );
 		viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewBar, 1, viewBar, 2 ) );
 		viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewBar, 1, viewBar, 2 ) );
-		viewDocument.render();
+		view.render();
 	} );
 	} );
 
 
 	it( 'should not fired if observer is disabled', done => {
 	it( 'should not fired if observer is disabled', done => {
-		viewDocument.getObserver( SelectionObserver ).disable();
+		view.getObserver( SelectionObserver ).disable();
 
 
 		viewDocument.on( 'selectionChange', () => {
 		viewDocument.on( 'selectionChange', () => {
 			throw 'selectionChange on render';
 			throw 'selectionChange on render';
@@ -208,8 +209,8 @@ describe( 'SelectionObserver', () => {
 		// We need to recreate SelectionObserver, so it will use mocked setInterval.
 		// We need to recreate SelectionObserver, so it will use mocked setInterval.
 		selectionObserver.disable();
 		selectionObserver.disable();
 		selectionObserver.destroy();
 		selectionObserver.destroy();
-		viewDocument._observers.delete( SelectionObserver );
-		viewDocument.addObserver( SelectionObserver );
+		view._observers.delete( SelectionObserver );
+		view.addObserver( SelectionObserver );
 
 
 		return doChanges()
 		return doChanges()
 			.then( doChanges )
 			.then( doChanges )
@@ -238,7 +239,7 @@ describe( 'SelectionObserver', () => {
 		viewDocument.on( 'selectionChangeDone', spy );
 		viewDocument.on( 'selectionChangeDone', spy );
 
 
 		// Disable focus observer to not re-render view on each focus.
 		// Disable focus observer to not re-render view on each focus.
-		viewDocument.getObserver( FocusObserver ).disable();
+		view.getObserver( FocusObserver ).disable();
 
 
 		// Change selection.
 		// Change selection.
 		changeDomSelection();
 		changeDomSelection();
@@ -316,13 +317,13 @@ describe( 'SelectionObserver', () => {
 			// Normally this is handled by view -> model -> view selection converters chain.
 			// Normally this is handled by view -> model -> view selection converters chain.
 			const viewSel = viewDocument.selection;
 			const viewSel = viewDocument.selection;
 
 
-			const viewAnchor = viewDocument.domConverter.domPositionToView( sel.anchorNode, sel.anchorOffset );
-			const viewFocus = viewDocument.domConverter.domPositionToView( sel.focusNode, sel.focusOffset );
+			const viewAnchor = view.domConverter.domPositionToView( sel.anchorNode, sel.anchorOffset );
+			const viewFocus = view.domConverter.domPositionToView( sel.focusNode, sel.focusOffset );
 
 
 			viewSel.setCollapsedAt( viewAnchor );
 			viewSel.setCollapsedAt( viewAnchor );
 			viewSel.moveFocusTo( viewFocus );
 			viewSel.moveFocusTo( viewFocus );
 
 
-			viewDocument.render();
+			view.render();
 		} );
 		} );
 
 
 		viewDocument.once( 'selectionChange', () => {
 		viewDocument.once( 'selectionChange', () => {
@@ -330,7 +331,7 @@ describe( 'SelectionObserver', () => {
 
 
 			selectionObserver.listenTo( domDocument, 'selectionchange', () => {
 			selectionObserver.listenTo( domDocument, 'selectionchange', () => {
 				// 4. Check if view was re-rendered.
 				// 4. Check if view was re-rendered.
-				expect( viewDocument.render.called ).to.be.true;
+				expect( view.render.called ).to.be.true;
 
 
 				done();
 				done();
 			}, { priority: 'lowest' } );
 			}, { priority: 'lowest' } );
@@ -339,7 +340,7 @@ describe( 'SelectionObserver', () => {
 			// Current and new selection position are similar in view (but not equal!).
 			// Current and new selection position are similar in view (but not equal!).
 			// Also add a spy to `viewDocument#render` to see if view will be re-rendered.
 			// Also add a spy to `viewDocument#render` to see if view will be re-rendered.
 			sel.collapse( domUI, 0 );
 			sel.collapse( domUI, 0 );
-			sinon.spy( viewDocument, 'render' );
+			sinon.spy( view, 'render' );
 
 
 			// Some browsers like Safari won't allow to put selection inside empty ui element.
 			// Some browsers like Safari won't allow to put selection inside empty ui element.
 			// In that situation selection should stay in correct place.
 			// In that situation selection should stay in correct place.

+ 25 - 23
packages/ckeditor5-engine/tests/view/renderer.js

@@ -5,7 +5,7 @@
 
 
 /* globals document, window, NodeFilter */
 /* globals document, window, NodeFilter */
 
 
-import ViewDocument from '../../src/view/document';
+import View from '../../src/view/view';
 import ViewElement from '../../src/view/element';
 import ViewElement from '../../src/view/element';
 import ViewContainerElement from '../../src/view/containerelement';
 import ViewContainerElement from '../../src/view/containerelement';
 import ViewAttributeElement from '../../src/view/attributeelement';
 import ViewAttributeElement from '../../src/view/attributeelement';
@@ -21,15 +21,16 @@ import { INLINE_FILLER, INLINE_FILLER_LENGTH, isBlockFiller, BR_FILLER } from '.
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import createViewRoot from './_utils/createroot';
 import createViewRoot from './_utils/createroot';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
-import { unwrap, insert, remove } from '../../src/view/writer';
+import Writer from '../../src/view/writer';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 
 
 testUtils.createSinonSandbox();
 testUtils.createSinonSandbox();
 
 
 describe( 'Renderer', () => {
 describe( 'Renderer', () => {
-	let selection, domConverter, renderer;
+	let selection, domConverter, renderer, writer;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
+		writer = new Writer();
 		selection = new Selection();
 		selection = new Selection();
 		domConverter = new DomConverter();
 		domConverter = new DomConverter();
 		renderer = new Renderer( domConverter, selection );
 		renderer = new Renderer( domConverter, selection );
@@ -1875,15 +1876,16 @@ describe( 'Renderer', () => {
 	} );
 	} );
 
 
 	describe( '#922', () => {
 	describe( '#922', () => {
-		let viewDoc, viewRoot, domRoot, converter;
+		let view, viewDoc, viewRoot, domRoot, converter;
 
 
 		beforeEach( () => {
 		beforeEach( () => {
-			viewDoc = new ViewDocument();
+			view = new View();
+			viewDoc = view.document;
 			domRoot = document.createElement( 'div' );
 			domRoot = document.createElement( 'div' );
 			document.body.appendChild( domRoot );
 			document.body.appendChild( domRoot );
 			viewRoot = createViewRoot( viewDoc );
 			viewRoot = createViewRoot( viewDoc );
-			viewDoc.attachDomRoot( domRoot );
-			converter = viewDoc.domConverter;
+			view.attachDomRoot( domRoot );
+			converter = view.domConverter;
 		} );
 		} );
 
 
 		it( 'should properly render unwrapped attributes #1', () => {
 		it( 'should properly render unwrapped attributes #1', () => {
@@ -1897,14 +1899,14 @@ describe( 'Renderer', () => {
 			);
 			);
 
 
 			// Render it to DOM to create initial DOM <-> view mappings.
 			// Render it to DOM to create initial DOM <-> view mappings.
-			viewDoc.render();
+			view.render();
 
 
 			// Unwrap italic attribute element.
 			// Unwrap italic attribute element.
-			unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
+			writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
 			expect( getViewData( viewDoc ) ).to.equal( '<p>[<strong>foo</strong>]</p>' );
 			expect( getViewData( viewDoc ) ).to.equal( '<p>[<strong>foo</strong>]</p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
-			viewDoc.render();
+			view.render();
 
 
 			// Check if DOM is rendered correctly.
 			// Check if DOM is rendered correctly.
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><strong>foo</strong></p>' );
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><strong>foo</strong></p>' );
@@ -1920,15 +1922,15 @@ describe( 'Renderer', () => {
 				'</container:p>' );
 				'</container:p>' );
 
 
 			// Render it to DOM to create initial DOM <-> view mappings.
 			// Render it to DOM to create initial DOM <-> view mappings.
-			viewDoc.render();
+			view.render();
 
 
 			// Unwrap italic attribute element and change text inside.
 			// Unwrap italic attribute element and change text inside.
-			unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
+			writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) );
 			viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 ).data = 'bar';
 			viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 ).data = 'bar';
 			expect( getViewData( viewDoc ) ).to.equal( '<p>[<strong>bar</strong>]</p>' );
 			expect( getViewData( viewDoc ) ).to.equal( '<p>[<strong>bar</strong>]</p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
-			viewDoc.render();
+			view.render();
 
 
 			// Check if DOM is rendered correctly.
 			// Check if DOM is rendered correctly.
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><strong>bar</strong></p>' );
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><strong>bar</strong></p>' );
@@ -1941,16 +1943,16 @@ describe( 'Renderer', () => {
 			);
 			);
 
 
 			// Render it to DOM to create initial DOM <-> view mappings.
 			// Render it to DOM to create initial DOM <-> view mappings.
-			viewDoc.render();
+			view.render();
 
 
 			// Change text and insert new element into paragraph.
 			// Change text and insert new element into paragraph.
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			textNode.data = 'foobar';
 			textNode.data = 'foobar';
-			insert( ViewPosition.createAfter( textNode ), new ViewAttributeElement( 'img' ) );
+			writer.insert( ViewPosition.createAfter( textNode ), new ViewAttributeElement( 'img' ) );
 			expect( getViewData( viewDoc ) ).to.equal( '<p>foobar<img></img></p>' );
 			expect( getViewData( viewDoc ) ).to.equal( '<p>foobar<img></img></p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
-			viewDoc.render();
+			view.render();
 
 
 			// Check if DOM is rendered correctly.
 			// Check if DOM is rendered correctly.
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p>foobar<img></img></p>' );
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p>foobar<img></img></p>' );
@@ -1963,16 +1965,16 @@ describe( 'Renderer', () => {
 			);
 			);
 
 
 			// Render it to DOM to create initial DOM <-> view mappings.
 			// Render it to DOM to create initial DOM <-> view mappings.
-			viewDoc.render();
+			view.render();
 
 
 			// Change text and insert new element into paragraph.
 			// Change text and insert new element into paragraph.
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			const textNode = viewRoot.getChild( 0 ).getChild( 0 );
 			textNode.data = 'foobar';
 			textNode.data = 'foobar';
-			insert( ViewPosition.createBefore( textNode ), new ViewAttributeElement( 'img' ) );
+			writer.insert( ViewPosition.createBefore( textNode ), new ViewAttributeElement( 'img' ) );
 			expect( getViewData( viewDoc ) ).to.equal( '<p><img></img>foobar</p>' );
 			expect( getViewData( viewDoc ) ).to.equal( '<p><img></img>foobar</p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
-			viewDoc.render();
+			view.render();
 
 
 			// Check if DOM is rendered correctly.
 			// Check if DOM is rendered correctly.
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><img></img>foobar</p>' );
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><img></img>foobar</p>' );
@@ -1989,18 +1991,18 @@ describe( 'Renderer', () => {
 			);
 			);
 
 
 			// Render it to DOM to create initial DOM <-> view mappings.
 			// Render it to DOM to create initial DOM <-> view mappings.
-			viewDoc.render();
+			view.render();
 
 
 			// Remove first element and reinsert it at the end.
 			// Remove first element and reinsert it at the end.
 			const container = viewRoot.getChild( 0 );
 			const container = viewRoot.getChild( 0 );
 			const firstElement = container.getChild( 0 );
 			const firstElement = container.getChild( 0 );
 
 
-			remove( ViewRange.createOn( firstElement ) );
-			insert( new ViewPosition( container, 2 ), firstElement );
+			writer.remove( ViewRange.createOn( firstElement ) );
+			writer.insert( new ViewPosition( container, 2 ), firstElement );
 			expect( getViewData( viewDoc ) ).to.equal( '<p><i></i><span></span><b></b></p>' );
 			expect( getViewData( viewDoc ) ).to.equal( '<p><i></i><span></span><b></b></p>' );
 
 
 			// Re-render changes in view to DOM.
 			// Re-render changes in view to DOM.
-			viewDoc.render();
+			view.render();
 
 
 			// Check if DOM is rendered correctly.
 			// Check if DOM is rendered correctly.
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><i></i><span></span><b></b></p>' );
 			expect( normalizeHtml( domRoot.innerHTML ) ).to.equal( '<p><i></i><span></span><b></b></p>' );

+ 18 - 17
packages/ckeditor5-engine/tests/view/document/jumpoverinlinefiller.js → packages/ckeditor5-engine/tests/view/view/jumpoverinlinefiller.js

@@ -6,7 +6,7 @@
 /* globals document */
 /* globals document */
 
 
 import ViewRange from '../../../src/view/range';
 import ViewRange from '../../../src/view/range';
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import { INLINE_FILLER_LENGTH, isInlineFiller, startsWithFiller } from '../../../src/view/filler';
 import { INLINE_FILLER_LENGTH, isInlineFiller, startsWithFiller } from '../../../src/view/filler';
 
 
 import createViewRoot from '../_utils/createroot';
 import createViewRoot from '../_utils/createroot';
@@ -15,8 +15,8 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 
 
 import { parse, setData } from '../../../src/dev-utils/view';
 import { parse, setData } from '../../../src/dev-utils/view';
 
 
-describe( 'Document', () => {
-	let viewDocument, domRoot;
+describe( 'View', () => {
+	let view, viewDocument, domRoot;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
 		domRoot = createElement( document, 'div', {
 		domRoot = createElement( document, 'div', {
@@ -24,17 +24,18 @@ describe( 'Document', () => {
 		} );
 		} );
 		document.body.appendChild( domRoot );
 		document.body.appendChild( domRoot );
 
 
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 		createViewRoot( viewDocument );
 		createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domRoot );
+		view.attachDomRoot( domRoot );
 
 
 		document.getSelection().removeAllRanges();
 		document.getSelection().removeAllRanges();
 
 
-		viewDocument.isFocused = true;
+		view.isFocused = true;
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 
 
 		domRoot.parentElement.removeChild( domRoot );
 		domRoot.parentElement.removeChild( domRoot );
 	} );
 	} );
@@ -42,9 +43,9 @@ describe( 'Document', () => {
 	describe( 'jump over inline filler hack', () => {
 	describe( 'jump over inline filler hack', () => {
 		it( 'should jump over inline filler when left arrow is pressed after inline filler', () => {
 		it( 'should jump over inline filler when left arrow is pressed after inline filler', () => {
 			setData( viewDocument, '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 			setData( viewDocument, '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
-			viewDocument.render();
+			view.render();
 
 
-			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowleft, domTarget: viewDocument.domRoots.get( 'main' ) } );
+			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowleft, domTarget: view.domRoots.get( 'main' ) } );
 
 
 			const domSelection = document.getSelection();
 			const domSelection = document.getSelection();
 
 
@@ -64,9 +65,9 @@ describe( 'Document', () => {
 
 
 		it( 'should do nothing when another key is pressed', () => {
 		it( 'should do nothing when another key is pressed', () => {
 			setData( viewDocument, '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 			setData( viewDocument, '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
-			viewDocument.render();
+			view.render();
 
 
-			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowright, domTarget: viewDocument.domRoots.get( 'main' ) } );
+			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowright, domTarget: view.domRoots.get( 'main' ) } );
 
 
 			const domSelection = document.getSelection();
 			const domSelection = document.getSelection();
 
 
@@ -77,9 +78,9 @@ describe( 'Document', () => {
 
 
 		it( 'should do nothing if range is not collapsed', () => {
 		it( 'should do nothing if range is not collapsed', () => {
 			setData( viewDocument, '<container:p>foo<attribute:b>{x}</attribute:b>bar</container:p>' );
 			setData( viewDocument, '<container:p>foo<attribute:b>{x}</attribute:b>bar</container:p>' );
-			viewDocument.render();
+			view.render();
 
 
-			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowleft, domTarget: viewDocument.domRoots.get( 'main' ) } );
+			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowleft, domTarget: view.domRoots.get( 'main' ) } );
 
 
 			const domSelection = document.getSelection();
 			const domSelection = document.getSelection();
 
 
@@ -105,7 +106,7 @@ describe( 'Document', () => {
 
 
 		it( 'should do nothing if caret is not directly before the filler', () => {
 		it( 'should do nothing if caret is not directly before the filler', () => {
 			setData( viewDocument, '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
 			setData( viewDocument, '<container:p>foo<attribute:b>[]</attribute:b>bar</container:p>' );
-			viewDocument.render();
+			view.render();
 
 
 			// Insert a letter to the <b>: '<container:p>foo<attribute:b>x{}</attribute:b>bar</container:p>'
 			// Insert a letter to the <b>: '<container:p>foo<attribute:b>x{}</attribute:b>bar</container:p>'
 			// Do this both in the view and in the DOM to simulate typing and to avoid rendering (which would remove the filler).
 			// Do this both in the view and in the DOM to simulate typing and to avoid rendering (which would remove the filler).
@@ -115,7 +116,7 @@ describe( 'Document', () => {
 			viewDocument.selection.removeAllRanges();
 			viewDocument.selection.removeAllRanges();
 			viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewTextX, 1, viewTextX, 1 ) );
 			viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewTextX, 1, viewTextX, 1 ) );
 
 
-			const domB = viewDocument.getDomRoot( 'main' ).querySelector( 'b' );
+			const domB = view.getDomRoot( 'main' ).querySelector( 'b' );
 			const domSelection = document.getSelection();
 			const domSelection = document.getSelection();
 			domB.childNodes[ 0 ].data += 'x';
 			domB.childNodes[ 0 ].data += 'x';
 
 
@@ -125,9 +126,9 @@ describe( 'Document', () => {
 			domRange.collapse( true );
 			domRange.collapse( true );
 			domSelection.addRange( domRange );
 			domSelection.addRange( domRange );
 
 
-			viewDocument.render();
+			view.render();
 
 
-			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowleft, domTarget: viewDocument.domRoots.get( 'main' ) } );
+			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowleft, domTarget: view.domRoots.get( 'main' ) } );
 
 
 			expect( startsWithFiller( domSelection.anchorNode ) ).to.be.true;
 			expect( startsWithFiller( domSelection.anchorNode ) ).to.be.true;
 			expect( domSelection.anchorOffset ).to.equal( INLINE_FILLER_LENGTH + 1 );
 			expect( domSelection.anchorOffset ).to.equal( INLINE_FILLER_LENGTH + 1 );

+ 11 - 10
packages/ckeditor5-engine/tests/view/document/jumpoveruielement.js → packages/ckeditor5-engine/tests/view/view/jumpoveruielement.js

@@ -5,7 +5,7 @@
 
 
 /* globals document */
 /* globals document */
 
 
-import ViewDocument from '../../../src/view/document';
+import View from '../../../src/view/view';
 import UIElement from '../../../src/view/uielement';
 import UIElement from '../../../src/view/uielement';
 import ViewContainerElement from '../../../src/view/containerelement';
 import ViewContainerElement from '../../../src/view/containerelement';
 import ViewAttribtueElement from '../../../src/view/attributeelement';
 import ViewAttribtueElement from '../../../src/view/attributeelement';
@@ -18,7 +18,7 @@ import { setData as setViewData } from '../../../src/dev-utils/view';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 
 
 describe( 'Document', () => {
 describe( 'Document', () => {
-	let viewDocument, domRoot, domSelection, viewRoot, foo, bar, ui, ui2;
+	let view, viewDocument, domRoot, domSelection, viewRoot, foo, bar, ui, ui2;
 
 
 	class MyUIElement extends UIElement {
 	class MyUIElement extends UIElement {
 		render( domDocument ) {
 		render( domDocument ) {
@@ -35,14 +35,15 @@ describe( 'Document', () => {
 		} );
 		} );
 		document.body.appendChild( domRoot );
 		document.body.appendChild( domRoot );
 
 
-		viewDocument = new ViewDocument();
+		view = new View();
+		viewDocument = view.document;
 		viewRoot = createViewRoot( viewDocument );
 		viewRoot = createViewRoot( viewDocument );
-		viewDocument.attachDomRoot( domRoot );
+		view.attachDomRoot( domRoot );
 
 
 		domSelection = document.getSelection();
 		domSelection = document.getSelection();
 		domSelection.removeAllRanges();
 		domSelection.removeAllRanges();
 
 
-		viewDocument.isFocused = true;
+		view.isFocused = true;
 
 
 		foo = new ViewText( 'foo' );
 		foo = new ViewText( 'foo' );
 		bar = new ViewText( 'bar' );
 		bar = new ViewText( 'bar' );
@@ -54,15 +55,15 @@ describe( 'Document', () => {
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
-		viewDocument.destroy();
+		view.destroy();
 
 
 		domRoot.parentElement.removeChild( domRoot );
 		domRoot.parentElement.removeChild( domRoot );
 	} );
 	} );
 
 
 	function renderAndFireKeydownEvent( options ) {
 	function renderAndFireKeydownEvent( options ) {
-		viewDocument.render();
+		view.render();
 
 
-		const eventData = Object.assign( { keyCode: keyCodes.arrowright, domTarget: viewDocument.domRoots.get( 'main' ) }, options );
+		const eventData = Object.assign( { keyCode: keyCodes.arrowright, domTarget: view.domRoots.get( 'main' ) }, options );
 		viewDocument.fire( 'keydown', eventData );
 		viewDocument.fire( 'keydown', eventData );
 	}
 	}
 
 
@@ -416,14 +417,14 @@ describe( 'Document', () => {
 			} );
 			} );
 		} );
 		} );
 
 
-		it( 'should do nothing if dom position cannot be converted to view position', () => {
+		it( 'should do nothing if DOM position cannot be converted to view position', () => {
 			const newDiv = document.createElement( 'div' );
 			const newDiv = document.createElement( 'div' );
 			const domSelection = document.getSelection();
 			const domSelection = document.getSelection();
 
 
 			document.body.appendChild( newDiv );
 			document.body.appendChild( newDiv );
 			domSelection.collapse( newDiv, 0 );
 			domSelection.collapse( newDiv, 0 );
 
 
-			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowright, domTarget: viewDocument.domRoots.get( 'main' ) } );
+			viewDocument.fire( 'keydown', { keyCode: keyCodes.arrowright, domTarget: view.domRoots.get( 'main' ) } );
 		} );
 		} );
 	} );
 	} );
 } );
 } );

+ 155 - 86
packages/ckeditor5-engine/tests/view/view.js → packages/ckeditor5-engine/tests/view/view/view.js

@@ -1,25 +1,29 @@
 /* globals document */
 /* globals document */
 
 
-import View from '../../src/view/view';
-import MutationObserver from '../../src/view/observer/mutationobserver';
+import View from '../../../src/view/view';
+import MutationObserver from '../../../src/view/observer/mutationobserver';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import count from '@ckeditor/ckeditor5-utils/src/count';
-import KeyObserver from '../../src/view/observer/keyobserver';
-import FakeSelectionObserver from '../../src/view/observer/fakeselectionobserver';
-import SelectionObserver from '../../src/view/observer/selectionobserver';
-import FocusObserver from '../../src/view/observer/focusobserver';
-import createViewRoot from './_utils/createroot';
-import Document from '../../src/view/document';
-import Observer from '../../src/view/observer/observer';
+import KeyObserver from '../../../src/view/observer/keyobserver';
+import FakeSelectionObserver from '../../../src/view/observer/fakeselectionobserver';
+import SelectionObserver from '../../../src/view/observer/selectionobserver';
+import FocusObserver from '../../../src/view/observer/focusobserver';
+import createViewRoot from '../_utils/createroot';
+import Observer from '../../../src/view/observer/observer';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
-import ViewRange from '../../src/view/range';
+import ViewRange from '../../../src/view/range';
+import RootEditableElement from '../../../src/view/rooteditableelement';
+import ViewElement from '../../../src/view/element';
+import { isBlockFiller, BR_FILLER } from '../../../src/view/filler';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 
 
 describe( 'view', () => {
 describe( 'view', () => {
 	const DEFAULT_OBSERVERS_COUNT = 5;
 	const DEFAULT_OBSERVERS_COUNT = 5;
 	let domRoot, view, viewDocument, ObserverMock, instantiated, enabled, ObserverMockGlobalCount;
 	let domRoot, view, viewDocument, ObserverMock, instantiated, enabled, ObserverMockGlobalCount;
 
 
+	testUtils.createSinonSandbox();
+
 	beforeEach( () => {
 	beforeEach( () => {
 		domRoot = createElement( document, 'div', {
 		domRoot = createElement( document, 'div', {
 			id: 'editor',
 			id: 'editor',
@@ -30,8 +34,8 @@ describe( 'view', () => {
 		viewDocument = view.document;
 		viewDocument = view.document;
 
 
 		ObserverMock = class extends Observer {
 		ObserverMock = class extends Observer {
-			constructor( viewDocument ) {
-				super( viewDocument );
+			constructor( view ) {
+				super( view );
 
 
 				this.enable = sinon.spy();
 				this.enable = sinon.spy();
 				this.disable = sinon.spy();
 				this.disable = sinon.spy();
@@ -43,8 +47,8 @@ describe( 'view', () => {
 		enabled = 0;
 		enabled = 0;
 
 
 		ObserverMockGlobalCount = class extends Observer {
 		ObserverMockGlobalCount = class extends Observer {
-			constructor( viewDocument ) {
-				super( viewDocument );
+			constructor( view ) {
+				super( view );
 				instantiated++;
 				instantiated++;
 
 
 				this.observe = sinon.spy();
 				this.observe = sinon.spy();
@@ -74,38 +78,39 @@ describe( 'view', () => {
 			const domDiv = document.createElement( 'div' );
 			const domDiv = document.createElement( 'div' );
 			const viewRoot = createViewRoot( viewDocument, 'div', 'main' );
 			const viewRoot = createViewRoot( viewDocument, 'div', 'main' );
 
 
-			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
+			expect( count( view.domRoots ) ).to.equal( 0 );
 
 
-			viewDocument.attachDomRoot( domDiv );
+			view.attachDomRoot( domDiv );
 
 
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
+			expect( count( view.domRoots ) ).to.equal( 1 );
 
 
-			expect( viewDocument.getDomRoot() ).to.equal( domDiv );
-			expect( viewDocument.domConverter.mapViewToDom( viewRoot ) ).to.equal( domDiv );
+			expect( view.getDomRoot() ).to.equal( domDiv );
+			expect( view.domConverter.mapViewToDom( viewRoot ) ).to.equal( domDiv );
 
 
-			expect( viewDocument.renderer.markedChildren.has( viewRoot ) ).to.be.true;
+			expect( view.renderer.markedChildren.has( viewRoot ) ).to.be.true;
 		} );
 		} );
 
 
 		it( 'should attach DOM element to custom view element', () => {
 		it( 'should attach DOM element to custom view element', () => {
 			const domH1 = document.createElement( 'h1' );
 			const domH1 = document.createElement( 'h1' );
 			const viewH1 = createViewRoot( viewDocument, 'h1', 'header' );
 			const viewH1 = createViewRoot( viewDocument, 'h1', 'header' );
 
 
-			expect( count( viewDocument.domRoots ) ).to.equal( 0 );
+			expect( count( view.domRoots ) ).to.equal( 0 );
 
 
-			viewDocument.attachDomRoot( domH1, 'header' );
+			view.attachDomRoot( domH1, 'header' );
 
 
-			expect( count( viewDocument.domRoots ) ).to.equal( 1 );
-			expect( viewDocument.getDomRoot( 'header' ) ).to.equal( domH1 );
-			expect( viewDocument.domConverter.mapViewToDom( viewH1 ) ).to.equal( domH1 );
-			expect( viewDocument.renderer.markedChildren.has( viewH1 ) ).to.be.true;
+			expect( count( view.domRoots ) ).to.equal( 1 );
+			expect( view.getDomRoot( 'header' ) ).to.equal( domH1 );
+			expect( view.domConverter.mapViewToDom( viewH1 ) ).to.equal( domH1 );
+			expect( view.renderer.markedChildren.has( viewH1 ) ).to.be.true;
 		} );
 		} );
 
 
 		it( 'should call observe on each observer', () => {
 		it( 'should call observe on each observer', () => {
 			// The variable will be overwritten.
 			// The variable will be overwritten.
-			viewDocument.destroy();
+			view.destroy();
 
 
-			viewDocument = new Document( document.createElement( 'div' ) );
-			viewDocument.renderer.render = sinon.spy();
+			view = new View();
+			viewDocument = view.document;
+			view.renderer.render = sinon.spy();
 
 
 			const domDiv1 = document.createElement( 'div' );
 			const domDiv1 = document.createElement( 'div' );
 			domDiv1.setAttribute( 'id', 'editor' );
 			domDiv1.setAttribute( 'id', 'editor' );
@@ -113,11 +118,11 @@ describe( 'view', () => {
 			const domDiv2 = document.createElement( 'div' );
 			const domDiv2 = document.createElement( 'div' );
 			domDiv2.setAttribute( 'id', 'editor' );
 			domDiv2.setAttribute( 'id', 'editor' );
 
 
-			const observerMock = viewDocument.addObserver( ObserverMock );
-			const observerMockGlobalCount = viewDocument.addObserver( ObserverMockGlobalCount );
+			const observerMock = view.addObserver( ObserverMock );
+			const observerMockGlobalCount = view.addObserver( ObserverMockGlobalCount );
 
 
 			createViewRoot( viewDocument, 'div', 'root1' );
 			createViewRoot( viewDocument, 'div', 'root1' );
-			viewDocument.attachDomRoot( document.createElement( 'div' ), 'root1' );
+			view.attachDomRoot( document.createElement( 'div' ), 'root1' );
 
 
 			sinon.assert.calledOnce( observerMock.observe );
 			sinon.assert.calledOnce( observerMock.observe );
 			sinon.assert.calledOnce( observerMockGlobalCount.observe );
 			sinon.assert.calledOnce( observerMockGlobalCount.observe );
@@ -127,28 +132,29 @@ describe( 'view', () => {
 	describe( 'addObserver()', () => {
 	describe( 'addObserver()', () => {
 		beforeEach( () => {
 		beforeEach( () => {
 			// The variable will be overwritten.
 			// The variable will be overwritten.
-			viewDocument.destroy();
+			view.destroy();
 
 
-			viewDocument = new Document( document.createElement( 'div' ) );
-			viewDocument.renderer.render = sinon.spy();
+			view = new View();
+			viewDocument = view.document;
+			view.renderer.render = sinon.spy();
 		} );
 		} );
 
 
 		afterEach( () => {
 		afterEach( () => {
-			viewDocument.destroy();
+			view.destroy();
 		} );
 		} );
 
 
 		it( 'should be instantiated and enabled on adding', () => {
 		it( 'should be instantiated and enabled on adding', () => {
-			const observerMock = viewDocument.addObserver( ObserverMock );
+			const observerMock = view.addObserver( ObserverMock );
 
 
-			expect( viewDocument._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 1 );
+			expect( view._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 1 );
 
 
 			expect( observerMock ).to.have.property( 'document', viewDocument );
 			expect( observerMock ).to.have.property( 'document', viewDocument );
 			sinon.assert.calledOnce( observerMock.enable );
 			sinon.assert.calledOnce( observerMock.enable );
 		} );
 		} );
 
 
 		it( 'should return observer instance each time addObserver is called', () => {
 		it( 'should return observer instance each time addObserver is called', () => {
-			const observerMock1 = viewDocument.addObserver( ObserverMock );
-			const observerMock2 = viewDocument.addObserver( ObserverMock );
+			const observerMock1 = view.addObserver( ObserverMock );
+			const observerMock2 = view.addObserver( ObserverMock );
 
 
 			expect( observerMock1 ).to.be.instanceof( ObserverMock );
 			expect( observerMock1 ).to.be.instanceof( ObserverMock );
 			expect( observerMock2 ).to.be.instanceof( ObserverMock );
 			expect( observerMock2 ).to.be.instanceof( ObserverMock );
@@ -156,15 +162,15 @@ describe( 'view', () => {
 		} );
 		} );
 
 
 		it( 'should instantiate one observer only once', () => {
 		it( 'should instantiate one observer only once', () => {
-			viewDocument.addObserver( ObserverMockGlobalCount );
-			viewDocument.addObserver( ObserverMockGlobalCount );
+			view.addObserver( ObserverMockGlobalCount );
+			view.addObserver( ObserverMockGlobalCount );
 
 
-			expect( viewDocument._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 1 );
+			expect( view._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 1 );
 			expect( instantiated ).to.equal( 1 );
 			expect( instantiated ).to.equal( 1 );
 			expect( enabled ).to.equal( 1 );
 			expect( enabled ).to.equal( 1 );
 
 
-			viewDocument.addObserver( ObserverMock );
-			expect( viewDocument._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 2 );
+			view.addObserver( ObserverMock );
+			expect( view._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 2 );
 		} );
 		} );
 
 
 		it( 'should instantiate child class of already registered observer', () => {
 		it( 'should instantiate child class of already registered observer', () => {
@@ -175,18 +181,18 @@ describe( 'view', () => {
 				enable() {}
 				enable() {}
 			}
 			}
 
 
-			viewDocument.addObserver( ObserverMock );
-			viewDocument.addObserver( ChildObserverMock );
+			view.addObserver( ObserverMock );
+			view.addObserver( ChildObserverMock );
 
 
-			expect( viewDocument._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 2 );
+			expect( view._observers.size ).to.equal( DEFAULT_OBSERVERS_COUNT + 2 );
 		} );
 		} );
 
 
 		it( 'should be disabled and re-enabled on render', () => {
 		it( 'should be disabled and re-enabled on render', () => {
-			const observerMock = viewDocument.addObserver( ObserverMock );
-			viewDocument.render();
+			const observerMock = view.addObserver( ObserverMock );
+			view.render();
 
 
 			sinon.assert.calledOnce( observerMock.disable );
 			sinon.assert.calledOnce( observerMock.disable );
-			sinon.assert.calledOnce( viewDocument.renderer.render );
+			sinon.assert.calledOnce( view.renderer.render );
 			sinon.assert.calledTwice( observerMock.enable );
 			sinon.assert.calledTwice( observerMock.enable );
 		} );
 		} );
 
 
@@ -194,10 +200,10 @@ describe( 'view', () => {
 			createViewRoot( viewDocument, 'div', 'roo1' );
 			createViewRoot( viewDocument, 'div', 'roo1' );
 			createViewRoot( viewDocument, 'div', 'roo2' );
 			createViewRoot( viewDocument, 'div', 'roo2' );
 
 
-			viewDocument.attachDomRoot( document.createElement( 'div' ), 'roo1' );
-			viewDocument.attachDomRoot( document.createElement( 'div' ), 'roo2' );
+			view.attachDomRoot( document.createElement( 'div' ), 'roo1' );
+			view.attachDomRoot( document.createElement( 'div' ), 'roo2' );
 
 
-			const observerMock = viewDocument.addObserver( ObserverMock );
+			const observerMock = view.addObserver( ObserverMock );
 
 
 			sinon.assert.calledTwice( observerMock.observe );
 			sinon.assert.calledTwice( observerMock.observe );
 		} );
 		} );
@@ -205,15 +211,15 @@ describe( 'view', () => {
 
 
 	describe( 'getObserver()', () => {
 	describe( 'getObserver()', () => {
 		it( 'should return observer it it is added', () => {
 		it( 'should return observer it it is added', () => {
-			const addedObserverMock = viewDocument.addObserver( ObserverMock );
-			const getObserverMock = viewDocument.getObserver( ObserverMock );
+			const addedObserverMock = view.addObserver( ObserverMock );
+			const getObserverMock = view.getObserver( ObserverMock );
 
 
 			expect( getObserverMock ).to.be.instanceof( ObserverMock );
 			expect( getObserverMock ).to.be.instanceof( ObserverMock );
 			expect( getObserverMock ).to.equal( addedObserverMock );
 			expect( getObserverMock ).to.equal( addedObserverMock );
 		} );
 		} );
 
 
 		it( 'should return undefined if observer is not added', () => {
 		it( 'should return undefined if observer is not added', () => {
-			const getObserverMock = viewDocument.getObserver( ObserverMock );
+			const getObserverMock = view.getObserver( ObserverMock );
 
 
 			expect( getObserverMock ).to.be.undefined;
 			expect( getObserverMock ).to.be.undefined;
 		} );
 		} );
@@ -228,16 +234,16 @@ describe( 'view', () => {
 		it( 'does nothing when there are no ranges in the selection', () => {
 		it( 'does nothing when there are no ranges in the selection', () => {
 			const stub = testUtils.sinon.stub( global.window, 'scrollTo' );
 			const stub = testUtils.sinon.stub( global.window, 'scrollTo' );
 
 
-			viewDocument.scrollToTheSelection();
+			view.scrollToTheSelection();
 			sinon.assert.notCalled( stub );
 			sinon.assert.notCalled( stub );
 		} );
 		} );
 
 
-		it( 'scrolls to the first range in selection with an offset', () => {
+		it.only( 'scrolls to the first range in selection with an offset', () => {
 			const root = createViewRoot( viewDocument, 'div', 'main' );
 			const root = createViewRoot( viewDocument, 'div', 'main' );
 			const stub = testUtils.sinon.stub( global.window, 'scrollTo' );
 			const stub = testUtils.sinon.stub( global.window, 'scrollTo' );
 			const range = ViewRange.createIn( root );
 			const range = ViewRange.createIn( root );
 
 
-			viewDocument.attachDomRoot( domRoot );
+			view.attachDomRoot( domRoot );
 
 
 			// Make sure the window will have to scroll to the domRoot.
 			// Make sure the window will have to scroll to the domRoot.
 			Object.assign( domRoot.style, {
 			Object.assign( domRoot.style, {
@@ -248,19 +254,19 @@ describe( 'view', () => {
 
 
 			viewDocument.selection.addRange( range );
 			viewDocument.selection.addRange( range );
 
 
-			viewDocument.scrollToTheSelection();
+			view.scrollToTheSelection();
 			sinon.assert.calledWithMatch( stub, sinon.match.number, sinon.match.number );
 			sinon.assert.calledWithMatch( stub, sinon.match.number, sinon.match.number );
 		} );
 		} );
 	} );
 	} );
 
 
 	describe( 'disableObservers()', () => {
 	describe( 'disableObservers()', () => {
 		it( 'should disable observers', () => {
 		it( 'should disable observers', () => {
-			const addedObserverMock = viewDocument.addObserver( ObserverMock );
+			const addedObserverMock = view.addObserver( ObserverMock );
 
 
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
 			expect( addedObserverMock.disable.called ).to.be.false;
 			expect( addedObserverMock.disable.called ).to.be.false;
 
 
-			viewDocument.disableObservers();
+			view.disableObservers();
 
 
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
 			expect( addedObserverMock.disable.calledOnce ).to.be.true;
 			expect( addedObserverMock.disable.calledOnce ).to.be.true;
@@ -269,14 +275,14 @@ describe( 'view', () => {
 
 
 	describe( 'enableObservers()', () => {
 	describe( 'enableObservers()', () => {
 		it( 'should enable observers', () => {
 		it( 'should enable observers', () => {
-			const addedObserverMock = viewDocument.addObserver( ObserverMock );
+			const addedObserverMock = view.addObserver( ObserverMock );
 
 
-			viewDocument.disableObservers();
+			view.disableObservers();
 
 
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
 			expect( addedObserverMock.enable.calledOnce ).to.be.true;
 			expect( addedObserverMock.disable.calledOnce ).to.be.true;
 			expect( addedObserverMock.disable.calledOnce ).to.be.true;
 
 
-			viewDocument.enableObservers();
+			view.enableObservers();
 
 
 			expect( addedObserverMock.enable.calledTwice ).to.be.true;
 			expect( addedObserverMock.enable.calledTwice ).to.be.true;
 			expect( addedObserverMock.disable.calledOnce ).to.be.true;
 			expect( addedObserverMock.disable.calledOnce ).to.be.true;
@@ -291,7 +297,7 @@ describe( 'view', () => {
 			domEditable.setAttribute( 'contenteditable', 'true' );
 			domEditable.setAttribute( 'contenteditable', 'true' );
 			document.body.appendChild( domEditable );
 			document.body.appendChild( domEditable );
 			viewEditable = createViewRoot( viewDocument, 'div', 'main' );
 			viewEditable = createViewRoot( viewDocument, 'div', 'main' );
-			viewDocument.attachDomRoot( domEditable );
+			view.attachDomRoot( domEditable );
 			viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewEditable, 0, viewEditable, 0 ) );
 			viewDocument.selection.addRange( ViewRange.createFromParentsAndOffsets( viewEditable, 0, viewEditable, 0 ) );
 		} );
 		} );
 
 
@@ -300,10 +306,10 @@ describe( 'view', () => {
 		} );
 		} );
 
 
 		it( 'should focus editable with selection', () => {
 		it( 'should focus editable with selection', () => {
-			const converterFocusSpy = testUtils.sinon.spy( viewDocument.domConverter, 'focus' );
-			const renderSpy = testUtils.sinon.spy( viewDocument, 'render' );
+			const converterFocusSpy = testUtils.sinon.spy( view.domConverter, 'focus' );
+			const renderSpy = testUtils.sinon.spy( view, 'render' );
 
 
-			viewDocument.focus();
+			view.focus();
 
 
 			expect( converterFocusSpy.called ).to.be.true;
 			expect( converterFocusSpy.called ).to.be.true;
 			expect( renderSpy.calledOnce ).to.be.true;
 			expect( renderSpy.calledOnce ).to.be.true;
@@ -317,11 +323,11 @@ describe( 'view', () => {
 		} );
 		} );
 
 
 		it( 'should not focus if document is already focused', () => {
 		it( 'should not focus if document is already focused', () => {
-			const converterFocusSpy = testUtils.sinon.spy( viewDocument.domConverter, 'focus' );
-			const renderSpy = testUtils.sinon.spy( viewDocument, 'render' );
+			const converterFocusSpy = testUtils.sinon.spy( view.domConverter, 'focus' );
+			const renderSpy = testUtils.sinon.spy( view, 'render' );
 			viewDocument.isFocused = true;
 			viewDocument.isFocused = true;
 
 
-			viewDocument.focus();
+			view.focus();
 
 
 			expect( converterFocusSpy.called ).to.be.false;
 			expect( converterFocusSpy.called ).to.be.false;
 			expect( renderSpy.called ).to.be.false;
 			expect( renderSpy.called ).to.be.false;
@@ -331,7 +337,7 @@ describe( 'view', () => {
 			const logSpy = testUtils.sinon.stub( log, 'warn' );
 			const logSpy = testUtils.sinon.stub( log, 'warn' );
 			viewDocument.selection.removeAllRanges();
 			viewDocument.selection.removeAllRanges();
 
 
-			viewDocument.focus();
+			view.focus();
 			expect( logSpy.calledOnce ).to.be.true;
 			expect( logSpy.calledOnce ).to.be.true;
 			expect( logSpy.args[ 0 ][ 0 ] ).to.match( /^view-focus-no-selection/ );
 			expect( logSpy.args[ 0 ][ 0 ] ).to.match( /^view-focus-no-selection/ );
 		} );
 		} );
@@ -340,33 +346,96 @@ describe( 'view', () => {
 	describe( 'isFocused', () => {
 	describe( 'isFocused', () => {
 		it( 'should change renderer.isFocused too', () => {
 		it( 'should change renderer.isFocused too', () => {
 			expect( viewDocument.isFocused ).to.equal( false );
 			expect( viewDocument.isFocused ).to.equal( false );
-			expect( viewDocument.renderer.isFocused ).to.equal( false );
+			expect( view.renderer.isFocused ).to.equal( false );
 
 
 			viewDocument.isFocused = true;
 			viewDocument.isFocused = true;
 
 
 			expect( viewDocument.isFocused ).to.equal( true );
 			expect( viewDocument.isFocused ).to.equal( true );
-			expect( viewDocument.renderer.isFocused ).to.equal( true );
+			expect( view.renderer.isFocused ).to.equal( true );
 		} );
 		} );
 	} );
 	} );
 
 
 	describe( 'render()', () => {
 	describe( 'render()', () => {
-		it( 'should fire an event', () => {
-			const spy = sinon.spy();
+		it( 'disable observers, renders and enable observers', () => {
+			const observerMock = view.addObserver( ObserverMock );
+			const renderStub = sinon.stub( view.renderer, 'render' );
+
+			view.render();
+
+			sinon.assert.callOrder( observerMock.disable, renderStub, observerMock.enable );
+		} );
+	} );
 
 
-			viewDocument.on( 'render', spy );
+	describe( 'view and DOM integration', () => {
+		it( 'should remove content of the DOM', () => {
+			const domDiv = createElement( document, 'div', { id: 'editor' }, [
+				createElement( document, 'p' ),
+				createElement( document, 'p' )
+			] );
 
 
-			viewDocument.render();
+			const view = new View();
+			const viewDocument = view.document;
 
 
-			expect( spy.calledOnce ).to.be.true;
+			createRoot( 'div', 'main', viewDocument );
+			view.attachDomRoot( domDiv );
+			view.render();
+
+			expect( domDiv.childNodes.length ).to.equal( 1 );
+			expect( isBlockFiller( domDiv.childNodes[ 0 ], BR_FILLER ) ).to.be.true;
+
+			view.destroy();
 		} );
 		} );
 
 
-		it( 'disable observers, renders and enable observers', () => {
-			const observerMock = viewDocument.addObserver( ObserverMock );
-			const renderStub = sinon.stub( viewDocument.renderer, 'render' );
+		it( 'should render changes in the Document', () => {
+			const domDiv = document.createElement( 'div' );
 
 
-			viewDocument.render();
+			const view = new View();
+			const viewDocument = view.document;
+			createRoot( 'div', 'main', viewDocument );
+			view.attachDomRoot( domDiv );
 
 
-			sinon.assert.callOrder( observerMock.disable, renderStub, observerMock.enable );
+			viewDocument.getRoot().appendChildren( new ViewElement( 'p' ) );
+			view.render();
+
+			expect( domDiv.childNodes.length ).to.equal( 1 );
+			expect( domDiv.childNodes[ 0 ].tagName ).to.equal( 'P' );
+
+			view.destroy();
+		} );
+
+		it( 'should render attribute changes', () => {
+			const domRoot = document.createElement( 'div' );
+
+			const view = new View();
+			const viewDocument = view.document;
+			const viewRoot = createRoot( 'div', 'main', viewDocument );
+
+			view.attachDomRoot( domRoot );
+
+			const viewP = new ViewElement( 'p', { class: 'foo' } );
+			viewRoot.appendChildren( viewP );
+			view.render();
+
+			expect( domRoot.childNodes.length ).to.equal( 1 );
+			expect( domRoot.childNodes[ 0 ].getAttribute( 'class' ) ).to.equal( 'foo' );
+
+			viewP.setAttribute( 'class', 'bar' );
+			view.render();
+
+			expect( domRoot.childNodes.length ).to.equal( 1 );
+			expect( domRoot.childNodes[ 0 ].getAttribute( 'class' ) ).to.equal( 'bar' );
+
+			view.destroy();
 		} );
 		} );
 	} );
 	} );
+
+	function createRoot( name, rootName, viewDoc ) {
+		const viewRoot = new RootEditableElement( name );
+
+		viewRoot.rootName = rootName;
+		viewRoot.document = viewDoc;
+		viewDoc.roots.add( viewRoot );
+
+		return viewRoot;
+	}
 } );
 } );