8
0
Просмотр исходного кода

Merge branch t/ckeditor5-watchdog/1

Internal: Add context to CKEditorError exceptions. Required by ckeditor/ckeditor5-watchdog#2.
Piotr Jasiun 6 лет назад
Родитель
Сommit
a4b65a02ff
86 измененных файлов с 842 добавлено и 726 удалено
  1. 4 4
      packages/ckeditor5-engine/src/controller/datacontroller.js
  2. 7 4
      packages/ckeditor5-engine/src/conversion/conversion.js
  3. 1 1
      packages/ckeditor5-engine/src/conversion/upcastdispatcher.js
  4. 1 1
      packages/ckeditor5-engine/src/conversion/viewconsumable.js
  5. 2 0
      packages/ckeditor5-engine/src/model/document.js
  6. 2 0
      packages/ckeditor5-engine/src/model/documentselection.js
  7. 2 1
      packages/ckeditor5-engine/src/model/liveposition.js
  8. 6 6
      packages/ckeditor5-engine/src/model/markercollection.js
  9. 2 2
      packages/ckeditor5-engine/src/model/node.js
  10. 12 6
      packages/ckeditor5-engine/src/model/nodelist.js
  11. 3 1
      packages/ckeditor5-engine/src/model/operation/attributeoperation.js
  12. 1 1
      packages/ckeditor5-engine/src/model/operation/detachoperation.js
  13. 2 1
      packages/ckeditor5-engine/src/model/operation/insertoperation.js
  14. 3 3
      packages/ckeditor5-engine/src/model/operation/mergeoperation.js
  15. 4 4
      packages/ckeditor5-engine/src/model/operation/moveoperation.js
  16. 4 2
      packages/ckeditor5-engine/src/model/operation/renameoperation.js
  17. 4 0
      packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js
  18. 4 4
      packages/ckeditor5-engine/src/model/operation/splitoperation.js
  19. 10 4
      packages/ckeditor5-engine/src/model/operation/utils.js
  20. 27 6
      packages/ckeditor5-engine/src/model/position.js
  21. 4 1
      packages/ckeditor5-engine/src/model/range.js
  22. 16 6
      packages/ckeditor5-engine/src/model/schema.js
  23. 12 4
      packages/ckeditor5-engine/src/model/selection.js
  24. 2 2
      packages/ckeditor5-engine/src/model/textproxy.js
  25. 5 1
      packages/ckeditor5-engine/src/model/treewalker.js
  26. 28 20
      packages/ckeditor5-engine/src/model/writer.js
  27. 2 1
      packages/ckeditor5-engine/src/view/attributeelement.js
  28. 53 48
      packages/ckeditor5-engine/src/view/downcastwriter.js
  29. 1 1
      packages/ckeditor5-engine/src/view/editableelement.js
  30. 4 1
      packages/ckeditor5-engine/src/view/emptyelement.js
  31. 1 1
      packages/ckeditor5-engine/src/view/node.js
  32. 5 3
      packages/ckeditor5-engine/src/view/position.js
  33. 2 2
      packages/ckeditor5-engine/src/view/renderer.js
  34. 8 4
      packages/ckeditor5-engine/src/view/selection.js
  35. 2 2
      packages/ckeditor5-engine/src/view/textproxy.js
  36. 5 1
      packages/ckeditor5-engine/src/view/treewalker.js
  37. 1 1
      packages/ckeditor5-engine/src/view/uielement.js
  38. 2 1
      packages/ckeditor5-engine/src/view/view.js
  39. 13 31
      packages/ckeditor5-engine/tests/controller/datacontroller.js
  40. 8 8
      packages/ckeditor5-engine/tests/conversion/conversion.js
  41. 3 3
      packages/ckeditor5-engine/tests/conversion/upcastdispatcher.js
  42. 9 13
      packages/ckeditor5-engine/tests/model/document.js
  43. 5 5
      packages/ckeditor5-engine/tests/model/documentfragment.js
  44. 25 25
      packages/ckeditor5-engine/tests/model/documentselection.js
  45. 5 5
      packages/ckeditor5-engine/tests/model/element.js
  46. 6 4
      packages/ckeditor5-engine/tests/model/liveposition.js
  47. 13 13
      packages/ckeditor5-engine/tests/model/markercollection.js
  48. 7 11
      packages/ckeditor5-engine/tests/model/node.js
  49. 12 11
      packages/ckeditor5-engine/tests/model/nodelist.js
  50. 8 7
      packages/ckeditor5-engine/tests/model/operation/attributeoperation.js
  51. 4 3
      packages/ckeditor5-engine/tests/model/operation/detachoperation.js
  52. 2 2
      packages/ckeditor5-engine/tests/model/operation/insertoperation.js
  53. 5 5
      packages/ckeditor5-engine/tests/model/operation/mergeoperation.js
  54. 6 5
      packages/ckeditor5-engine/tests/model/operation/moveoperation.js
  55. 6 5
      packages/ckeditor5-engine/tests/model/operation/renameoperation.js
  56. 11 11
      packages/ckeditor5-engine/tests/model/operation/rootattributeoperation.js
  57. 6 5
      packages/ckeditor5-engine/tests/model/operation/splitoperation.js
  58. 5 6
      packages/ckeditor5-engine/tests/model/operation/utils.js
  59. 21 20
      packages/ckeditor5-engine/tests/model/position.js
  60. 4 3
      packages/ckeditor5-engine/tests/model/range.js
  61. 39 40
      packages/ckeditor5-engine/tests/model/schema.js
  62. 17 17
      packages/ckeditor5-engine/tests/model/selection.js
  63. 10 9
      packages/ckeditor5-engine/tests/model/textproxy.js
  64. 10 9
      packages/ckeditor5-engine/tests/model/treewalker.js
  65. 98 97
      packages/ckeditor5-engine/tests/model/writer.js
  66. 4 3
      packages/ckeditor5-engine/tests/view/attributeelement.js
  67. 19 19
      packages/ckeditor5-engine/tests/view/documentselection.js
  68. 18 16
      packages/ckeditor5-engine/tests/view/downcastwriter/breakattributes.js
  69. 6 5
      packages/ckeditor5-engine/tests/view/downcastwriter/breakcontainer.js
  70. 10 8
      packages/ckeditor5-engine/tests/view/downcastwriter/clear.js
  71. 17 14
      packages/ckeditor5-engine/tests/view/downcastwriter/insert.js
  72. 10 9
      packages/ckeditor5-engine/tests/view/downcastwriter/mergecontainers.js
  73. 6 5
      packages/ckeditor5-engine/tests/view/downcastwriter/move.js
  74. 16 14
      packages/ckeditor5-engine/tests/view/downcastwriter/remove.js
  75. 16 14
      packages/ckeditor5-engine/tests/view/downcastwriter/unwrap.js
  76. 18 16
      packages/ckeditor5-engine/tests/view/downcastwriter/wrap.js
  77. 4 3
      packages/ckeditor5-engine/tests/view/editableelement.js
  78. 11 8
      packages/ckeditor5-engine/tests/view/emptyelement.js
  79. 4 6
      packages/ckeditor5-engine/tests/view/node.js
  80. 14 9
      packages/ckeditor5-engine/tests/view/position.js
  81. 6 5
      packages/ckeditor5-engine/tests/view/renderer.js
  82. 20 19
      packages/ckeditor5-engine/tests/view/selection.js
  83. 9 9
      packages/ckeditor5-engine/tests/view/textproxy.js
  84. 9 9
      packages/ckeditor5-engine/tests/view/treewalker.js
  85. 7 7
      packages/ckeditor5-engine/tests/view/uielement.js
  86. 6 4
      packages/ckeditor5-engine/tests/view/view/view.js

+ 4 - 4
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -142,7 +142,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-get-non-existent-root
 			 */
-			throw new CKEditorError( 'datacontroller-get-non-existent-root: Attempting to get data from a non-existing root.' );
+			throw new CKEditorError( 'datacontroller-get-non-existent-root: Attempting to get data from a non-existing root.', this );
 		}
 
 		const root = this.model.document.getRoot( rootName );
@@ -240,7 +240,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-init-document-not-empty
 			 */
-			throw new CKEditorError( 'datacontroller-init-document-not-empty: Trying to set initial data to not empty document.' );
+			throw new CKEditorError( 'datacontroller-init-document-not-empty: Trying to set initial data to not empty document.', this );
 		}
 
 		let initialData = {};
@@ -262,7 +262,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-init-non-existent-root
 			 */
-			throw new CKEditorError( 'datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.' );
+			throw new CKEditorError( 'datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.', this );
 		}
 
 		this.model.enqueueChange( 'transparent', writer => {
@@ -316,7 +316,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-set-non-existent-root
 			 */
-			throw new CKEditorError( 'datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.' );
+			throw new CKEditorError( 'datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.', this );
 		}
 
 		this.model.enqueueChange( 'transparent', writer => {

+ 7 - 4
packages/ckeditor5-engine/src/conversion/conversion.js

@@ -105,8 +105,11 @@ export default class Conversion {
 			 *
 			 * @error conversion-add-alias-dispatcher-not-registered
 			 */
-			throw new CKEditorError( 'conversion-add-alias-dispatcher-not-registered: ' +
-				'Trying to register and alias for a dispatcher that nas not been registered.' );
+			throw new CKEditorError(
+				'conversion-add-alias-dispatcher-not-registered: ' +
+				'Trying to register and alias for a dispatcher that nas not been registered.',
+				this
+			);
 		}
 
 		this._createConversionHelpers( { name: alias, dispatchers: [ dispatcher ], isDowncast } );
@@ -180,7 +183,7 @@ export default class Conversion {
 			 *
 			 * @error conversion-for-unknown-group
 			 */
-			throw new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.' );
+			throw new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.', this );
 		}
 
 		return this._helpers.get( groupName );
@@ -585,7 +588,7 @@ export default class Conversion {
 			 *
 			 * @error conversion-group-exists
 			 */
-			throw new CKEditorError( 'conversion-group-exists: Trying to register a group name that has already been registered.' );
+			throw new CKEditorError( 'conversion-group-exists: Trying to register a group name that has already been registered.', this );
 		}
 
 		const helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers );

+ 1 - 1
packages/ckeditor5-engine/src/conversion/upcastdispatcher.js

@@ -231,7 +231,7 @@ export default class UpcastDispatcher {
 			 *
 			 * @error view-conversion-dispatcher-incorrect-result
 			 */
-			throw new CKEditorError( 'view-conversion-dispatcher-incorrect-result: Incorrect conversion result was dropped.' );
+			throw new CKEditorError( 'view-conversion-dispatcher-incorrect-result: Incorrect conversion result was dropped.', this );
 		}
 
 		return { modelRange: data.modelRange, modelCursor: data.modelCursor };

+ 1 - 1
packages/ckeditor5-engine/src/conversion/viewconsumable.js

@@ -503,7 +503,7 @@ class ViewElementConsumables {
 				 *
 				 * @error viewconsumable-invalid-attribute
 				 */
-				throw new CKEditorError( 'viewconsumable-invalid-attribute: Classes and styles should be handled separately.' );
+				throw new CKEditorError( 'viewconsumable-invalid-attribute: Classes and styles should be handled separately.', this );
 			}
 
 			consumables.set( name, true );

+ 2 - 0
packages/ckeditor5-engine/src/model/document.js

@@ -127,6 +127,7 @@ export default class Document {
 				 */
 				throw new CKEditorError(
 					'model-document-applyOperation-wrong-version: Only operations with matching versions can be applied.',
+					this,
 					{ operation }
 				);
 			}
@@ -201,6 +202,7 @@ export default class Document {
 			 */
 			throw new CKEditorError(
 				'model-document-createRoot-name-exists: Root with specified name already exists.',
+				this,
 				{ name: rootName }
 			);
 		}

+ 2 - 0
packages/ckeditor5-engine/src/model/documentselection.js

@@ -639,6 +639,7 @@ class LiveSelection extends Selection {
 					 */
 					throw new CKEditorError(
 						'document-selection-wrong-position: Range from document selection starts or ends at incorrect position.',
+						this,
 						{ range }
 					);
 				}
@@ -767,6 +768,7 @@ class LiveSelection extends Selection {
 			 */
 			throw new CKEditorError(
 				'document-selection-gravity-wrong-restore: Attempting to restore the selection gravity for an unknown UID.',
+				this,
 				{ uid }
 			);
 		}

+ 2 - 1
packages/ckeditor5-engine/src/model/liveposition.js

@@ -46,7 +46,8 @@ export default class LivePosition extends Position {
 			 * @error liveposition-root-not-rootelement
 			 */
 			throw new CKEditorError(
-				'model-liveposition-root-not-rootelement: LivePosition\'s root has to be an instance of RootElement.'
+				'model-liveposition-root-not-rootelement: LivePosition\'s root has to be an instance of RootElement.',
+				root
 			);
 		}
 

+ 6 - 6
packages/ckeditor5-engine/src/model/markercollection.js

@@ -167,7 +167,7 @@ export default class MarkerCollection {
 		const marker = this._markers.get( markerName );
 
 		if ( !marker ) {
-			throw new CKEditorError( 'markercollection-refresh-marker-not-exists: Marker with provided name does not exists.' );
+			throw new CKEditorError( 'markercollection-refresh-marker-not-exists: Marker with provided name does not exists.', this );
 		}
 
 		const range = marker.getRange();
@@ -383,7 +383,7 @@ class Marker {
 	 */
 	get managedUsingOperations() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
+			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
 		}
 
 		return this._managedUsingOperations;
@@ -396,7 +396,7 @@ class Marker {
 	 */
 	get affectsData() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
+			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
 		}
 
 		return this._affectsData;
@@ -409,7 +409,7 @@ class Marker {
 	 */
 	getStart() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
+			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
 		}
 
 		return this._liveRange.start.clone();
@@ -422,7 +422,7 @@ class Marker {
 	 */
 	getEnd() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
+			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
 		}
 
 		return this._liveRange.end.clone();
@@ -442,7 +442,7 @@ class Marker {
 	 */
 	getRange() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.' );
+			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
 		}
 
 		return this._liveRange.toRange();

+ 2 - 2
packages/ckeditor5-engine/src/model/node.js

@@ -88,7 +88,7 @@ export default class Node {
 		}
 
 		if ( ( pos = this.parent.getChildIndex( this ) ) === null ) {
-			throw new CKEditorError( 'model-node-not-found-in-parent: The node\'s parent does not contain this node.' );
+			throw new CKEditorError( 'model-node-not-found-in-parent: The node\'s parent does not contain this node.', this );
 		}
 
 		return pos;
@@ -112,7 +112,7 @@ export default class Node {
 		}
 
 		if ( ( pos = this.parent.getChildStartOffset( this ) ) === null ) {
-			throw new CKEditorError( 'model-node-not-found-in-parent: The node\'s parent does not contain this node.' );
+			throw new CKEditorError( 'model-node-not-found-in-parent: The node\'s parent does not contain this node.', this );
 		}
 
 		return pos;

+ 12 - 6
packages/ckeditor5-engine/src/model/nodelist.js

@@ -124,7 +124,7 @@ export default class NodeList {
 			 *
 			 * @error nodelist-index-out-of-bounds
 			 */
-			throw new CKEditorError( 'model-nodelist-index-out-of-bounds: Given index cannot be found in the node list.' );
+			throw new CKEditorError( 'model-nodelist-index-out-of-bounds: Given index cannot be found in the node list.', this );
 		}
 
 		return this.getNodeStartOffset( node );
@@ -158,10 +158,13 @@ export default class NodeList {
 			 * @param {Number} offset
 			 * @param {module:engine/model/nodelist~NodeList} nodeList Stringified node list.
 			 */
-			throw new CKEditorError( 'model-nodelist-offset-out-of-bounds: Given offset cannot be found in the node list.', {
-				offset,
-				nodeList: this
-			} );
+			throw new CKEditorError( 'model-nodelist-offset-out-of-bounds: Given offset cannot be found in the node list.',
+				this,
+				{
+					offset,
+					nodeList: this
+				}
+			);
 		}
 
 		return this.length;
@@ -183,7 +186,10 @@ export default class NodeList {
 				 *
 				 * @error nodelist-insertNodes-not-node
 				 */
-				throw new CKEditorError( 'model-nodelist-insertNodes-not-node: Trying to insert an object which is not a Node instance.' );
+				throw new CKEditorError(
+					'model-nodelist-insertNodes-not-node: Trying to insert an object which is not a Node instance.',
+					this
+				);
 			}
 		}
 

+ 3 - 1
packages/ckeditor5-engine/src/model/operation/attributeoperation.js

@@ -128,7 +128,7 @@ export default class AttributeOperation extends Operation {
 			 *
 			 * @error attribute-operation-range-not-flat
 			 */
-			throw new CKEditorError( 'attribute-operation-range-not-flat: The range to change is not flat.' );
+			throw new CKEditorError( 'attribute-operation-range-not-flat: The range to change is not flat.', this );
 		}
 
 		for ( const item of this.range.getItems( { shallow: true } ) ) {
@@ -144,6 +144,7 @@ export default class AttributeOperation extends Operation {
 				throw new CKEditorError(
 					'attribute-operation-wrong-old-value: Changed node has different attribute value than operation\'s ' +
 					'old attribute value.',
+					this,
 					{ item, key: this.key, value: this.oldValue }
 				);
 			}
@@ -158,6 +159,7 @@ export default class AttributeOperation extends Operation {
 				 */
 				throw new CKEditorError(
 					'attribute-operation-attribute-exists: The attribute with given key already exists.',
+					this,
 					{ node: item, key: this.key }
 				);
 			}

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/detachoperation.js

@@ -73,7 +73,7 @@ export default class DetachOperation extends Operation {
 			 *
 			 * @error detach-operation-on-document-node
 			 */
-			throw new CKEditorError( 'detach-operation-on-document-node: Cannot detach document node.' );
+			throw new CKEditorError( 'detach-operation-on-document-node: Cannot detach document node.', this );
 		}
 	}
 

+ 2 - 1
packages/ckeditor5-engine/src/model/operation/insertoperation.js

@@ -115,7 +115,8 @@ export default class InsertOperation extends Operation {
 			 * @error insert-operation-position-invalid
 			 */
 			throw new CKEditorError(
-				'insert-operation-position-invalid: Insertion position is invalid.'
+				'insert-operation-position-invalid: Insertion position is invalid.',
+				this
 			);
 		}
 	}

+ 3 - 3
packages/ckeditor5-engine/src/model/operation/mergeoperation.js

@@ -147,21 +147,21 @@ export default class MergeOperation extends Operation {
 			 *
 			 * @error merge-operation-source-position-invalid
 			 */
-			throw new CKEditorError( 'merge-operation-source-position-invalid: Merge source position is invalid.' );
+			throw new CKEditorError( 'merge-operation-source-position-invalid: Merge source position is invalid.', this );
 		} else if ( !targetElement || !targetElement.is( 'element' ) || !targetElement.parent ) {
 			/**
 			 * Merge target position is invalid.
 			 *
 			 * @error merge-operation-target-position-invalid
 			 */
-			throw new CKEditorError( 'merge-operation-target-position-invalid: Merge target position is invalid.' );
+			throw new CKEditorError( 'merge-operation-target-position-invalid: Merge target position is invalid.', this );
 		} else if ( this.howMany != sourceElement.maxOffset ) {
 			/**
 			 * Merge operation specifies wrong number of nodes to move.
 			 *
 			 * @error merge-operation-how-many-invalid
 			 */
-			throw new CKEditorError( 'merge-operation-how-many-invalid: Merge operation specifies wrong number of nodes to move.' );
+			throw new CKEditorError( 'merge-operation-how-many-invalid: Merge operation specifies wrong number of nodes to move.', this );
 		}
 	}
 

+ 4 - 4
packages/ckeditor5-engine/src/model/operation/moveoperation.js

@@ -130,7 +130,7 @@ export default class MoveOperation extends Operation {
 			 * @error move-operation-position-invalid
 			 */
 			throw new CKEditorError(
-				'move-operation-position-invalid: Source position or target position is invalid.'
+				'move-operation-position-invalid: Source position or target position is invalid.', this
 			);
 		} else if ( sourceOffset + this.howMany > sourceElement.maxOffset ) {
 			/**
@@ -139,7 +139,7 @@ export default class MoveOperation extends Operation {
 			 * @error move-operation-nodes-do-not-exist
 			 */
 			throw new CKEditorError(
-				'move-operation-nodes-do-not-exist: The nodes which should be moved do not exist.'
+				'move-operation-nodes-do-not-exist: The nodes which should be moved do not exist.', this
 			);
 		} else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {
 			/**
@@ -148,7 +148,7 @@ export default class MoveOperation extends Operation {
 			 * @error move-operation-range-into-itself
 			 */
 			throw new CKEditorError(
-				'move-operation-range-into-itself: Trying to move a range of nodes to the inside of that range.'
+				'move-operation-range-into-itself: Trying to move a range of nodes to the inside of that range.', this
 			);
 		} else if ( this.sourcePosition.root == this.targetPosition.root ) {
 			if ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {
@@ -161,7 +161,7 @@ export default class MoveOperation extends Operation {
 					 * @error move-operation-node-into-itself
 					 */
 					throw new CKEditorError(
-						'move-operation-node-into-itself: Trying to move a range of nodes into one of nodes from that range.'
+						'move-operation-node-into-itself: Trying to move a range of nodes into one of nodes from that range.', this
 					);
 				}
 			}

+ 4 - 2
packages/ckeditor5-engine/src/model/operation/renameoperation.js

@@ -94,7 +94,8 @@ export default class RenameOperation extends Operation {
 			 * @error rename-operation-wrong-position
 			 */
 			throw new CKEditorError(
-				'rename-operation-wrong-position: Given position is invalid or node after it is not an instance of Element.'
+				'rename-operation-wrong-position: Given position is invalid or node after it is not an instance of Element.',
+				this
 			);
 		} else if ( element.name !== this.oldName ) {
 			/**
@@ -103,7 +104,8 @@ export default class RenameOperation extends Operation {
 			 * @error rename-operation-wrong-name
 			 */
 			throw new CKEditorError(
-				'rename-operation-wrong-name: Element to change has different name than operation\'s old name.'
+				'rename-operation-wrong-name: Element to change has different name than operation\'s old name.',
+				this
 			);
 		}
 	}

+ 4 - 0
packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js

@@ -116,6 +116,7 @@ export default class RootAttributeOperation extends Operation {
 			 */
 			throw new CKEditorError(
 				'rootattribute-operation-not-a-root: The element to change is not a root element.',
+				this,
 				{ root: this.root, key: this.key }
 			);
 		}
@@ -132,6 +133,7 @@ export default class RootAttributeOperation extends Operation {
 			throw new CKEditorError(
 				'rootattribute-operation-wrong-old-value: Changed node has different attribute value than operation\'s ' +
 				'old attribute value.',
+				this,
 				{ root: this.root, key: this.key }
 			);
 		}
@@ -146,6 +148,7 @@ export default class RootAttributeOperation extends Operation {
 			 */
 			throw new CKEditorError(
 				'rootattribute-operation-attribute-exists: The attribute with given key already exists.',
+				this,
 				{ root: this.root, key: this.key }
 			);
 		}
@@ -197,6 +200,7 @@ export default class RootAttributeOperation extends Operation {
 			 */
 			throw new CKEditorError(
 				'rootattribute-operation-fromjson-no-root: Cannot create RootAttributeOperation. Root with specified name does not exist.',
+				this,
 				{ rootName: json.root }
 			);
 		}

+ 4 - 4
packages/ckeditor5-engine/src/model/operation/splitoperation.js

@@ -149,28 +149,28 @@ export default class SplitOperation extends Operation {
 			 *
 			 * @error split-operation-position-invalid
 			 */
-			throw new CKEditorError( 'split-operation-position-invalid: Split position is invalid.' );
+			throw new CKEditorError( 'split-operation-position-invalid: Split position is invalid.', this );
 		} else if ( !element.parent ) {
 			/**
 			 * Cannot split root element.
 			 *
 			 * @error split-operation-split-in-root
 			 */
-			throw new CKEditorError( 'split-operation-split-in-root: Cannot split root element.' );
+			throw new CKEditorError( 'split-operation-split-in-root: Cannot split root element.', this );
 		} else if ( this.howMany != element.maxOffset - this.splitPosition.offset ) {
 			/**
 			 * Split operation specifies wrong number of nodes to move.
 			 *
 			 * @error split-operation-how-many-invalid
 			 */
-			throw new CKEditorError( 'split-operation-how-many-invalid: Split operation specifies wrong number of nodes to move.' );
+			throw new CKEditorError( 'split-operation-how-many-invalid: Split operation specifies wrong number of nodes to move.', this );
 		} else if ( this.graveyardPosition && !this.graveyardPosition.nodeAfter ) {
 			/**
 			 * Graveyard position invalid.
 			 *
 			 * @error split-operation-graveyard-position-invalid
 			 */
-			throw new CKEditorError( 'split-operation-graveyard-position-invalid: Graveyard position invalid.' );
+			throw new CKEditorError( 'split-operation-graveyard-position-invalid: Graveyard position invalid.', this );
 		}
 	}
 

+ 10 - 4
packages/ckeditor5-engine/src/model/operation/utils.js

@@ -69,8 +69,11 @@ export function _remove( range ) {
 		 *
 		 * @error operation-utils-remove-range-not-flat
 		 */
-		throw new CKEditorError( 'operation-utils-remove-range-not-flat: ' +
-			'Trying to remove a range which starts and ends in different element.' );
+		throw new CKEditorError(
+			'operation-utils-remove-range-not-flat: ' +
+			'Trying to remove a range which starts and ends in different element.',
+			this
+		);
 	}
 
 	const parent = range.start.parent;
@@ -105,8 +108,11 @@ export function _move( sourceRange, targetPosition ) {
 		 *
 		 * @error operation-utils-move-range-not-flat
 		 */
-		throw new CKEditorError( 'operation-utils-move-range-not-flat: ' +
-			'Trying to move a range which starts and ends in different element.' );
+		throw new CKEditorError(
+			'operation-utils-move-range-not-flat: ' +
+			'Trying to move a range which starts and ends in different element.',
+			this
+		);
 	}
 
 	const nodes = _remove( sourceRange );

+ 27 - 6
packages/ckeditor5-engine/src/model/position.js

@@ -61,7 +61,10 @@ export default class Position {
 			 *
 			 * @error model-position-root-invalid
 			 */
-			throw new CKEditorError( 'model-position-root-invalid: Position root invalid.' );
+			throw new CKEditorError(
+				'model-position-root-invalid: Position root invalid.',
+				root
+			);
 		}
 
 		if ( !( path instanceof Array ) || path.length === 0 ) {
@@ -71,7 +74,11 @@ export default class Position {
 			 * @error model-position-path-incorrect
 			 * @param path
 			 */
-			throw new CKEditorError( 'model-position-path-incorrect: Position path must be an array with at least one item.', { path } );
+			throw new CKEditorError(
+				'model-position-path-incorrect: Position path must be an array with at least one item.',
+				root,
+				{ path }
+			);
 		}
 
 		// Normalize the root and path (if element was passed).
@@ -858,7 +865,9 @@ export default class Position {
 				 */
 				throw new CKEditorError(
 					'model-createPositionAt-offset-required: ' +
-					'Model#createPositionAt() requires the offset when the first parameter is a model item.' );
+					'Model#createPositionAt() requires the offset when the first parameter is a model item.',
+					[ this, itemOrPosition ]
+				);
 			}
 
 			if ( !node.is( 'element' ) && !node.is( 'documentFragment' ) ) {
@@ -867,7 +876,10 @@ export default class Position {
 				 *
 				 * @error model-position-parent-incorrect
 				 */
-				throw new CKEditorError( 'model-position-parent-incorrect: Position parent have to be a element or document fragment.' );
+				throw new CKEditorError(
+					'model-position-parent-incorrect: Position parent have to be a element or document fragment.',
+					[ this, itemOrPosition ]
+				);
 			}
 
 			const path = node.getPath();
@@ -894,7 +906,11 @@ export default class Position {
 			 * @error model-position-after-root
 			 * @param {module:engine/model/item~Item} root
 			 */
-			throw new CKEditorError( 'model-position-after-root: You cannot make a position after root.', { root: item } );
+			throw new CKEditorError(
+				'model-position-after-root: You cannot make a position after root.',
+				[ this, item ],
+				{ root: item }
+			);
 		}
 
 		return this._createAt( item.parent, item.endOffset, stickiness );
@@ -916,7 +932,11 @@ export default class Position {
 			 * @error model-position-before-root
 			 * @param {module:engine/model/item~Item} root
 			 */
-			throw new CKEditorError( 'model-position-before-root: You cannot make a position before root.', { root: item } );
+			throw new CKEditorError(
+				'model-position-before-root: You cannot make a position before root.',
+				item,
+				{ root: item }
+			);
 		}
 
 		return this._createAt( item.parent, item.startOffset, stickiness );
@@ -946,6 +966,7 @@ export default class Position {
 			 */
 			throw new CKEditorError(
 				'model-position-fromjson-no-root: Cannot create position for document. Root with specified name does not exist.',
+				doc,
 				{ rootName: json.root }
 			);
 		}

+ 4 - 1
packages/ckeditor5-engine/src/model/range.js

@@ -877,7 +877,10 @@ export default class Range {
 			 *
 			 * @error range-create-from-ranges-empty-array
 			 */
-			throw new CKEditorError( 'range-create-from-ranges-empty-array: At least one range has to be passed.' );
+			throw new CKEditorError(
+				'range-create-from-ranges-empty-array: At least one range has to be passed.',
+				null
+			);
 		} else if ( ranges.length == 1 ) {
 			return ranges[ 0 ].clone();
 		}

+ 16 - 6
packages/ckeditor5-engine/src/model/schema.js

@@ -91,9 +91,13 @@ export default class Schema {
 			 * @param itemName The name of the model element that is being registered twice.
 			 * @error schema-cannot-register-item-twice
 			 */
-			throw new CKEditorError( 'schema-cannot-register-item-twice: A single item cannot be registered twice in the schema.', {
-				itemName
-			} );
+			throw new CKEditorError(
+				'schema-cannot-register-item-twice: A single item cannot be registered twice in the schema.',
+				this,
+				{
+					itemName
+				}
+			);
 		}
 
 		this._sourceDefinitions[ itemName ] = [
@@ -138,7 +142,7 @@ export default class Schema {
 			 * @param itemName The name of the model element which is being extended.
 			 * @error schema-cannot-register-item-twice
 			 */
-			throw new CKEditorError( 'schema-cannot-extend-missing-item: Cannot extend an item which was not registered yet.', {
+			throw new CKEditorError( 'schema-cannot-extend-missing-item: Cannot extend an item which was not registered yet.', this, {
 				itemName
 			} );
 		}
@@ -352,7 +356,10 @@ export default class Schema {
 				 *
 				 * @error schema-check-merge-no-element-before
 				 */
-				throw new CKEditorError( 'schema-check-merge-no-element-before: The node before the merge position must be an element.' );
+				throw new CKEditorError(
+					'schema-check-merge-no-element-before: The node before the merge position must be an element.',
+					this
+				);
 			}
 
 			if ( !( nodeAfter instanceof Element ) ) {
@@ -361,7 +368,10 @@ export default class Schema {
 				 *
 				 * @error schema-check-merge-no-element-after
 				 */
-				throw new CKEditorError( 'schema-check-merge-no-element-after: The node after the merge position must be an element.' );
+				throw new CKEditorError(
+					'schema-check-merge-no-element-after: The node after the merge position must be an element.',
+					this
+				);
 			}
 
 			return this.checkMerge( nodeBefore, nodeAfter );

+ 12 - 4
packages/ckeditor5-engine/src/model/selection.js

@@ -395,7 +395,9 @@ export default class Selection {
 				 */
 				throw new CKEditorError(
 					'model-selection-setTo-required-second-parameter: ' +
-					'selection.setTo requires the second parameter when the first parameter is a node.' );
+					'selection.setTo requires the second parameter when the first parameter is a node.',
+					[ this, selectable ]
+				);
 			}
 
 			this._setRanges( [ range ], backward );
@@ -415,7 +417,10 @@ export default class Selection {
 			 *
 			 * @error model-selection-setTo-not-selectable
 			 */
-			throw new CKEditorError( 'model-selection-setTo-not-selectable: Cannot set the selection to the given place.' );
+			throw new CKEditorError(
+				'model-selection-setTo-not-selectable: Cannot set the selection to the given place.',
+				[ this, selectable ]
+			);
 		}
 	}
 
@@ -449,7 +454,8 @@ export default class Selection {
 				 */
 				throw new CKEditorError(
 					'model-selection-set-ranges-not-range: ' +
-					'Selection range set to an object that is not an instance of model.Range.'
+					'Selection range set to an object that is not an instance of model.Range.',
+					[ this, newRanges ]
 				);
 			}
 
@@ -493,7 +499,8 @@ export default class Selection {
 			 * @error model-selection-setFocus-no-ranges
 			 */
 			throw new CKEditorError(
-				'model-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.'
+				'model-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.',
+				[ this, itemOrPosition ]
 			);
 		}
 
@@ -763,6 +770,7 @@ export default class Selection {
 				 */
 				throw new CKEditorError(
 					'model-selection-range-intersects: Trying to add a range that intersects with another range in the selection.',
+					[ this, range ],
 					{ addedRange: range, intersectingRange: this._ranges[ i ] }
 				);
 			}

+ 2 - 2
packages/ckeditor5-engine/src/model/textproxy.js

@@ -64,7 +64,7 @@ export default class TextProxy {
 			 *
 			 * @error model-textproxy-wrong-offsetintext
 			 */
-			throw new CKEditorError( 'model-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.' );
+			throw new CKEditorError( 'model-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.', this );
 		}
 
 		if ( length < 0 || offsetInText + length > textNode.offsetSize ) {
@@ -73,7 +73,7 @@ export default class TextProxy {
 			 *
 			 * @error model-textproxy-wrong-length
 			 */
-			throw new CKEditorError( 'model-textproxy-wrong-length: Given length value is incorrect.' );
+			throw new CKEditorError( 'model-textproxy-wrong-length: Given length value is incorrect.', this );
 		}
 
 		/**

+ 5 - 1
packages/ckeditor5-engine/src/model/treewalker.js

@@ -42,7 +42,10 @@ export default class TreeWalker {
 			 *
 			 * @error model-tree-walker-no-start-position
 			 */
-			throw new CKEditorError( 'model-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.' );
+			throw new CKEditorError(
+				'model-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.',
+				null
+			);
 		}
 
 		const direction = options.direction || 'forward';
@@ -50,6 +53,7 @@ export default class TreeWalker {
 		if ( direction != 'forward' && direction != 'backward' ) {
 			throw new CKEditorError(
 				'model-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.',
+				options,
 				{ direction }
 			);
 		}

+ 28 - 20
packages/ckeditor5-engine/src/model/writer.js

@@ -186,7 +186,9 @@ export default class Writer {
 					throw new CKEditorError(
 						'model-writer-insert-forbidden-move: ' +
 						'Cannot move a node from a document to a different tree. ' +
-						'It is forbidden to move a node that was already in a document outside of it.' );
+						'It is forbidden to move a node that was already in a document outside of it.',
+						this
+					);
 				} else {
 					// Move between two different document fragments or from document fragment to a document is possible.
 					// In that case, remove the item from it's original parent.
@@ -470,7 +472,7 @@ export default class Writer {
 			 *
 			 * @error writer-move-invalid-range
 			 */
-			throw new CKEditorError( 'writer-move-invalid-range: Invalid range to move.' );
+			throw new CKEditorError( 'writer-move-invalid-range: Invalid range to move.', this );
 		}
 
 		if ( !range.isFlat ) {
@@ -479,7 +481,7 @@ export default class Writer {
 			 *
 			 * @error writer-move-range-not-flat
 			 */
-			throw new CKEditorError( 'writer-move-range-not-flat: Range to move is not flat.' );
+			throw new CKEditorError( 'writer-move-range-not-flat: Range to move is not flat.', this );
 		}
 
 		const position = Position._createAt( itemOrPosition, offset );
@@ -499,7 +501,7 @@ export default class Writer {
 			 *
 			 * @error writer-move-different-document
 			 */
-			throw new CKEditorError( 'writer-move-different-document: Range is going to be moved between different documents.' );
+			throw new CKEditorError( 'writer-move-different-document: Range is going to be moved between different documents.', this );
 		}
 
 		const version = range.root.document ? range.root.document.version : null;
@@ -551,7 +553,7 @@ export default class Writer {
 			 *
 			 * @error writer-merge-no-element-before
 			 */
-			throw new CKEditorError( 'writer-merge-no-element-before: Node before merge position must be an element.' );
+			throw new CKEditorError( 'writer-merge-no-element-before: Node before merge position must be an element.', this );
 		}
 
 		if ( !( nodeAfter instanceof Element ) ) {
@@ -560,7 +562,7 @@ export default class Writer {
 			 *
 			 * @error writer-merge-no-element-after
 			 */
-			throw new CKEditorError( 'writer-merge-no-element-after: Node after merge position must be an element.' );
+			throw new CKEditorError( 'writer-merge-no-element-after: Node after merge position must be an element.', this );
 		}
 
 		if ( !position.root.document ) {
@@ -710,7 +712,8 @@ export default class Writer {
 			 * @error writer-rename-not-element-instance
 			 */
 			throw new CKEditorError(
-				'writer-rename-not-element-instance: Trying to rename an object which is not an instance of Element.'
+				'writer-rename-not-element-instance: Trying to rename an object which is not an instance of Element.',
+				this
 			);
 		}
 
@@ -746,7 +749,7 @@ export default class Writer {
 			 *
 			 * @error writer-split-element-no-parent
 			 */
-			throw new CKEditorError( 'writer-split-element-no-parent: Element with no parent can not be split.' );
+			throw new CKEditorError( 'writer-split-element-no-parent: Element with no parent can not be split.', this );
 		}
 
 		// When limit element is not defined lets set splitElement parent as limit.
@@ -755,7 +758,7 @@ export default class Writer {
 		}
 
 		if ( !position.parent.getAncestors( { includeSelf: true } ).includes( limitElement ) ) {
-			throw new CKEditorError( 'writer-split-invalid-limit-element: Limit element is not a position ancestor.' );
+			throw new CKEditorError( 'writer-split-invalid-limit-element: Limit element is not a position ancestor.', this );
 		}
 
 		// We need to cache elements that will be created as a result of the first split because
@@ -805,7 +808,7 @@ export default class Writer {
 			 *
 			 * @error writer-wrap-range-not-flat
 			 */
-			throw new CKEditorError( 'writer-wrap-range-not-flat: Range to wrap is not flat.' );
+			throw new CKEditorError( 'writer-wrap-range-not-flat: Range to wrap is not flat.', this );
 		}
 
 		const element = elementOrString instanceof Element ? elementOrString : new Element( elementOrString );
@@ -816,7 +819,7 @@ export default class Writer {
 			 *
 			 * @error writer-wrap-element-not-empty
 			 */
-			throw new CKEditorError( 'writer-wrap-element-not-empty: Element to wrap with is not empty.' );
+			throw new CKEditorError( 'writer-wrap-element-not-empty: Element to wrap with is not empty.', this );
 		}
 
 		if ( element.parent !== null ) {
@@ -825,7 +828,7 @@ export default class Writer {
 			 *
 			 * @error writer-wrap-element-attached
 			 */
-			throw new CKEditorError( 'writer-wrap-element-attached: Element to wrap with is already attached to tree model.' );
+			throw new CKEditorError( 'writer-wrap-element-attached: Element to wrap with is already attached to tree model.', this );
 		}
 
 		this.insert( element, range.start );
@@ -851,7 +854,7 @@ export default class Writer {
 			 *
 			 * @error writer-unwrap-element-no-parent
 			 */
-			throw new CKEditorError( 'writer-unwrap-element-no-parent: Trying to unwrap an element which has no parent.' );
+			throw new CKEditorError( 'writer-unwrap-element-no-parent: Trying to unwrap an element which has no parent.', this );
 		}
 
 		this.move( Range._createIn( element ), this.createPositionAfter( element ) );
@@ -907,7 +910,8 @@ export default class Writer {
 			 * @error writer-addMarker-no-usingOperation
 			 */
 			throw new CKEditorError(
-				'writer-addMarker-no-usingOperation: The options.usingOperation parameter is required when adding a new marker.'
+				'writer-addMarker-no-usingOperation: The options.usingOperation parameter is required when adding a new marker.',
+				this
 			);
 		}
 
@@ -921,7 +925,7 @@ export default class Writer {
 			 *
 			 * @error writer-addMarker-marker-exists
 			 */
-			throw new CKEditorError( 'writer-addMarker-marker-exists: Marker with provided name already exists.' );
+			throw new CKEditorError( 'writer-addMarker-marker-exists: Marker with provided name already exists.', this );
 		}
 
 		if ( !range ) {
@@ -930,7 +934,10 @@ export default class Writer {
 			 *
 			 * @error writer-addMarker-no-range
 			 */
-			throw new CKEditorError( 'writer-addMarker-no-range: Range parameter is required when adding a new marker.' );
+			throw new CKEditorError(
+				'writer-addMarker-no-range: Range parameter is required when adding a new marker.',
+				this
+			);
 		}
 
 		if ( !usingOperation ) {
@@ -1023,7 +1030,7 @@ export default class Writer {
 			 *
 			 * @error writer-updateMarker-marker-not-exists
 			 */
-			throw new CKEditorError( 'writer-updateMarker-marker-not-exists: Marker with provided name does not exists.' );
+			throw new CKEditorError( 'writer-updateMarker-marker-not-exists: Marker with provided name does not exists.', this );
 		}
 
 		if ( !options ) {
@@ -1045,7 +1052,8 @@ export default class Writer {
 			 * @error writer-updateMarker-wrong-options
 			 */
 			throw new CKEditorError(
-				'writer-updateMarker-wrong-options: One of the options is required - provide range, usingOperations or affectsData.'
+				'writer-updateMarker-wrong-options: One of the options is required - provide range, usingOperations or affectsData.',
+				this
 			);
 		}
 
@@ -1096,7 +1104,7 @@ export default class Writer {
 			 *
 			 * @error writer-removeMarker-no-marker
 			 */
-			throw new CKEditorError( 'writer-removeMarker-no-marker: Trying to remove marker which does not exist.' );
+			throw new CKEditorError( 'writer-removeMarker-no-marker: Trying to remove marker which does not exist.', this );
 		}
 
 		const marker = this.model.markers.get( name );
@@ -1329,7 +1337,7 @@ export default class Writer {
 		 * @error writer-incorrect-use
 		 */
 		if ( this.model._currentWriter !== this ) {
-			throw new CKEditorError( 'writer-incorrect-use: Trying to use a writer outside the change() block.' );
+			throw new CKEditorError( 'writer-incorrect-use: Trying to use a writer outside the change() block.', this );
 		}
 	}
 

+ 2 - 1
packages/ckeditor5-engine/src/view/attributeelement.js

@@ -116,7 +116,8 @@ export default class AttributeElement extends Element {
 			 */
 			throw new CKEditorError(
 				'attribute-element-get-elements-with-same-id-no-id: ' +
-				'Cannot get elements with the same id for an attribute element without id.'
+				'Cannot get elements with the same id for an attribute element without id.',
+				this
 			);
 		}
 

+ 53 - 48
packages/ckeditor5-engine/src/view/downcastwriter.js

@@ -444,7 +444,8 @@ export default class DowncastWriter {
 			 * @error view-writer-break-non-container-element
 			 */
 			throw new CKEditorError(
-				'view-writer-break-non-container-element: Trying to break an element which is not a container element.'
+				'view-writer-break-non-container-element: Trying to break an element which is not a container element.',
+				this.document
 			);
 		}
 
@@ -454,7 +455,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-break-root
 			 */
-			throw new CKEditorError( 'view-writer-break-root: Trying to break root element.' );
+			throw new CKEditorError( 'view-writer-break-root: Trying to break root element.', this.document );
 		}
 
 		if ( position.isAtStart ) {
@@ -577,7 +578,7 @@ export default class DowncastWriter {
 			 * @error view-writer-merge-containers-invalid-position
 			 */
 			throw new CKEditorError( 'view-writer-merge-containers-invalid-position: ' +
-				'Element before and after given position cannot be merged.' );
+				'Element before and after given position cannot be merged.', this.document );
 		}
 
 		const lastChild = prev.getChild( prev.childCount - 1 );
@@ -612,7 +613,7 @@ export default class DowncastWriter {
 		nodes = isIterable( nodes ) ? [ ...nodes ] : [ nodes ];
 
 		// Check if nodes to insert are instances of AttributeElements, ContainerElements, EmptyElements, UIElements or Text.
-		validateNodesToInsert( nodes );
+		validateNodesToInsert( nodes, this.document );
 
 		const container = getParentContainer( position );
 
@@ -622,7 +623,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-invalid-position-container
 			 */
-			throw new CKEditorError( 'view-writer-invalid-position-container' );
+			throw new CKEditorError( 'view-writer-invalid-position-container', this.document );
 		}
 
 		const insertionPosition = this._breakAttributes( position, true );
@@ -665,7 +666,7 @@ export default class DowncastWriter {
 	remove( rangeOrItem ) {
 		const range = rangeOrItem instanceof Range ? rangeOrItem : Range._createOn( rangeOrItem );
 
-		validateRangeContainer( range );
+		validateRangeContainer( range, this.document );
 
 		// If range is collapsed - nothing to remove.
 		if ( range.isCollapsed ) {
@@ -705,7 +706,7 @@ export default class DowncastWriter {
 	 * @param {module:engine/view/element~Element} element Element to remove.
 	 */
 	clear( range, element ) {
-		validateRangeContainer( range );
+		validateRangeContainer( range, this.document );
 
 		// Create walker on given range.
 		// We walk backward because when we remove element during walk it modifies range end position.
@@ -809,10 +810,10 @@ export default class DowncastWriter {
     */
 	wrap( range, attribute ) {
 		if ( !( attribute instanceof AttributeElement ) ) {
-			throw new CKEditorError( 'view-writer-wrap-invalid-attribute' );
+			throw new CKEditorError( 'view-writer-wrap-invalid-attribute', this.document );
 		}
 
-		validateRangeContainer( range );
+		validateRangeContainer( range, this.document );
 
 		if ( !range.isCollapsed ) {
 			// Non-collapsed range. Wrap it with the attribute element.
@@ -854,10 +855,10 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-unwrap-invalid-attribute
 			 */
-			throw new CKEditorError( 'view-writer-unwrap-invalid-attribute' );
+			throw new CKEditorError( 'view-writer-unwrap-invalid-attribute', this.document );
 		}
 
-		validateRangeContainer( range );
+		validateRangeContainer( range, this.document );
 
 		// If range is collapsed - nothing to unwrap.
 		if ( range.isCollapsed ) {
@@ -1093,7 +1094,7 @@ export default class DowncastWriter {
 			// <p><span class="bar">abc</span></p>  -->  <p><span class="foo bar">abc</span></p>
 			//
 			if ( isAttribute && this._wrapAttributeElement( wrapElement, child ) ) {
-				wrapPositions.push(	new Position( parent, i ) );
+				wrapPositions.push( new Position( parent, i ) );
 			}
 			//
 			// Wrap the child if it is not an attribute element or if it is an attribute element that should be inside
@@ -1113,7 +1114,7 @@ export default class DowncastWriter {
 				parent._insertChild( i, newAttribute );
 				this._addToClonedElementsGroup( newAttribute );
 
-				wrapPositions.push(	new Position( parent, i ) );
+				wrapPositions.push( new Position( parent, i ) );
 			}
 			//
 			// If other nested attribute is found and it wasn't wrapped (see above), continue wrapping inside it.
@@ -1489,7 +1490,7 @@ export default class DowncastWriter {
 		const rangeStart = range.start;
 		const rangeEnd = range.end;
 
-		validateRangeContainer( range );
+		validateRangeContainer( range, this.document );
 
 		// Break at the collapsed position. Return new collapsed range.
 		if ( range.isCollapsed ) {
@@ -1534,7 +1535,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-cannot-break-empty-element
 			 */
-			throw new CKEditorError( 'view-writer-cannot-break-empty-element' );
+			throw new CKEditorError( 'view-writer-cannot-break-empty-element', this.document );
 		}
 
 		// If position is placed inside UIElement - throw an exception as we cannot break inside.
@@ -1544,7 +1545,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-cannot-break-ui-element
 			 */
-			throw new CKEditorError( 'view-writer-cannot-break-ui-element' );
+			throw new CKEditorError( 'view-writer-cannot-break-ui-element', this.document );
 		}
 
 		// There are no attributes to break and text nodes breaking is not forced.
@@ -1571,40 +1572,41 @@ export default class DowncastWriter {
 			const newPosition = new Position( positionParent.parent, positionParent.index + 1 );
 
 			return this._breakAttributes( newPosition, forceSplitText );
-		} else
-		// <p>foo<b><u>{}bar</u></b></p>
-		// <p>foo<b>[]<u>bar</u></b></p>
-		// <p>foo{}<b><u>bar</u></b></p>
-		if ( positionOffset === 0 ) {
-			const newPosition = new Position( positionParent.parent, positionParent.index );
+		} else {
+			// <p>foo<b><u>{}bar</u></b></p>
+			// <p>foo<b>[]<u>bar</u></b></p>
+			// <p>foo{}<b><u>bar</u></b></p>
+			if ( positionOffset === 0 ) {
+				const newPosition = new Position( positionParent.parent, positionParent.index );
 
-			return this._breakAttributes( newPosition, forceSplitText );
-		}
-		// <p>foo<b><u>b{}ar</u></b></p>
-		// <p>foo<b><u>b[]ar</u></b></p>
-		// <p>foo<b><u>b</u>[]<u>ar</u></b></p>
-		// <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>
-		else {
-			const offsetAfter = positionParent.index + 1;
+				return this._breakAttributes( newPosition, forceSplitText );
+			}
+			// <p>foo<b><u>b{}ar</u></b></p>
+			// <p>foo<b><u>b[]ar</u></b></p>
+			// <p>foo<b><u>b</u>[]<u>ar</u></b></p>
+			// <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>
+			else {
+				const offsetAfter = positionParent.index + 1;
 
-			// Break element.
-			const clonedNode = positionParent._clone();
+				// Break element.
+				const clonedNode = positionParent._clone();
 
-			// Insert cloned node to position's parent node.
-			positionParent.parent._insertChild( offsetAfter, clonedNode );
-			this._addToClonedElementsGroup( clonedNode );
+				// Insert cloned node to position's parent node.
+				positionParent.parent._insertChild( offsetAfter, clonedNode );
+				this._addToClonedElementsGroup( clonedNode );
 
-			// Get nodes to move.
-			const count = positionParent.childCount - positionOffset;
-			const nodesToMove = positionParent._removeChildren( positionOffset, count );
+				// Get nodes to move.
+				const count = positionParent.childCount - positionOffset;
+				const nodesToMove = positionParent._removeChildren( positionOffset, count );
 
-			// Move nodes to cloned node.
-			clonedNode._appendChild( nodesToMove );
+				// Move nodes to cloned node.
+				clonedNode._appendChild( nodesToMove );
 
-			// Create new position to work on.
-			const newPosition = new Position( positionParent.parent, offsetAfter );
+				// Create new position to work on.
+				const newPosition = new Position( positionParent.parent, offsetAfter );
 
-			return this._breakAttributes( newPosition, forceSplitText );
+				return this._breakAttributes( newPosition, forceSplitText );
+			}
 		}
 	}
 
@@ -1825,7 +1827,8 @@ function mergeTextNodes( t1, t2 ) {
 //
 // @param Iterable.<module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement
 // |module:engine/view/containerelement~ContainerElement> nodes
-function validateNodesToInsert( nodes ) {
+// @param {Object} errorContext
+function validateNodesToInsert( nodes, errorContext ) {
 	for ( const node of nodes ) {
 		if ( !validNodesToInsert.some( ( validNode => node instanceof validNode ) ) ) { // eslint-disable-line no-use-before-define
 			/**
@@ -1836,11 +1839,11 @@ function validateNodesToInsert( nodes ) {
 			 *
 			 * @error view-writer-insert-invalid-node
 			 */
-			throw new CKEditorError( 'view-writer-insert-invalid-node' );
+			throw new CKEditorError( 'view-writer-insert-invalid-node', errorContext );
 		}
 
 		if ( !node.is( 'text' ) ) {
-			validateNodesToInsert( node.getChildren() );
+			validateNodesToInsert( node.getChildren(), errorContext );
 		}
 	}
 }
@@ -1860,7 +1863,8 @@ function isContainerOrFragment( node ) {
 // Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when validation fails.
 //
 // @param {module:engine/view/range~Range} range
-function validateRangeContainer( range ) {
+// @param {Object} errorContext
+function validateRangeContainer( range, errorContext ) {
 	const startContainer = getParentContainer( range.start );
 	const endContainer = getParentContainer( range.end );
 
@@ -1872,7 +1876,8 @@ function validateRangeContainer( range ) {
 		 *
 		 * @error view-writer-invalid-range-container
 		 */
-		throw new CKEditorError( 'view-writer-invalid-range-container' );
+
+		throw new CKEditorError( 'view-writer-invalid-range-container', errorContext );
 	}
 }
 

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

@@ -104,7 +104,7 @@ export default class EditableElement extends ContainerElement {
 			 *
 			 * @error view-editableelement-document-already-set
 			 */
-			throw new CKEditorError( 'view-editableelement-document-already-set: View document is already set.' );
+			throw new CKEditorError( 'view-editableelement-document-already-set: View document is already set.', this );
 		}
 
 		this._setCustomProperty( documentSymbol, document );

+ 4 - 1
packages/ckeditor5-engine/src/view/emptyelement.js

@@ -68,7 +68,10 @@ export default class EmptyElement extends Element {
 			 *
 			 * @error view-emptyelement-cannot-add
 			 */
-			throw new CKEditorError( 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
+			throw new CKEditorError(
+				'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.',
+				[ this, nodes ]
+			);
 		}
 	}
 }

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

@@ -62,7 +62,7 @@ export default class Node {
 			 *
 			 * @error view-node-not-found-in-parent
 			 */
-			throw new CKEditorError( 'view-node-not-found-in-parent: The node\'s parent does not contain this node.' );
+			throw new CKEditorError( 'view-node-not-found-in-parent: The node\'s parent does not contain this node.', this );
 		}
 
 		return pos;

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

@@ -341,7 +341,9 @@ export default class Position {
 				 */
 				throw new CKEditorError(
 					'view-createPositionAt-offset-required: ' +
-					'View#createPositionAt() requires the offset when the first parameter is a view item.' );
+					'View#createPositionAt() requires the offset when the first parameter is a view item.',
+					node
+				);
 			}
 
 			return new Position( node, offset );
@@ -368,7 +370,7 @@ export default class Position {
 			 * @error view-position-after-root
 			 * @param {module:engine/view/node~Node} root
 			 */
-			throw new CKEditorError( 'view-position-after-root: You can not make position after root.', { root: item } );
+			throw new CKEditorError( 'view-position-after-root: You can not make position after root.', item, { root: item } );
 		}
 
 		return new Position( item.parent, item.index + 1 );
@@ -394,7 +396,7 @@ export default class Position {
 			 * @error view-position-before-root
 			 * @param {module:engine/view/node~Node} root
 			 */
-			throw new CKEditorError( 'view-position-before-root: You can not make position before root.', { root: item } );
+			throw new CKEditorError( 'view-position-before-root: You can not make position before root.', item, { root: item } );
 		}
 
 		return new Position( item.parent, item.index );

+ 2 - 2
packages/ckeditor5-engine/src/view/renderer.js

@@ -152,7 +152,7 @@ export default class Renderer {
 				 *
 				 * @error renderer-unknown-type
 				 */
-				throw new CKEditorError( 'view-renderer-unknown-type: Unknown type passed to Renderer.markToSync.' );
+				throw new CKEditorError( 'view-renderer-unknown-type: Unknown type passed to Renderer.markToSync.', this );
 			}
 		}
 	}
@@ -387,7 +387,7 @@ export default class Renderer {
 			 *
 			 * @error view-renderer-filler-was-lost
 			 */
-			throw new CKEditorError( 'view-renderer-filler-was-lost: The inline filler node was lost.' );
+			throw new CKEditorError( 'view-renderer-filler-was-lost: The inline filler node was lost.', this );
 		}
 
 		if ( isInlineFiller( domFillerNode ) ) {

+ 8 - 4
packages/ckeditor5-engine/src/view/selection.js

@@ -524,7 +524,8 @@ export default class Selection {
 				 */
 				throw new CKEditorError(
 					'view-selection-setTo-required-second-parameter: ' +
-					'selection.setTo requires the second parameter when the first parameter is a node.'
+					'selection.setTo requires the second parameter when the first parameter is a node.',
+					this
 				);
 			} else if ( placeOrOffset == 'in' ) {
 				range = Range._createIn( selectable );
@@ -547,7 +548,7 @@ export default class Selection {
 			 *
 			 * @error view-selection-setTo-not-selectable
 			 */
-			throw new CKEditorError( 'view-selection-setTo-not-selectable: Cannot set selection to given place.' );
+			throw new CKEditorError( 'view-selection-setTo-not-selectable: Cannot set selection to given place.', this );
 		}
 
 		this.fire( 'change' );
@@ -572,7 +573,8 @@ export default class Selection {
 			 * @error view-selection-setFocus-no-ranges
 			 */
 			throw new CKEditorError(
-				'view-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.'
+				'view-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.',
+				this
 			);
 		}
 
@@ -680,7 +682,8 @@ export default class Selection {
 			 */
 			throw new CKEditorError(
 				'view-selection-add-range-not-range: ' +
-				'Selection range set to an object that is not an instance of view.Range'
+				'Selection range set to an object that is not an instance of view.Range',
+				this
 			);
 		}
 
@@ -709,6 +712,7 @@ export default class Selection {
 				 */
 				throw new CKEditorError(
 					'view-selection-range-intersects: Trying to add a range that intersects with another range from selection.',
+					this,
 					{ addedRange: range, intersectingRange: storedRange }
 				);
 			}

+ 2 - 2
packages/ckeditor5-engine/src/view/textproxy.js

@@ -55,7 +55,7 @@ export default class TextProxy {
 			 *
 			 * @error view-textproxy-wrong-offsetintext
 			 */
-			throw new CKEditorError( 'view-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.' );
+			throw new CKEditorError( 'view-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.', this );
 		}
 
 		if ( length < 0 || offsetInText + length > textNode.data.length ) {
@@ -64,7 +64,7 @@ export default class TextProxy {
 			 *
 			 * @error view-textproxy-wrong-length
 			 */
-			throw new CKEditorError( 'view-textproxy-wrong-length: Given length value is incorrect.' );
+			throw new CKEditorError( 'view-textproxy-wrong-length: Given length value is incorrect.', this );
 		}
 
 		/**

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

@@ -42,12 +42,16 @@ export default class TreeWalker {
 			 *
 			 * @error view-tree-walker-no-start-position
 			 */
-			throw new CKEditorError( 'view-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.' );
+			throw new CKEditorError(
+				'view-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.',
+				null
+			);
 		}
 
 		if ( options.direction && options.direction != 'forward' && options.direction != 'backward' ) {
 			throw new CKEditorError(
 				'view-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.',
+				options.startPosition,
 				{ direction: options.direction }
 			);
 		}

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

@@ -81,7 +81,7 @@ export default class UIElement extends Element {
 			 *
 			 * @error view-uielement-cannot-add
 			 */
-			throw new CKEditorError( 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
+			throw new CKEditorError( 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.', this );
 		}
 	}
 

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

@@ -451,7 +451,8 @@ export default class View {
 			throw new CKEditorError(
 				'cannot-change-view-tree: ' +
 				'Attempting to make changes to the view when it is in an incorrect state: rendering or post-fixers are in progress. ' +
-				'This may cause some unexpected behavior and inconsistency between the DOM and the view.'
+				'This may cause some unexpected behavior and inconsistency between the DOM and the view.',
+				this
 			);
 		}
 

+ 13 - 31
packages/ckeditor5-engine/tests/controller/datacontroller.js

@@ -8,7 +8,6 @@ import ModelRange from '../../src/model/range';
 import ViewRange from '../../src/view/range';
 import DataController from '../../src/controller/datacontroller';
 import HtmlDataProcessor from '../../src/dataprocessor/htmldataprocessor';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import ModelDocumentFragment from '../../src/model/documentfragment';
 import ViewDocumentFragment from '../../src/view/documentfragment';
@@ -20,6 +19,7 @@ import count from '@ckeditor/ckeditor5-utils/src/count';
 
 import UpcastHelpers from '../../src/conversion/upcasthelpers';
 import DowncastHelpers from '../../src/conversion/downcasthelpers';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DataController', () => {
 	let model, modelDocument, htmlDataProcessor, data, schema, upcastHelpers, downcastHelpers;
@@ -173,12 +173,9 @@ describe( 'DataController', () => {
 		it( 'should throw an error when document data is already initialized', () => {
 			data.init( '<p>Foo</p>' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				data.init( '<p>Bar</p>' );
-			} ).to.throw(
-				CKEditorError,
-				'datacontroller-init-document-not-empty: Trying to set initial data to not empty document.'
-			);
+			}, /datacontroller-init-document-not-empty:/, model );
 		} );
 
 		it( 'should set data to default main root', () => {
@@ -230,23 +227,17 @@ describe( 'DataController', () => {
 		} );
 
 		it( 'should throw an error when non-existent root is used (single)', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				data.init( { nonexistent: '<p>Bar</p>' } );
-			} ).to.throw(
-				CKEditorError,
-				'datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.'
-			);
+			}, /^datacontroller-init-non-existent-root:/ );
 		} );
 
 		it( 'should throw an error when non-existent root is used (one of many)', () => {
 			schema.extend( '$text', { allowIn: '$root' } );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				data.init( { main: 'bar', nonexistent: '<p>Bar</p>' } );
-			} ).to.throw(
-				CKEditorError,
-				'datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.'
-			);
+			}, /^datacontroller-init-non-existent-root:/, model );
 
 			expect( getData( model, { withoutSelection: true } ) ).to.equal( '' );
 		} );
@@ -315,24 +306,18 @@ describe( 'DataController', () => {
 		} );
 
 		it( 'should throw an error when non-existent root is used (single)', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				data.set( { nonexistent: '<p>Bar</p>' } );
-			} ).to.throw(
-				CKEditorError,
-				'datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.'
-			);
+			}, /datacontroller-set-non-existent-root:/, model );
 		} );
 
 		it( 'should throw an error when non-existent root is used (one of many) without touching any roots data', () => {
 			schema.extend( '$text', { allowIn: '$root' } );
 			data.set( 'foo' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				data.set( { main: 'bar', nonexistent: '<p>Bar</p>' } );
-			} ).to.throw(
-				CKEditorError,
-				'datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.'
-			);
+			}, /datacontroller-set-non-existent-root:/, model );
 
 			expect( getData( model, { withoutSelection: true } ) ).to.equal( 'foo' );
 		} );
@@ -441,12 +426,9 @@ describe( 'DataController', () => {
 		} );
 
 		it( 'should throw an error when non-existent root is used', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				data.get( { rootName: 'nonexistent' } );
-			} ).to.throw(
-				CKEditorError,
-				'datacontroller-get-non-existent-root: Attempting to get data from a non-existing root.'
-			);
+			}, /datacontroller-get-non-existent-root:/ );
 		} );
 	} );
 

+ 8 - 8
packages/ckeditor5-engine/tests/conversion/conversion.js

@@ -4,7 +4,6 @@
  */
 
 import Conversion from '../../src/conversion/conversion';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import UpcastDispatcher from '../../src/conversion/upcastdispatcher';
 
@@ -18,6 +17,7 @@ import Model from '../../src/model/model';
 import { parse as viewParse, stringify as viewStringify } from '../../src/dev-utils/view';
 import { stringify as modelStringify } from '../../src/dev-utils/model';
 import ConversionHelpers from '../../src/conversion/conversionhelpers';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Conversion', () => {
 	let conversion, downcastDispA, upcastDispaA, downcastDispB;
@@ -34,15 +34,15 @@ describe( 'Conversion', () => {
 
 	describe( 'addAlias()', () => {
 		it( 'should throw when trying to use same group name twice', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				conversion.addAlias( 'upcast', upcastDispaA );
-			} ).to.throw( CKEditorError, /conversion-group-exists/ );
+			}, /conversion-group-exists/ );
 		} );
 
 		it( 'should throw when trying to add not registered dispatcher', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				conversion.addAlias( 'foo', {} );
-			} ).to.throw( CKEditorError, /conversion-add-alias-dispatcher-not-registered/ );
+			}, /conversion-add-alias-dispatcher-not-registered/ );
 		} );
 	} );
 
@@ -53,9 +53,9 @@ describe( 'Conversion', () => {
 		} );
 
 		it( 'should throw if non-existing group name has been used', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				conversion.for( 'foo' );
-			} ).to.throw( CKEditorError, /conversion-for-unknown-group/ );
+			}, /conversion-for-unknown-group/ );
 		} );
 
 		it( 'should return proper helpers for group', () => {
@@ -81,7 +81,7 @@ describe( 'Conversion', () => {
 
 		it( 'should be chainable', () => {
 			const helpers = conversion.for( 'upcast' );
-			const addResult = helpers.add( () => {} );
+			const addResult = helpers.add( () => { } );
 
 			expect( addResult ).to.equal( helpers );
 		} );

+ 3 - 3
packages/ckeditor5-engine/tests/conversion/upcastdispatcher.js

@@ -19,7 +19,7 @@ import ModelRange from '../../src/model/range';
 import ModelWriter from '../../src/model/writer';
 
 import first from '@ckeditor/ckeditor5-utils/src/first';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'UpcastDispatcher', () => {
 	let model;
@@ -472,9 +472,9 @@ describe( 'UpcastDispatcher', () => {
 					conversionApi.convertItem( viewArray, data.modelCursor );
 				} );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) );
-				} ).to.throw( CKEditorError, /^view-conversion-dispatcher-incorrect-result/ );
+				}, /^view-conversion-dispatcher-incorrect-result/, model );
 
 				expect( spy.calledOnce ).to.be.true;
 				expect( spyArray.calledOnce ).to.be.true;

+ 9 - 13
packages/ckeditor5-engine/tests/model/document.js

@@ -9,8 +9,8 @@ import RootElement from '../../src/model/rootelement';
 import Text from '../../src/model/text';
 import Batch from '../../src/model/batch';
 import Collection from '@ckeditor/ckeditor5-utils/src/collection';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import count from '@ckeditor/ckeditor5-utils/src/count';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Document', () => {
 	let model, doc;
@@ -44,7 +44,7 @@ describe( 'Document', () => {
 				baseVersion: 0,
 				isDocumentOperation: true,
 				_execute: sinon.stub().returns( data ),
-				_validate: () => {}
+				_validate: () => { }
 			};
 
 			batch = new Batch();
@@ -82,14 +82,12 @@ describe( 'Document', () => {
 			const operation = {
 				baseVersion: 1,
 				isDocumentOperation: true,
-				_execute: () => {}
+				_execute: () => { }
 			};
 
-			expect(
-				() => {
-					model.applyOperation( operation );
-				}
-			).to.throw( CKEditorError, /^model-document-applyOperation-wrong-version/ );
+			expectToThrowCKEditorError( () => {
+				model.applyOperation( operation );
+			}, /^model-document-applyOperation-wrong-version/, model );
 		} );
 	} );
 
@@ -130,11 +128,9 @@ describe( 'Document', () => {
 		it( 'should throw an error when trying to create a second root with the same name', () => {
 			doc.createRoot( '$root', 'rootName' );
 
-			expect(
-				() => {
-					doc.createRoot( '$root', 'rootName' );
-				}
-			).to.throw( CKEditorError, /model-document-createRoot-name-exists/ );
+			expectToThrowCKEditorError( () => {
+				doc.createRoot( '$root', 'rootName' );
+			}, /model-document-createRoot-name-exists/, model );
 		} );
 	} );
 

+ 5 - 5
packages/ckeditor5-engine/tests/model/documentfragment.js

@@ -7,7 +7,7 @@ import Element from '../../src/model/element';
 import Text from '../../src/model/text';
 import TextProxy from '../../src/model/textproxy';
 import DocumentFragment from '../../src/model/documentfragment';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DocumentFragment', () => {
 	describe( 'constructor()', () => {
@@ -111,13 +111,13 @@ describe( 'DocumentFragment', () => {
 		} );
 
 		it( 'should throw if given offset is too high or too low', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				frag.offsetToIndex( -1 );
-			} ).to.throw( CKEditorError, /nodelist-offset-out-of-bounds/ );
+			}, /nodelist-offset-out-of-bounds/, frag );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				frag.offsetToIndex( 55 );
-			} ).to.throw( CKEditorError, /nodelist-offset-out-of-bounds/ );
+			}, /nodelist-offset-out-of-bounds/, frag );
 		} );
 
 		it( 'should return length if given offset is equal to maxOffset', () => {

+ 25 - 25
packages/ckeditor5-engine/tests/model/documentselection.js

@@ -15,11 +15,11 @@ import InsertOperation from '../../src/model/operation/insertoperation';
 import MoveOperation from '../../src/model/operation/moveoperation';
 import AttributeOperation from '../../src/model/operation/attributeoperation';
 import SplitOperation from '../../src/model/operation/splitoperation';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import { setData, getData } from '../../src/dev-utils/model';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DocumentSelection', () => {
 	let model, doc, root, selection, liveRange, range;
@@ -596,9 +596,9 @@ describe( 'DocumentSelection', () => {
 
 	describe( '_setTo()', () => {
 		it( 'should throw an error when range is invalid', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection._setTo( [ { invalid: 'range' } ] );
-			} ).to.throw( CKEditorError, /model-selection-set-ranges-not-range/ );
+			}, /model-selection-set-ranges-not-range/, model );
 		} );
 
 		it( 'should log a warning when trying to set selection to the graveyard', () => {
@@ -1094,19 +1094,19 @@ describe( 'DocumentSelection', () => {
 			selection._restoreGravity( overrideUid );
 
 			// Wrong UID
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection._restoreGravity( 'foo' );
-			} ).to.throw( CKEditorError, /^document-selection-gravity-wrong-restore/ );
+			}, /^document-selection-gravity-wrong-restore/, model );
 
 			// Already restored
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection._restoreGravity( overrideUid );
-			} ).to.throw( CKEditorError, /^document-selection-gravity-wrong-restore/ );
+			}, /^document-selection-gravity-wrong-restore/, model );
 
 			// No UID
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection._restoreGravity();
-			} ).to.throw( CKEditorError, /^document-selection-gravity-wrong-restore/ );
+			}, /^document-selection-gravity-wrong-restore/, model );
 		} );
 
 		it( 'should revert default gravity when is overridden', () => {
@@ -1601,41 +1601,41 @@ describe( 'DocumentSelection', () => {
 		root._removeChildren( 0, root.childCount );
 		root._appendChild( '\uD83D\uDCA9' );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 0 ), Position._createAt( root, 1 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 2 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 	} );
 
 	it( 'should throw if one of ranges starts or ends between base character and combining mark', () => {
 		root._removeChildren( 0, root.childCount );
 		root._appendChild( 'foo̻̐ͩbar' );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 3 ), Position._createAt( root, 9 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 4 ), Position._createAt( root, 9 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 5 ), Position._createAt( root, 9 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 3 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 4 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			doc.selection._setTo( new Range( Position._createAt( root, 1 ), Position._createAt( root, 5 ) ) );
-		} ).to.throw( CKEditorError, /document-selection-wrong-position/ );
+		}, /document-selection-wrong-position/, model );
 	} );
 } );

+ 5 - 5
packages/ckeditor5-engine/tests/model/element.js

@@ -8,7 +8,7 @@ import Element from '../../src/model/element';
 import Text from '../../src/model/text';
 import TextProxy from '../../src/model/textproxy';
 import count from '@ckeditor/ckeditor5-utils/src/count';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Element', () => {
 	describe( 'constructor()', () => {
@@ -301,13 +301,13 @@ describe( 'Element', () => {
 		} );
 
 		it( 'should throw if given offset is too high or too low', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				element.offsetToIndex( -1 );
-			} ).to.throw( CKEditorError, /nodelist-offset-out-of-bounds/ );
+			}, /nodelist-offset-out-of-bounds/, element );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				element.offsetToIndex( 55 );
-			} ).to.throw( CKEditorError, /nodelist-offset-out-of-bounds/ );
+			}, /nodelist-offset-out-of-bounds/, element );
 		} );
 
 		it( 'should return length if given offset is equal to maxOffset', () => {

+ 6 - 4
packages/ckeditor5-engine/tests/model/liveposition.js

@@ -10,7 +10,7 @@ import Text from '../../src/model/text';
 import Position from '../../src/model/position';
 import LivePosition from '../../src/model/liveposition';
 import Range from '../../src/model/range';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'LivePosition', () =>
 {
@@ -42,9 +42,11 @@ describe( 'LivePosition', () =>
 	} );
 
 	it( 'should throw if given root is not a RootElement', () => {
-		expect( () => {
-			new LivePosition( new DocumentFragment(), [ 1 ] ); // eslint-disable-line no-new
-		} ).to.throw( CKEditorError, /model-liveposition-root-not-rootelement/ );
+		const docFrag = new DocumentFragment();
+
+		expectToThrowCKEditorError( () => {
+			new LivePosition( docFrag, [ 1 ] ); // eslint-disable-line no-new
+		}, /model-liveposition-root-not-rootelement/, docFrag );
 	} );
 
 	it( 'should listen to the model applyOperation event', () => {

+ 13 - 13
packages/ckeditor5-engine/tests/model/markercollection.js

@@ -9,7 +9,7 @@ import Range from '../../src/model/range';
 import LiveRange from '../../src/model/liverange';
 import Text from '../../src/model/text';
 import Model from '../../src/model/model';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'MarkerCollection', () => {
 	let markers, range, range2, doc, root;
@@ -207,9 +207,9 @@ describe( 'MarkerCollection', () => {
 		} );
 
 		it( 'should throw if marker does not exist', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				markers._refresh( 'name' );
-			} ).to.throw( CKEditorError, 'markercollection-refresh-marker-not-exists: Marker with provided name does not exists.' );
+			}, /^markercollection-refresh-marker-not-exists:/, markers );
 		} );
 	} );
 
@@ -292,25 +292,25 @@ describe( 'Marker', () => {
 
 		model.markers._remove( 'name' );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			marker.getRange();
-		} ).to.throw( CKEditorError, /^marker-destroyed/ );
+		}, /^marker-destroyed/ );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			marker.getStart();
-		} ).to.throw( CKEditorError, /^marker-destroyed/ );
+		}, /^marker-destroyed/ );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			marker.getEnd();
-		} ).to.throw( CKEditorError, /^marker-destroyed/ );
+		}, /^marker-destroyed/ );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			marker.managedUsingOperations;
-		} ).to.throw( CKEditorError, /^marker-destroyed/ );
+		}, /^marker-destroyed/ );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			marker.affectsData;
-		} ).to.throw( CKEditorError, /^marker-destroyed/ );
+		}, /^marker-destroyed/ );
 	} );
 
 	it( 'should attach live range to marker', () => {

+ 7 - 11
packages/ckeditor5-engine/tests/model/node.js

@@ -8,8 +8,8 @@ import DocumentFragment from '../../src/model/documentfragment';
 import Node from '../../src/model/node';
 import Element from '../../src/model/element';
 import Text from '../../src/model/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import count from '@ckeditor/ckeditor5-utils/src/count';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Node', () => {
 	let doc, root, node,
@@ -128,11 +128,9 @@ describe( 'Node', () => {
 		it( 'should throw an error if parent does not contain element', () => {
 			node.parent = new Element( 'parent' );
 
-			expect(
-				() => {
-					node.index;
-				}
-			).to.throw( CKEditorError, /model-node-not-found-in-parent/ );
+			expectToThrowCKEditorError( () => {
+				node.index;
+			}, /model-node-not-found-in-parent/, node.parent );
 		} );
 	} );
 
@@ -188,11 +186,9 @@ describe( 'Node', () => {
 		it( 'should throw an error if parent does not contain element', () => {
 			node.parent = new Element( 'parent' );
 
-			expect(
-				() => {
-					node.startOffset;
-				}
-			).to.throw( CKEditorError, /model-node-not-found-in-parent/ );
+			expectToThrowCKEditorError( () => {
+				node.startOffset;
+			}, /model-node-not-found-in-parent/, node.parent );
 		} );
 	} );
 

+ 12 - 11
packages/ckeditor5-engine/tests/model/nodelist.js

@@ -6,7 +6,8 @@
 import NodeList from '../../src/model/nodelist';
 import Element from '../../src/model/element';
 import Text from '../../src/model/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'NodeList', () => {
 	let nodes, p, foo, img;
@@ -82,13 +83,13 @@ describe( 'NodeList', () => {
 		} );
 
 		it( 'should throw if given offset is too high or too low', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				nodes.indexToOffset( -1 );
-			} ).to.throw( CKEditorError, /model-nodelist-index-out-of-bounds/ );
+			}, /model-nodelist-index-out-of-bounds/, nodes );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				nodes.indexToOffset( 99 );
-			} ).to.throw( CKEditorError, /model-nodelist-index-out-of-bounds/ );
+			}, /model-nodelist-index-out-of-bounds/, nodes );
 		} );
 
 		it( 'should return length if given offset is equal to maxOffset', () => {
@@ -106,13 +107,13 @@ describe( 'NodeList', () => {
 		} );
 
 		it( 'should throw if given offset is too high or too low', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				nodes.offsetToIndex( -1 );
-			} ).to.throw( CKEditorError, /nodelist-offset-out-of-bounds/ );
+			}, /nodelist-offset-out-of-bounds/, nodes );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				nodes.offsetToIndex( 55 );
-			} ).to.throw( CKEditorError, /nodelist-offset-out-of-bounds/ );
+			}, /nodelist-offset-out-of-bounds/, nodes );
 		} );
 
 		it( 'should return length if given offset is equal to maxOffset', () => {
@@ -157,9 +158,9 @@ describe( 'NodeList', () => {
 		} );
 
 		it( 'should throw if not a Node is inserted', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				nodes._insertNodes( 0, [ 'foo' ] );
-			} ).to.throw( CKEditorError, /nodelist-insertNodes-not-node/ );
+			}, /nodelist-insertNodes-not-node/, nodes );
 		} );
 	} );
 

+ 8 - 7
packages/ckeditor5-engine/tests/model/operation/attributeoperation.js

@@ -9,8 +9,9 @@ import Element from '../../../src/model/element';
 import AttributeOperation from '../../../src/model/operation/attributeoperation';
 import Position from '../../../src/model/position';
 import Range from '../../../src/model/range';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import count from '@ckeditor/ckeditor5-utils/src/count';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'AttributeOperation', () => {
 	let model, doc, root;
@@ -202,7 +203,7 @@ describe( 'AttributeOperation', () => {
 		it( 'should throw an error when one try to remove and the attribute does not exists', () => {
 			root._insertChild( 0, new Text( 'x' ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const operation = new AttributeOperation(
 					new Range( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) ),
 					'foo',
@@ -212,13 +213,13 @@ describe( 'AttributeOperation', () => {
 				);
 
 				operation._validate();
-			} ).to.throw( CKEditorError, /attribute-operation-wrong-old-value/ );
+			}, /attribute-operation-wrong-old-value/, model );
 		} );
 
 		it( 'should throw an error when one try to insert and the attribute already exists', () => {
 			root._insertChild( 0, new Text( 'x', { x: 1 } ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const operation = new AttributeOperation(
 					new Range( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) ),
 					'x',
@@ -228,7 +229,7 @@ describe( 'AttributeOperation', () => {
 				);
 
 				operation._validate();
-			} ).to.throw( CKEditorError, /attribute-operation-attribute-exists/ );
+			}, /attribute-operation-attribute-exists/, model );
 		} );
 
 		it( 'should not throw when attribute value is the same', () => {
@@ -253,7 +254,7 @@ describe( 'AttributeOperation', () => {
 				new Element( 'paragraph', null, new Text( 'Bar' ) )
 			] );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const operation = new AttributeOperation(
 					new Range( new Position( root, [ 0, 1 ] ), new Position( root, [ 1, 1 ] ) ),
 					'x',
@@ -263,7 +264,7 @@ describe( 'AttributeOperation', () => {
 				);
 
 				operation._validate();
-			} ).to.throw( CKEditorError, /attribute-operation-range-not-flat/ );
+			}, /attribute-operation-range-not-flat/, model );
 		} );
 	} );
 

+ 4 - 3
packages/ckeditor5-engine/tests/model/operation/detachoperation.js

@@ -5,10 +5,11 @@
 
 import Model from '../../../src/model/model';
 import DetachOperation from '../../../src/model/operation/detachoperation';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import Position from '../../../src/model/position';
 import DocumentFragment from '../../../src/model/documentfragment';
 import Element from '../../../src/model/element';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DetachOperation', () => {
 	let model, doc, docFrag, element;
@@ -43,9 +44,9 @@ describe( 'DetachOperation', () => {
 
 			const op = new DetachOperation( Position._createBefore( element ), 1 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				op._validate();
-			} ).to.throw( CKEditorError, /^detach-operation-on-document-node/ );
+			}, /^detach-operation-on-document-node/, model );
 		} );
 	} );
 

+ 2 - 2
packages/ckeditor5-engine/tests/model/operation/insertoperation.js

@@ -10,7 +10,7 @@ import InsertOperation from '../../../src/model/operation/insertoperation';
 import MoveOperation from '../../../src/model/operation/moveoperation';
 import Position from '../../../src/model/position';
 import Text from '../../../src/model/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'InsertOperation', () => {
 	let model, doc, root;
@@ -225,7 +225,7 @@ describe( 'InsertOperation', () => {
 			const element = new Element( 'p' );
 			const op = new InsertOperation( new Position( root, [ 4 ] ), element, doc.version );
 
-			expect( () => op._validate() ).to.throw( CKEditorError, /insert-operation-position-invalid/ );
+			expectToThrowCKEditorError( () => op._validate(), /insert-operation-position-invalid/, model );
 		} );
 	} );
 

+ 5 - 5
packages/ckeditor5-engine/tests/model/operation/mergeoperation.js

@@ -9,7 +9,7 @@ import SplitOperation from '../../../src/model/operation/splitoperation';
 import Position from '../../../src/model/position';
 import Element from '../../../src/model/element';
 import Text from '../../../src/model/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'MergeOperation', () => {
 	let model, doc, root, gy, gyPos;
@@ -119,7 +119,7 @@ describe( 'MergeOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /merge-operation-target-position-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /merge-operation-target-position-invalid/, model );
 		} );
 
 		it( 'should throw an error if source position is in root', () => {
@@ -136,7 +136,7 @@ describe( 'MergeOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /merge-operation-source-position-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /merge-operation-source-position-invalid/, model );
 		} );
 
 		it( 'should throw an error if target position is invalid', () => {
@@ -153,7 +153,7 @@ describe( 'MergeOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /merge-operation-source-position-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /merge-operation-source-position-invalid/, model );
 		} );
 
 		it( 'should throw an error if number of nodes to move is invalid', () => {
@@ -170,7 +170,7 @@ describe( 'MergeOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /merge-operation-how-many-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /merge-operation-how-many-invalid/, model );
 		} );
 	} );
 

+ 6 - 5
packages/ckeditor5-engine/tests/model/operation/moveoperation.js

@@ -8,7 +8,8 @@ import MoveOperation from '../../../src/model/operation/moveoperation';
 import Position from '../../../src/model/position';
 import Element from '../../../src/model/element';
 import Text from '../../../src/model/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'MoveOperation', () => {
 	let model, doc, root, gy;
@@ -153,7 +154,7 @@ describe( 'MoveOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /move-operation-nodes-do-not-exist/ );
+			expectToThrowCKEditorError( () => operation._validate(), /move-operation-nodes-do-not-exist/, model );
 		} );
 
 		it( 'should throw an error if target or source parent-element specified by position does not exist', () => {
@@ -170,7 +171,7 @@ describe( 'MoveOperation', () => {
 
 			root._removeChildren( 1 );
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /move-operation-position-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /move-operation-position-invalid/, model );
 		} );
 
 		it( 'should throw an error if operation tries to move a range between the beginning and the end of that range', () => {
@@ -183,7 +184,7 @@ describe( 'MoveOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /move-operation-range-into-itself/ );
+			expectToThrowCKEditorError( () => operation._validate(), /move-operation-range-into-itself/, model );
 		} );
 
 		it( 'should throw an error if operation tries to move a range into a sub-tree of a node that is in that range', () => {
@@ -197,7 +198,7 @@ describe( 'MoveOperation', () => {
 				doc.version
 			);
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /move-operation-node-into-itself/ );
+			expectToThrowCKEditorError( () => operation._validate(), /move-operation-node-into-itself/, model );
 		} );
 
 		it( 'should not throw an error if operation move a range into a sibling', () => {

+ 6 - 5
packages/ckeditor5-engine/tests/model/operation/renameoperation.js

@@ -7,7 +7,8 @@ import Model from '../../../src/model/model';
 import Element from '../../../src/model/element';
 import RenameOperation from '../../../src/model/operation/renameoperation';
 import Position from '../../../src/model/position';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'RenameOperation', () => {
 	const oldName = 'oldName';
@@ -66,17 +67,17 @@ describe( 'RenameOperation', () => {
 		it( 'should throw an error if position is not before an element', () => {
 			const op = new RenameOperation( Position._createAt( root, 'end' ), oldName, newName, doc.version );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				op._validate();
-			} ).to.throw( CKEditorError, /rename-operation-wrong-position/ );
+			}, /rename-operation-wrong-position/, model );
 		} );
 
 		it( 'should throw an error if oldName is different than renamed element name', () => {
 			const op = new RenameOperation( position, 'foo', newName, doc.version );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				op._validate();
-			} ).to.throw( CKEditorError, /rename-operation-wrong-name/ );
+			}, /rename-operation-wrong-name/, model );
 		} );
 
 		it( 'should not throw when new name is the same as previous', () => {

+ 11 - 11
packages/ckeditor5-engine/tests/model/operation/rootattributeoperation.js

@@ -7,7 +7,7 @@ import Model from '../../../src/model/model';
 import DocumentFragment from '../../../src/model/documentfragment';
 import Element from '../../../src/model/element';
 import RootAttributeOperation from '../../../src/model/operation/rootattributeoperation';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'RootAttributeOperation', () => {
 	let model, doc, root;
@@ -181,7 +181,7 @@ describe( 'RootAttributeOperation', () => {
 			const parent = new Element( 'p' );
 			parent._appendChild( child );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const op = new RootAttributeOperation(
 					child,
 					'foo',
@@ -191,11 +191,11 @@ describe( 'RootAttributeOperation', () => {
 				);
 
 				op._validate();
-			} ).to.throw( CKEditorError, /rootattribute-operation-not-a-root/ );
+			}, /rootattribute-operation-not-a-root/ );
 		} );
 
 		it( 'should throw an error when trying to change document fragment', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const op = new RootAttributeOperation(
 					new DocumentFragment(),
 					'foo',
@@ -205,11 +205,11 @@ describe( 'RootAttributeOperation', () => {
 				);
 
 				op._validate();
-			} ).to.throw( CKEditorError, /rootattribute-operation-not-a-root/ );
+			}, /rootattribute-operation-not-a-root/ );
 		} );
 
 		it( 'should throw an error when trying to remove an attribute that does not exists', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const op = new RootAttributeOperation(
 					root,
 					'foo',
@@ -219,13 +219,13 @@ describe( 'RootAttributeOperation', () => {
 				);
 
 				op._validate();
-			} ).to.throw( CKEditorError, /rootattribute-operation-wrong-old-value/ );
+			}, /rootattribute-operation-wrong-old-value/, model );
 		} );
 
 		it( 'should throw an error when trying to add an attribute that already exists', () => {
 			root._setAttribute( 'x', 1 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const op = new RootAttributeOperation(
 					root,
 					'x',
@@ -235,7 +235,7 @@ describe( 'RootAttributeOperation', () => {
 				);
 
 				op._validate();
-			} ).to.throw( CKEditorError, /rootattribute-operation-attribute-exists/ );
+			}, /rootattribute-operation-attribute-exists/, model );
 		} );
 	} );
 
@@ -304,9 +304,9 @@ describe( 'RootAttributeOperation', () => {
 
 			serialized.root = 'no-root';
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				RootAttributeOperation.fromJSON( serialized, doc );
-			} ).to.throw( CKEditorError, /rootattribute-operation-fromjson-no-root/ );
+			}, /rootattribute-operation-fromjson-no-root/ );
 		} );
 	} );
 } );

+ 6 - 5
packages/ckeditor5-engine/tests/model/operation/splitoperation.js

@@ -9,7 +9,8 @@ import MergeOperation from '../../../src/model/operation/mergeoperation';
 import Position from '../../../src/model/position';
 import Element from '../../../src/model/element';
 import Text from '../../../src/model/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'SplitOperation', () => {
 	let model, doc, root, gy, gyPos;
@@ -125,7 +126,7 @@ describe( 'SplitOperation', () => {
 
 			const operation = new SplitOperation( new Position( root, [ 0, 8 ] ), 3, null, doc.version );
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /split-operation-position-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /split-operation-position-invalid/, model );
 		} );
 
 		it( 'should throw an error if split position is in root', () => {
@@ -136,7 +137,7 @@ describe( 'SplitOperation', () => {
 			const operation = new SplitOperation( new Position( root, [ 0, 0 ] ), 3, null, doc.version );
 			operation.splitPosition = new Position( root, [ 1 ] );
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /split-operation-split-in-root/ );
+			expectToThrowCKEditorError( () => operation._validate(), /split-operation-split-in-root/, model );
 		} );
 
 		it( 'should throw an error if number of nodes to move is invalid', () => {
@@ -146,7 +147,7 @@ describe( 'SplitOperation', () => {
 
 			const operation = new SplitOperation( new Position( root, [ 0, 2 ] ), 6, null, doc.version );
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /split-operation-how-many-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /split-operation-how-many-invalid/, model );
 		} );
 
 		it( 'should throw an error if graveyard position is invalid', () => {
@@ -156,7 +157,7 @@ describe( 'SplitOperation', () => {
 
 			const operation = new SplitOperation( new Position( root, [ 0, 2 ] ), 4, gyPos, doc.version );
 
-			expect( () => operation._validate() ).to.throw( CKEditorError, /split-operation-graveyard-position-invalid/ );
+			expectToThrowCKEditorError( () => operation._validate(), /split-operation-graveyard-position-invalid/, model );
 		} );
 	} );
 

+ 5 - 6
packages/ckeditor5-engine/tests/model/operation/utils.js

@@ -12,8 +12,7 @@ import Position from '../../../src/model/position';
 import Range from '../../../src/model/range';
 import * as utils from '../../../src/model/operation/utils';
 import { getData } from '../../../src/dev-utils/model';
-
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 let model, doc, root;
 
@@ -81,9 +80,9 @@ describe( 'Operation utils', () => {
 		} );
 
 		it( 'should throw if given range is not flat', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				utils._remove( new Range( new Position( root, [ 0 ] ), new Position( root, [ 1, 2 ] ) ) );
-			} ).to.throw( CKEditorError, /operation-utils-remove-range-not-flat/ );
+			}, /operation-utils-remove-range-not-flat/ );
 		} );
 	} );
 
@@ -103,9 +102,9 @@ describe( 'Operation utils', () => {
 		} );
 
 		it( 'should throw if given range is not flat', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				utils._move( new Range( new Position( root, [ 0 ] ), new Position( root, [ 1, 2 ] ) ), null );
-			} ).to.throw( CKEditorError, /operation-utils-move-range-not-flat/ );
+			}, /operation-utils-move-range-not-flat/ );
 		} );
 	} );
 

+ 21 - 20
packages/ckeditor5-engine/tests/model/position.js

@@ -17,9 +17,10 @@ import MoveOperation from '../../src/model/operation/moveoperation';
 import RenameOperation from '../../src/model/operation/renameoperation';
 import MergeOperation from '../../src/model/operation/mergeoperation';
 import SplitOperation from '../../src/model/operation/splitoperation';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import LivePosition from '../../src/model/liveposition';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Position', () => {
 	let doc, model, root, otherRoot, p, ul, li1, li2, f, o, z, b, a, r, foz, bar;
@@ -107,19 +108,19 @@ describe( 'Position', () => {
 		} );
 
 		it( 'should throw error if given path is incorrect', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new Position( root, {} ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /model-position-path-incorrect/ );
+			}, /model-position-path-incorrect/, model );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new Position( root, [] ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /model-position-path-incorrect/ );
+			}, /model-position-path-incorrect/, model );
 		} );
 
 		it( 'should throw error if given root is invalid', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new Position( new Text( 'a' ) ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /model-position-root-invalid/ );
+			}, /model-position-root-invalid/ );
 
 			expect( () => {
 				new Position(); // eslint-disable-line no-new
@@ -130,7 +131,9 @@ describe( 'Position', () => {
 	describe( 'static creators', () => {
 		describe( '_createAt()', () => {
 			it( 'should throw if no offset is passed', () => {
-				expect( () => Position._createAt( ul ) ).to.throw( CKEditorError, /model-createPositionAt-offset-required/ );
+				expectToThrowCKEditorError( () => {
+					Position._createAt( ul );
+				}, /model-createPositionAt-offset-required/, model );
 			} );
 
 			it( 'should create positions from positions', () => {
@@ -187,9 +190,9 @@ describe( 'Position', () => {
 			} );
 
 			it( 'throws when parent is not an element', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					Position._createAt( b, 0 );
-				} ).to.throw( CKEditorError, /^model-position-parent-incorrect/ );
+				}, /^model-position-parent-incorrect/, model );
 			} );
 
 			it( 'works with a doc frag', () => {
@@ -223,9 +226,9 @@ describe( 'Position', () => {
 			} );
 
 			it( 'should throw error if one try to create positions before root', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					Position._createBefore( root );
-				} ).to.throw( CKEditorError, /model-position-before-root/ );
+				}, /model-position-before-root/, model );
 			} );
 		} );
 
@@ -253,9 +256,9 @@ describe( 'Position', () => {
 			} );
 
 			it( 'should throw error if one try to make positions after root', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					Position._createAfter( root );
-				} ).to.throw( CKEditorError, /model-position-after-root/ );
+				}, /model-position-after-root/, model );
 			} );
 		} );
 	} );
@@ -954,7 +957,7 @@ describe( 'Position', () => {
 		} );
 
 		it( 'should not update path if deletion position parent is a node from that path and ' +
-			'offset is after next node on that path', () => {
+		'offset is after next node on that path', () => {
 			const position = new Position( root, [ 1, 2, 3 ] );
 			const transformed = position._getTransformedByDeletion( new Position( root, [ 1, 3 ] ), 2 );
 
@@ -1088,11 +1091,9 @@ describe( 'Position', () => {
 		} );
 
 		it( 'should throw error when creating object in document that does not have provided root', () => {
-			expect(
-				() => {
-					Position.fromJSON( { root: 'noroot', path: [ 0 ] }, doc );
-				}
-			).to.throw( CKEditorError, /model-position-fromjson-no-root/ );
+			expectToThrowCKEditorError( () => {
+				Position.fromJSON( { root: 'noroot', path: [ 0 ] }, doc );
+			}, /model-position-fromjson-no-root/, model );
 		} );
 	} );
 

+ 4 - 3
packages/ckeditor5-engine/tests/model/range.js

@@ -16,7 +16,8 @@ import MoveOperation from '../../src/model/operation/moveoperation';
 import RenameOperation from '../../src/model/operation/renameoperation';
 import MergeOperation from '../../src/model/operation/mergeoperation';
 import SplitOperation from '../../src/model/operation/splitoperation';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Range', () => {
 	let doc, range, start, end, root, otherRoot, gy, model;
@@ -210,9 +211,9 @@ describe( 'Range', () => {
 			} );
 
 			it( 'should throw if empty array is passed', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					Range._createFromRanges( [] );
-				} ).to.throw( CKEditorError, /^range-create-from-ranges-empty-array/ );
+				}, /^range-create-from-ranges-empty-array/ );
 			} );
 
 			it( 'should return a copy of the range if only one range was passed', () => {

+ 39 - 40
packages/ckeditor5-engine/tests/model/schema.js

@@ -5,8 +5,6 @@
 
 import Schema, { SchemaContext } from '../../src/model/schema';
 
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
-
 import Model from '../../src/model/model';
 
 import DocumentFragment from '../../src/model/documentfragment';
@@ -19,6 +17,7 @@ import Range from '../../src/model/range';
 import { getData, setData, stringify, parse } from '../../src/dev-utils/model';
 
 import AttributeOperation from '../../src/model/operation/attributeoperation';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Schema', () => {
 	let schema, root1, r1p1, r1p2, r1bQ, r1bQp, root2;
@@ -61,9 +60,9 @@ describe( 'Schema', () => {
 		it( 'throws when trying to register for a single item twice', () => {
 			schema.register( 'foo' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				schema.register( 'foo' );
-			} ).to.throw( CKEditorError, /^schema-cannot-register-item-twice:/ );
+			}, /^schema-cannot-register-item-twice:/, schema );
 		} );
 	} );
 
@@ -90,9 +89,9 @@ describe( 'Schema', () => {
 		} );
 
 		it( 'throws when trying to extend a not yet registered item', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				schema.extend( 'foo' );
-			} ).to.throw( CKEditorError, /^schema-cannot-extend-missing-item:/ );
+			}, /^schema-cannot-extend-missing-item:/, schema );
 		} );
 	} );
 
@@ -846,9 +845,9 @@ describe( 'Schema', () => {
 
 			const position = Position._createBefore( listItem );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			} ).to.throw( CKEditorError, /^schema-check-merge-no-element-before:/ );
+			}, /^schema-check-merge-no-element-before:/, schema );
 		} );
 
 		it( 'throws an error if the node before the position is not the element', () => {
@@ -864,9 +863,9 @@ describe( 'Schema', () => {
 
 			const position = Position._createBefore( listItem );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			} ).to.throw( CKEditorError, /^schema-check-merge-no-element-before:/ );
+			}, /^schema-check-merge-no-element-before:/, schema );
 		} );
 
 		it( 'throws an error if there is no element after the position', () => {
@@ -881,9 +880,9 @@ describe( 'Schema', () => {
 
 			const position = Position._createAfter( listItem );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			} ).to.throw( CKEditorError, /^schema-check-merge-no-element-after:/ );
+			}, /^schema-check-merge-no-element-after:/, schema );
 		} );
 
 		it( 'throws an error if the node after the position is not the element', () => {
@@ -899,9 +898,9 @@ describe( 'Schema', () => {
 
 			const position = Position._createBefore( listItem );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			} ).to.throw( CKEditorError, /^schema-check-merge-no-element-before:/ );
+			}, /^schema-check-merge-no-element-before:/, schema );
 		} );
 
 		// This is an invalid case by definition – the baseElement should not contain disallowed elements
@@ -1005,16 +1004,16 @@ describe( 'Schema', () => {
 			setData(
 				model,
 				'<div>' +
-					'<section>' +
-						'<article>' +
-							'<paragraph>[foo]</paragraph>' +
-						'</article>' +
-					'</section>' +
-					'<widget>' +
-						'<image>' +
-							'<caption>b[a]r</caption>' +
-						'</image>' +
-					'</widget>' +
+				'<section>' +
+				'<article>' +
+				'<paragraph>[foo]</paragraph>' +
+				'</article>' +
+				'</section>' +
+				'<widget>' +
+				'<image>' +
+				'<caption>b[a]r</caption>' +
+				'</image>' +
+				'</widget>' +
 				'</div>'
 			);
 
@@ -1026,11 +1025,11 @@ describe( 'Schema', () => {
 			setData(
 				model,
 				'<div>' +
-					'<section>' +
-						'<article>' +
-							'<paragraph>[foo]</paragraph>' +
-						'</article>' +
-					'</section>' +
+				'<section>' +
+				'<article>' +
+				'<paragraph>[foo]</paragraph>' +
+				'</article>' +
+				'</section>' +
 				'</div>' +
 				'<section>b[]ar</section>'
 			);
@@ -1042,10 +1041,10 @@ describe( 'Schema', () => {
 			setData(
 				model,
 				'<image>' +
-					'<caption>[Foo</caption>' +
+				'<caption>[Foo</caption>' +
 				'</image>' +
 				'<article>' +
-					'<paragraph>Paragraph in article]</paragraph>' +
+				'<paragraph>Paragraph in article]</paragraph>' +
 				'</article>' +
 				'<paragraph>Paragraph item 1</paragraph>' +
 				'<paragraph>Paragraph [item 2]</paragraph>'
@@ -1060,10 +1059,10 @@ describe( 'Schema', () => {
 				'<paragraph>Paragraph item 1</paragraph>' +
 				'<paragraph>Paragraph [item 2]</paragraph>' +
 				'<image>' +
-					'<caption>[Foo</caption>' +
+				'<caption>[Foo</caption>' +
 				'</image>' +
 				'<article>' +
-					'<paragraph>Paragraph in article]</paragraph>' +
+				'<paragraph>Paragraph in article]</paragraph>' +
 				'</article>'
 			);
 
@@ -1814,12 +1813,12 @@ describe( 'Schema', () => {
 				expect( getData( model, { withoutSelection: true } ) )
 					.to.equal(
 						'<div>' +
-							'<paragraph>' +
-								'<$text b="1">foo</$text>' +
-								'<image b="1"></image>' +
-							'</paragraph>' +
-							'<$text a="1">bar</$text>' +
-							'<image a="1"></image>' +
+						'<paragraph>' +
+						'<$text b="1">foo</$text>' +
+						'<image b="1"></image>' +
+						'</paragraph>' +
+						'<$text a="1">bar</$text>' +
+						'<image a="1"></image>' +
 						'</div>'
 					);
 			} );
@@ -2139,7 +2138,7 @@ describe( 'Schema', () => {
 			} );
 
 			it( 'passes $root>paragraph and $root2>paragraph – where $root2 inherits content of $root' +
-				'and paragraph inherits allowWhere from $block', () => {
+			'and paragraph inherits allowWhere from $block', () => {
 				schema.register( '$root' );
 				schema.register( '$root2', {
 					allowContentOf: '$root'

+ 17 - 17
packages/ckeditor5-engine/tests/model/selection.js

@@ -10,11 +10,11 @@ import Range from '../../src/model/range';
 import Position from '../../src/model/position';
 import LiveRange from '../../src/model/liverange';
 import Selection from '../../src/model/selection';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import { parse, setData } from '../../src/dev-utils/model';
 import Schema from '../../src/model/schema';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Selection', () => {
 	let model, doc, root, selection, liveRange, range, range1, range2, range3;
@@ -107,7 +107,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should throw an error if added ranges intersects', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new Selection( [
 					liveRange,
@@ -116,14 +116,14 @@ describe( 'Selection', () => {
 						new Position( root, [ 1, 2 ] )
 					)
 				] );
-			} ).to.throw( CKEditorError, /model-selection-range-intersects/ );
+			}, /model-selection-range-intersects/, model );
 		} );
 
 		it( 'should throw an error when trying to set selection to not selectable', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new Selection( {} );
-			} ).to.throw( /model-selection-setTo-not-selectable/ );
+			}, /model-selection-setTo-not-selectable/ );
 		} );
 	} );
 
@@ -268,7 +268,7 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should throw an error if added ranges intersects', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection.setTo( [
 					liveRange,
 					new Range(
@@ -276,19 +276,19 @@ describe( 'Selection', () => {
 						new Position( root, [ 1, 2 ] )
 					)
 				] );
-			} ).to.throw( CKEditorError, /model-selection-range-intersects/ );
+			}, /model-selection-range-intersects/, model );
 		} );
 
 		it( 'should throw an error when trying to set selection to not selectable', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection.setTo( {} );
-			} ).to.throw( /model-selection-setTo-not-selectable/ );
+			}, /model-selection-setTo-not-selectable/ );
 		} );
 
 		it( 'should throw an error when trying to set selection to not selectable #2', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection.setTo();
-			} ).to.throw( /model-selection-setTo-not-selectable/ );
+			}, /model-selection-setTo-not-selectable/ );
 		} );
 
 		it( 'should allow setting selection inside an element', () => {
@@ -352,9 +352,9 @@ describe( 'Selection', () => {
 			} );
 
 			it( 'should throw if second parameter is not passed', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					selection.setTo( root );
-				} ).to.throw( CKEditorError, /model-selection-setTo-required-second-parameter/ );
+				}, /model-selection-setTo-required-second-parameter/, model );
 			} );
 
 			it( 'should set selection at given offset in given parent', () => {
@@ -438,9 +438,9 @@ describe( 'Selection', () => {
 		it( 'throws if there are no ranges in selection', () => {
 			const endPos = Position._createAt( root, 'end' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection.setFocus( endPos );
-			} ).to.throw( CKEditorError, /model-selection-setFocus-no-ranges/ );
+			}, /model-selection-setFocus-no-ranges/, model );
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
@@ -617,9 +617,9 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should throw an error when range is invalid', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection._setRanges( [ { invalid: 'range' } ] );
-			} ).to.throw( CKEditorError, /model-selection-set-ranges-not-range/ );
+			}, /model-selection-set-ranges-not-range/, model );
 		} );
 
 		it( 'should remove all ranges and add given ranges', () => {

+ 10 - 9
packages/ckeditor5-engine/tests/model/textproxy.js

@@ -7,7 +7,8 @@ import Element from '../../src/model/element';
 import Text from '../../src/model/text';
 import TextProxy from '../../src/model/textproxy';
 import Model from '../../src/model/model';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'TextProxy', () => {
 	let model, doc, element, textProxy, root, textProxyNoParent, text, textNoParent;
@@ -82,23 +83,23 @@ describe( 'TextProxy', () => {
 	} );
 
 	it( 'should throw if wrong offsetInText is passed', () => {
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			new TextProxy( text, -1, 2 ); // eslint-disable-line no-new
-		} ).to.throw( CKEditorError, /model-textproxy-wrong-offsetintext/ );
+		}, /model-textproxy-wrong-offsetintext/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			new TextProxy( text, 9, 1 ); // eslint-disable-line no-new
-		} ).to.throw( CKEditorError, /model-textproxy-wrong-offsetintext/ );
+		}, /model-textproxy-wrong-offsetintext/, model );
 	} );
 
 	it( 'should throw if wrong length is passed', () => {
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			new TextProxy( text, 2, -1 ); // eslint-disable-line no-new
-		} ).to.throw( CKEditorError, /model-textproxy-wrong-length/ );
+		}, /model-textproxy-wrong-length/, model );
 
-		expect( () => {
+		expectToThrowCKEditorError( () => {
 			new TextProxy( text, 2, 9 ); // eslint-disable-line no-new
-		} ).to.throw( CKEditorError, /model-textproxy-wrong-length/ );
+		}, /model-textproxy-wrong-length/, model );
 	} );
 
 	describe( 'is', () => {

+ 10 - 9
packages/ckeditor5-engine/tests/model/treewalker.js

@@ -10,7 +10,8 @@ import Text from '../../src/model/text';
 import TreeWalker from '../../src/model/treewalker';
 import Position from '../../src/model/position';
 import Range from '../../src/model/range';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'TreeWalker', () => {
 	let model, doc, root, img1, paragraph, ba, r, img2, x,
@@ -48,23 +49,23 @@ describe( 'TreeWalker', () => {
 
 	describe( 'constructor()', () => {
 		it( 'should throw if neither boundaries nor starting position is set', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker(); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^model-tree-walker-no-start-position/ );
+			}, /^model-tree-walker-no-start-position/, null );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker( {} ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^model-tree-walker-no-start-position/ );
+			}, /^model-tree-walker-no-start-position/, null );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker( { singleCharacters: true } ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^model-tree-walker-no-start-position/ );
+			}, /^model-tree-walker-no-start-position/, null );
 		} );
 
 		it( 'should throw if walking direction is unknown', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker( { startPosition: rootBeginning, direction: 'unknown' } ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^model-tree-walker-unknown-direction/ );
+			}, /^model-tree-walker-unknown-direction/, model );
 		} );
 	} );
 

+ 98 - 97
packages/ckeditor5-engine/tests/model/writer.js

@@ -15,9 +15,10 @@ import Position from '../../src/model/position';
 import Range from '../../src/model/range';
 
 import count from '@ckeditor/ckeditor5-utils/src/count';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import { getNodesAndText } from '../../tests/model/_utils/utils';
 import DocumentSelection from '../../src/model/documentselection';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Writer', () => {
 	let model, doc, batch;
@@ -300,9 +301,9 @@ describe( 'Writer', () => {
 
 			insert( node, root );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				insert( node, docFrag );
-			} ).to.throw( CKEditorError, /^model-writer-insert-forbidden-move/ );
+			}, /^model-writer-insert-forbidden-move/, model );
 		} );
 
 		it( 'should transfer markers from given DocumentFragment', () => {
@@ -369,9 +370,9 @@ describe( 'Writer', () => {
 			const root = doc.createRoot();
 			const node = createText( 'foo' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insert( node, root );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -495,9 +496,9 @@ describe( 'Writer', () => {
 			const writer = new Writer( model, batch );
 			const parent = createDocumentFragment();
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insertText( 'foo', parent );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -617,9 +618,9 @@ describe( 'Writer', () => {
 			const writer = new Writer( model, batch );
 			const child = createElement( 'child' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insertElement( 'foo', child, 'after' );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -747,9 +748,9 @@ describe( 'Writer', () => {
 
 			insert( node, root );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				append( node, docFrag );
-			} ).to.throw( CKEditorError, /^model-writer-insert-forbidden-move/ );
+			}, /^model-writer-insert-forbidden-move/, model );
 		} );
 	} );
 
@@ -803,9 +804,9 @@ describe( 'Writer', () => {
 			const writer = new Writer( model, batch );
 			const parent = createDocumentFragment();
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.appendText( 'foo', parent );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -857,9 +858,9 @@ describe( 'Writer', () => {
 			const writer = new Writer( model, batch );
 			const parent = createDocumentFragment();
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.appendElement( 'foo', parent );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -917,9 +918,9 @@ describe( 'Writer', () => {
 				it( 'should throw when trying to use detached writer', () => {
 					const writer = new Writer( model, batch );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.setAttribute( 'a', 1, node );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 
@@ -944,9 +945,9 @@ describe( 'Writer', () => {
 				it( 'should throw when trying to use detached writer', () => {
 					const writer = new Writer( model, batch );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.removeAttribute( 'b', node );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 		} );
@@ -1089,9 +1090,9 @@ describe( 'Writer', () => {
 				it( 'should throw when trying to use detached writer', () => {
 					const writer = new Writer( model, batch );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.setAttribute( 'a', 1, getRange( 0, 20 ) );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 
@@ -1165,9 +1166,9 @@ describe( 'Writer', () => {
 				it( 'should throw when trying to use detached writer', () => {
 					const writer = new Writer( model, batch );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.removeAttribute( 'a', getRange( 3, 15 ) );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 		} );
@@ -1224,9 +1225,9 @@ describe( 'Writer', () => {
 				it( 'should throw when trying to use detached writer', () => {
 					const writer = new Writer( model, batch );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.setAttribute( 'a', 1, p );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 
@@ -1247,9 +1248,9 @@ describe( 'Writer', () => {
 				it( 'should throw when trying to use detached writer', () => {
 					const writer = new Writer( model, batch );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.removeAttribute( 'b', root );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 
@@ -1311,9 +1312,9 @@ describe( 'Writer', () => {
 					const writer = new Writer( model, batch );
 					const element = createElement( 'x' );
 
-					expect( () => {
+					expectToThrowCKEditorError( () => {
 						writer.clearAttributes( element );
-					} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+					}, /^writer-incorrect-use/, model );
 				} );
 			} );
 		} );
@@ -1417,9 +1418,9 @@ describe( 'Writer', () => {
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.setAttributes( new Map( [ [ 'a', 3 ], [ 'c', null ] ] ), item );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -1525,23 +1526,23 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if there is no element after', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				merge( new Position( root, [ 2 ] ) );
-			} ).to.throw( CKEditorError, /^writer-merge-no-element-after/ );
+			}, /^writer-merge-no-element-after/, model );
 		} );
 
 		it( 'should throw if there is no element before', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				merge( new Position( root, [ 0, 2 ] ) );
-			} ).to.throw( CKEditorError, /^writer-merge-no-element-before/ );
+			}, /^writer-merge-no-element-before/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.merge( new Position( root, [ 1 ] ) );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -1615,33 +1616,33 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if object to move is not a range', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				move( root.getChild( 0 ), new Position( root, [ 1, 3 ] ) );
-			} ).to.throw( CKEditorError, /^writer-move-invalid-range/ );
+			}, /^writer-move-invalid-range/, model );
 		} );
 
 		it( 'should throw if given range is not flat', () => {
 			const notFlatRange = new Range( new Position( root, [ 0, 2, 2 ] ), new Position( root, [ 0, 6 ] ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				move( notFlatRange, new Position( root, [ 1, 3 ] ) );
-			} ).to.throw( CKEditorError, /^writer-move-range-not-flat/ );
+			}, /^writer-move-range-not-flat/, model );
 		} );
 
 		it( 'should throw if range is going to be moved to the other document', () => {
 			const docFrag = createDocumentFragment();
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				move( range, docFrag, 0 );
-			} ).to.throw( CKEditorError, /^writer-move-different-document/ );
+			}, /^writer-move-different-document/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.move( range, new Position( root, [ 1, 3 ] ) );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -1760,9 +1761,9 @@ describe( 'Writer', () => {
 			it( 'should throw when trying to use detached writer', () => {
 				const writer = new Writer( model, batch );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.remove( range );
-				} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+				}, /^writer-incorrect-use/, model );
 			} );
 		} );
 
@@ -1817,9 +1818,9 @@ describe( 'Writer', () => {
 			it( 'should throw when trying to use detached writer', () => {
 				const writer = new Writer( model, batch );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.remove( range );
-				} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+				}, /^writer-incorrect-use/, model );
 			} );
 		} );
 	} );
@@ -1850,18 +1851,18 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if not an Element instance is passed', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				rename( new Text( 'abc' ), 'h' );
-			} ).to.throw( CKEditorError, /^writer-rename-not-element-instance/ );
+			}, /^writer-rename-not-element-instance/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 			const p = new Element( 'p', null, new Text( 'abc' ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.rename( p, 'h' );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -1929,25 +1930,25 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if we try to split a root', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				split( new Position( root, [ 0 ] ) );
-			} ).to.throw( CKEditorError, /^writer-split-element-no-parent/ );
+			}, /^writer-split-element-no-parent/, model );
 		} );
 
 		it( 'should throw if we try to split an element with no parent', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const element = createElement( 'p' );
 
 				split( new Position( element, [ 0 ] ) );
-			} ).to.throw( CKEditorError, /^writer-split-element-no-parent/ );
+			}, /^writer-split-element-no-parent/, model );
 		} );
 
 		it( 'should throw if we try to split a document fragment', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				const documentFragment = createDocumentFragment();
 
 				split( new Position( documentFragment, [ 0 ] ) );
-			} ).to.throw( CKEditorError, /^writer-split-element-no-parent/ );
+			}, /^writer-split-element-no-parent/, model );
 		} );
 
 		it( 'should split elements to limitElement', () => {
@@ -1981,17 +1982,17 @@ describe( 'Writer', () => {
 			root._insertChild( 0, div );
 			root._insertChild( 1, section );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				split( new Position( p, [ 3 ] ), section );
-			} ).to.throw( CKEditorError, /^writer-split-invalid-limit-element/ );
+			}, /^writer-split-invalid-limit-element/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.split( new Position( root, [ 0, 3 ] ) );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -2041,34 +2042,34 @@ describe( 'Writer', () => {
 			root._insertChild( 1, [ new Element( 'p', [], new Text( 'xyz' ) ) ] );
 			const notFlatRange = new Range( new Position( root, [ 3 ] ), new Position( root, [ 6, 2 ] ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				wrap( notFlatRange, 'p' );
-			} ).to.throw( CKEditorError, /^writer-wrap-range-not-flat/ );
+			}, /^writer-wrap-range-not-flat/, model );
 		} );
 
 		it( 'should throw if element to wrap with has children #1', () => {
 			const p = new Element( 'p', [], new Text( 'a' ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				wrap( range, p );
-			} ).to.throw( CKEditorError, /^writer-wrap-element-not-empty/ );
+			}, /^writer-wrap-element-not-empty/, model );
 		} );
 
 		it( 'should throw if element to wrap with has children #2', () => {
 			const p = new Element( 'p' );
 			root._insertChild( 0, p );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				wrap( range, p );
-			} ).to.throw( CKEditorError, /^writer-wrap-element-attached/ );
+			}, /^writer-wrap-element-attached/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.wrap( range, 'p' );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -2101,17 +2102,17 @@ describe( 'Writer', () => {
 		it( 'should throw if element to unwrap has no parent', () => {
 			const element = new Element( 'p' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				unwrap( element );
-			} ).to.throw( CKEditorError, /^writer-unwrap-element-no-parent/ );
+			}, /^writer-unwrap-element-no-parent/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.unwrap( p );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -2125,15 +2126,15 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if options.usingOperation is not defined', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				addMarker( 'name' );
-			} ).to.throw( CKEditorError, /^writer-addMarker-no-usingOperation/ );
+			}, /^writer-addMarker-no-usingOperation/, model );
 		} );
 
 		it( 'should throw if name and range is defined but options.usingOperation is not defined', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { range } );
-			} ).to.throw( CKEditorError, /^writer-addMarker-no-usingOperation/ );
+			}, /^writer-addMarker-no-usingOperation/, model );
 		} );
 
 		it( 'should add marker to the document marker collection', () => {
@@ -2183,9 +2184,9 @@ describe( 'Writer', () => {
 
 			const range2 = new Range( Position._createAt( root, 0 ), Position._createAt( root, 0 ) );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { range: range2, usingOperation: false } );
-			} ).to.throw( CKEditorError, /^writer-addMarker-marker-exists/ );
+			}, /^writer-addMarker-marker-exists/, model );
 		} );
 
 		it( 'should use operations when having set usingOperation to true', () => {
@@ -2203,24 +2204,24 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw if marker with given name does not exist and range is not passed', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { usingOperation: true } );
-			} ).to.throw( CKEditorError, /^writer-addMarker-no-range/ );
+			}, /^writer-addMarker-no-range/, model );
 		} );
 
 		it( 'should throw if marker is set directly and range is not passed', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { usingOperation: false } );
-			} ).to.throw( CKEditorError, /^writer-addMarker-no-range/ );
+			}, /^writer-addMarker-no-range/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const marker = addMarker( 'name', { range, usingOperation: false } );
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.addMarker( marker, null, { usingOperation: true } );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -2454,16 +2455,16 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw when range and usingOperations were not provided', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { range, usingOperation: false } );
 				updateMarker( 'name', {} );
-			} ).to.throw( CKEditorError, /^writer-updateMarker-wrong-options/ );
+			}, /^writer-updateMarker-wrong-options/, model );
 		} );
 
 		it( 'should throw when marker provided by name does not exists', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				updateMarker( 'name', { usingOperation: false } );
-			} ).to.throw( CKEditorError, /^writer-updateMarker-marker-not-exists/ );
+			}, /^writer-updateMarker-marker-not-exists/, model );
 		} );
 
 		it( 'should only refresh the marker when there is no provided options to update', () => {
@@ -2485,9 +2486,9 @@ describe( 'Writer', () => {
 			const marker = addMarker( 'name', { range, usingOperation: false } );
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.updateMarker( marker, { usingOperation: true } );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 	} );
 
@@ -2508,17 +2509,17 @@ describe( 'Writer', () => {
 		} );
 
 		it( 'should throw when trying to remove non existing marker', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				removeMarker( 'name' );
-			} ).to.throw( CKEditorError, /^writer-removeMarker-no-marker/ );
+			}, /^writer-removeMarker-no-marker/, model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
 			const writer = new Writer( model, batch );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.removeMarker( 'name' );
-			} ).to.throw( CKEditorError, /^writer-incorrect-use/ );
+			}, /^writer-incorrect-use/, model );
 		} );
 
 		it( 'should accept marker instance', () => {

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

@@ -6,7 +6,8 @@
 import AttributeElement from '../../src/view/attributeelement';
 import Element from '../../src/view/element';
 import { parse } from '../../src/dev-utils/view';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'AttributeElement', () => {
 	describe( 'constructor()', () => {
@@ -128,9 +129,9 @@ describe( 'AttributeElement', () => {
 		it( 'should throw if attribute element has no id', () => {
 			const attribute = new AttributeElement( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				attribute.getElementsWithSameId();
-			} ).to.throw( CKEditorError, /attribute-element-get-elements-with-same-id-no-id/ );
+			}, /attribute-element-get-elements-with-same-id-no-id/ );
 		} );
 	} );
 

+ 19 - 19
packages/ckeditor5-engine/tests/view/documentselection.js

@@ -10,11 +10,11 @@ import Document from '../../src/view/document';
 import Element from '../../src/view/element';
 import Text from '../../src/view/text';
 import Position from '../../src/view/position';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import createViewRoot from './_utils/createroot';
 import { parse } from '../../src/dev-utils/view';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DocumentSelection', () => {
 	let documentSelection, el, range1, range2, range3;
@@ -113,27 +113,27 @@ describe( 'DocumentSelection', () => {
 		} );
 
 		it( 'should throw an error when range is invalid', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new DocumentSelection( [ { invalid: 'range' } ] );
-			} ).to.throw( CKEditorError, /view-selection-add-range-not-range/ );
+			}, /view-selection-add-range-not-range/ );
 		} );
 
 		it( 'should throw an error when ranges intersects', () => {
 			const text = el.getChild( 0 );
 			const range2 = Range._createFromParentsAndOffsets( text, 7, text, 15 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new DocumentSelection( [ range1, range2 ] );
-			} ).to.throw( CKEditorError, 'view-selection-range-intersects' );
+			}, 'view-selection-range-intersects' );
 		} );
 
 		it( 'should throw an error when trying to set to not selectable', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new DocumentSelection( {} );
-			} ).to.throw( /view-selection-setTo-not-selectable/ );
+			}, /view-selection-setTo-not-selectable/ );
 		} );
 	} );
 
@@ -203,9 +203,9 @@ describe( 'DocumentSelection', () => {
 		it( 'throws if there are no ranges in selection', () => {
 			const endPos = Position._createAt( el, 'end' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				documentSelection._setFocus( endPos );
-			} ).to.throw( CKEditorError, /view-selection-setFocus-no-ranges/ );
+			}, /view-selection-setFocus-no-ranges/, documentSelection );
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
@@ -808,17 +808,17 @@ describe( 'DocumentSelection', () => {
 			it( 'should throw an error when trying to set to not selectable', () => {
 				const otherSelection = new DocumentSelection();
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					otherSelection._setTo( {} );
-				} ).to.throw( /view-selection-setTo-not-selectable/ );
+				}, /view-selection-setTo-not-selectable/ );
 			} );
 
 			it( 'should throw an error when trying to set to not selectable #2', () => {
 				const otherSelection = new DocumentSelection();
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					otherSelection._setTo();
-				} ).to.throw( /view-selection-setTo-not-selectable/ );
+				}, /view-selection-setTo-not-selectable/ );
 			} );
 		} );
 
@@ -860,9 +860,9 @@ describe( 'DocumentSelection', () => {
 			it( 'should throw an error when the second parameter is not passed and first is an item', () => {
 				const foo = new Text( 'foo' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					documentSelection._setTo( foo );
-				} ).to.throw( CKEditorError, /view-selection-setTo-required-second-parameter/ );
+				}, /view-selection-setTo-required-second-parameter/, documentSelection );
 			} );
 
 			it( 'should collapse selection at node and flag', () => {
@@ -1007,18 +1007,18 @@ describe( 'DocumentSelection', () => {
 
 		describe( 'throwing errors', () => {
 			it( 'should throw an error when range is invalid', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					documentSelection._setTo( [ { invalid: 'range' } ] );
-				} ).to.throw( CKEditorError, /view-selection-add-range-not-range/ );
+				}, /view-selection-add-range-not-range/, documentSelection );
 			} );
 
 			it( 'should throw when range is intersecting with already added range', () => {
 				const text = el.getChild( 0 );
 				const range2 = Range._createFromParentsAndOffsets( text, 7, text, 15 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					documentSelection._setTo( [ range1, range2 ] );
-				} ).to.throw( CKEditorError, 'view-selection-range-intersects' );
+				}, 'view-selection-range-intersects', documentSelection );
 			} );
 		} );
 

+ 18 - 16
packages/ckeditor5-engine/tests/view/downcastwriter/breakattributes.js

@@ -12,14 +12,16 @@ import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
 import Range from '../../../src/view/range';
 import Position from '../../../src/view/position';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'breakAttributes()', () => {
-		let writer;
+		let writer, document;
 
-		before( () => {
-			writer = new DowncastWriter( new Document() );
+		beforeEach( () => {
+			document = new Document();
+			writer = new DowncastWriter( document );
 		} );
 
 		describe( 'break position', () => {
@@ -153,17 +155,17 @@ describe( 'DowncastWriter', () => {
 				const p1 = new ContainerElement( 'p' );
 				const p2 = new ContainerElement( 'p' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.breakAttributes( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
-				} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+				}, 'view-writer-invalid-range-container', document );
 			} );
 
 			it( 'should throw when range has no parent container', () => {
 				const el = new AttributeElement( 'b' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.breakAttributes( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
-				} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+				}, 'view-writer-invalid-range-container', document );
 			} );
 
 			it( 'should not break text nodes if they are not in attribute elements', () => {
@@ -243,9 +245,9 @@ describe( 'DowncastWriter', () => {
 				new ContainerElement( 'p', null, img ); // eslint-disable-line no-new
 				const position = new Position( img, 0 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.breakAttributes( position );
-				} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+				}, 'view-writer-cannot-break-empty-element', writer );
 			} );
 
 			it( 'should throw if breaking inside EmptyElement #2', () => {
@@ -254,9 +256,9 @@ describe( 'DowncastWriter', () => {
 				new ContainerElement( 'p', null, [ img, b ] ); // eslint-disable-line no-new
 				const range = Range._createFromParentsAndOffsets( img, 0, b, 0 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.breakAttributes( range );
-				} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+				}, 'view-writer-cannot-break-empty-element', writer );
 			} );
 
 			it( 'should throw if breaking inside UIElement #1', () => {
@@ -264,9 +266,9 @@ describe( 'DowncastWriter', () => {
 				new ContainerElement( 'p', null, span ); // eslint-disable-line no-new
 				const position = new Position( span, 0 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.breakAttributes( position );
-				} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+				}, 'view-writer-cannot-break-ui-element', writer );
 			} );
 
 			it( 'should throw if breaking inside UIElement #2', () => {
@@ -275,9 +277,9 @@ describe( 'DowncastWriter', () => {
 				new ContainerElement( 'p', null, [ span, b ] ); // eslint-disable-line no-new
 				const range = Range._createFromParentsAndOffsets( span, 0, b, 0 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.breakAttributes( range );
-				} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+				}, 'view-writer-cannot-break-ui-element', writer );
 			} );
 		} );
 	} );

+ 6 - 5
packages/ckeditor5-engine/tests/view/downcastwriter/breakcontainer.js

@@ -5,10 +5,11 @@
 
 import DowncastWriter from '../../../src/view/downcastwriter';
 import { stringify, parse } from '../../../src/dev-utils/view';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import ContainerElement from '../../../src/view/containerelement';
 import Position from '../../../src/view/position';
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'breakContainer()', () => {
@@ -66,18 +67,18 @@ describe( 'DowncastWriter', () => {
 		it( 'should throw if position parent is not container', () => {
 			const { selection } = parse( '<container:div>foo{}bar</container:div>' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.breakContainer( selection.getFirstPosition() );
-			} ).to.throw( CKEditorError, /view-writer-break-non-container-element/ );
+			}, /view-writer-break-non-container-element/, writer );
 		} );
 
 		it( 'should throw if position parent is root', () => {
 			const element = new ContainerElement( 'div' );
 			const position = Position._createAt( element, 0 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.breakContainer( position );
-			} ).to.throw( CKEditorError, /view-writer-break-root/ );
+			}, /view-writer-break-root/, writer );
 		} );
 	} );
 } );

+ 10 - 8
packages/ckeditor5-engine/tests/view/downcastwriter/clear.js

@@ -10,12 +10,13 @@ import ContainerElement from '../../../src/view/containerelement';
 import AttributeElement from '../../../src/view/attributeelement';
 import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'clear()', () => {
-		let writer;
+		let writer, document;
 
 		// Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create ranges.
 		//
@@ -30,25 +31,26 @@ describe( 'DowncastWriter', () => {
 			expect( stringify( view, null, { showType: true } ) ).to.equal( expectedResult );
 		}
 
-		before( () => {
-			writer = new DowncastWriter( new Document() );
+		beforeEach( () => {
+			document = new Document();
+			writer = new DowncastWriter( document );
 		} );
 
 		it( 'should throw when range placed in two containers', () => {
 			const p1 = new ContainerElement( 'p' );
 			const p2 = new ContainerElement( 'p' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.clear( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+			}, 'view-writer-invalid-range-container', document );
 		} );
 
 		it( 'should throw when range has no parent container', () => {
 			const el = new AttributeElement( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.clear( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+			}, 'view-writer-invalid-range-container', document );
 		} );
 
 		it( 'should remove matched element from range', () => {

+ 17 - 14
packages/ckeditor5-engine/tests/view/downcastwriter/insert.js

@@ -9,14 +9,15 @@ import Element from '../../../src/view/element';
 import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
 import Position from '../../../src/view/position';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import { stringify, parse } from '../../../src/dev-utils/view';
 import AttributeElement from '../../../src/view/attributeelement';
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'insert()', () => {
-		let writer;
+		let writer, document;
 
 		// Executes test using `parse` and `stringify` utils functions.
 		//
@@ -31,8 +32,9 @@ describe( 'DowncastWriter', () => {
 			expect( stringify( view.root, newRange, { showType: true, showPriority: true } ) ).to.equal( expected );
 		}
 
-		before( () => {
-			writer = new DowncastWriter( new Document() );
+		beforeEach( () => {
+			document = new Document();
+			writer = new DowncastWriter( document );
 		} );
 
 		it( 'should return collapsed range in insertion position when using empty array', () => {
@@ -155,9 +157,10 @@ describe( 'DowncastWriter', () => {
 			const element = new Element( 'b' );
 			const container = new ContainerElement( 'p' );
 			const position = new Position( container, 0 );
-			expect( () => {
+
+			expectToThrowCKEditorError( () => {
 				writer.insert( position, element );
-			} ).to.throw( CKEditorError, 'view-writer-insert-invalid-node' );
+			}, 'view-writer-insert-invalid-node', document );
 		} );
 
 		it( 'should throw when Element is inserted as child node', () => {
@@ -166,9 +169,9 @@ describe( 'DowncastWriter', () => {
 			const container = new ContainerElement( 'p' );
 			const position = new Position( container, 0 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insert( position, root );
-			} ).to.throw( CKEditorError, 'view-writer-insert-invalid-node' );
+			}, 'view-writer-insert-invalid-node', document );
 		} );
 
 		it( 'should throw when position is not placed inside container', () => {
@@ -176,9 +179,9 @@ describe( 'DowncastWriter', () => {
 			const position = new Position( element, 0 );
 			const attributeElement = new AttributeElement( 'i' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insert( position, attributeElement );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-position-container' );
+			}, 'view-writer-invalid-position-container', document );
 		} );
 
 		it( 'should allow to insert EmptyElement into container', () => {
@@ -195,9 +198,9 @@ describe( 'DowncastWriter', () => {
 			const position = new Position( emptyElement, 0 );
 			const attributeElement = new AttributeElement( 'i' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insert( position, attributeElement );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+			}, 'view-writer-cannot-break-empty-element', document );
 		} );
 
 		it( 'should throw if trying to insert inside UIElement', () => {
@@ -206,9 +209,9 @@ describe( 'DowncastWriter', () => {
 			const position = new Position( uiElement, 0 );
 			const attributeElement = new AttributeElement( 'i' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.insert( position, attributeElement );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+			}, 'view-writer-cannot-break-ui-element', document );
 		} );
 	} );
 } );

+ 10 - 9
packages/ckeditor5-engine/tests/view/downcastwriter/mergecontainers.js

@@ -5,8 +5,9 @@
 
 import DowncastWriter from '../../../src/view/downcastwriter';
 import { stringify, parse } from '../../../src/dev-utils/view';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'mergeContainers()', () => {
@@ -58,33 +59,33 @@ describe( 'DowncastWriter', () => {
 		it( 'should throw if there is no element before position', () => {
 			const { selection } = parse( '[]<container:div>foobar</container:div>' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.mergeContainers( selection.getFirstPosition() );
-			} ).to.throw( CKEditorError, /view-writer-merge-containers-invalid-position/ );
+			}, /view-writer-merge-containers-invalid-position/, writer );
 		} );
 
 		it( 'should throw if there is no element after position', () => {
 			const { selection } = parse( '<container:div>foobar</container:div>[]' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.mergeContainers( selection.getFirstPosition() );
-			} ).to.throw( CKEditorError, /view-writer-merge-containers-invalid-position/ );
+			}, /view-writer-merge-containers-invalid-position/, writer );
 		} );
 
 		it( 'should throw if element before position is not a container element', () => {
 			const { selection } = parse( '<attribute:u>foo</attribute:u>[]<container:div>bar</container:div>' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.mergeContainers( selection.getFirstPosition() );
-			} ).to.throw( CKEditorError, /view-writer-merge-containers-invalid-position/ );
+			}, /view-writer-merge-containers-invalid-position/, writer );
 		} );
 
 		it( 'should throw if element after position is not a container element', () => {
 			const { selection } = parse( '<container:div>foo</container:div>[]<attribute:u>bar</attribute:u>' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.mergeContainers( selection.getFirstPosition() );
-			} ).to.throw( CKEditorError, /view-writer-merge-containers-invalid-position/ );
+			}, /view-writer-merge-containers-invalid-position/, writer );
 		} );
 	} );
 } );

+ 6 - 5
packages/ckeditor5-engine/tests/view/downcastwriter/move.js

@@ -12,9 +12,10 @@ import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
 import Range from '../../../src/view/range';
 import Position from '../../../src/view/position';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import Document from '../../../src/view/document';
 import Mapper from '../../../src/conversion/mapper';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'move()', () => {
@@ -155,9 +156,9 @@ describe( 'DowncastWriter', () => {
 			new ContainerElement( 'p', null, dstEmpty ); // eslint-disable-line no-new
 			const dstPosition = new Position( dstEmpty, 0 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.move( srcRange, dstPosition );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+			}, 'view-writer-cannot-break-empty-element', writer );
 		} );
 
 		it( 'should move UIElement', () => {
@@ -178,9 +179,9 @@ describe( 'DowncastWriter', () => {
 			new ContainerElement( 'p', null, dstUI ); // eslint-disable-line no-new
 			const dstPosition = new Position( dstUI, 0 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.move( srcRange, dstPosition );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+			}, 'view-writer-cannot-break-ui-element', writer );
 		} );
 
 		it( 'should not break marker mappings if marker element was split and the original element was removed', () => {

+ 16 - 14
packages/ckeditor5-engine/tests/view/downcastwriter/remove.js

@@ -11,12 +11,13 @@ import { stringify, parse } from '../../../src/dev-utils/view';
 import AttributeElement from '../../../src/view/attributeelement';
 import EmptyElement from '../../../src/view/emptyelement';
 import UIElement from '../../../src/view/uielement';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'remove()', () => {
-		let writer;
+		let writer, document;
 
 		// Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create and
 		// test ranges.
@@ -36,25 +37,26 @@ describe( 'DowncastWriter', () => {
 			expect( stringify( removed, null, { showType: true, showPriority: true } ) ).to.equal( expectedRemoved );
 		}
 
-		before( () => {
-			writer = new DowncastWriter( new Document() );
+		beforeEach( () => {
+			document = new Document();
+			writer = new DowncastWriter( document );
 		} );
 
 		it( 'should throw when range placed in two containers', () => {
 			const p1 = new ContainerElement( 'p' );
 			const p2 = new ContainerElement( 'p' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.remove( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+			}, 'view-writer-invalid-range-container', document );
 		} );
 
 		it( 'should throw when range has no parent container', () => {
 			const el = new AttributeElement( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.remove( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+			}, 'view-writer-invalid-range-container', document );
 		} );
 
 		it( 'should return empty DocumentFragment when range is collapsed', () => {
@@ -133,9 +135,9 @@ describe( 'DowncastWriter', () => {
 			new ContainerElement( 'p', null, [ emptyElement, attributeElement ] ); // eslint-disable-line no-new
 			const range = Range._createFromParentsAndOffsets( emptyElement, 0, attributeElement, 0 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.remove( range );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+			}, 'view-writer-cannot-break-empty-element', document );
 		} );
 
 		it( 'should remove UIElement', () => {
@@ -152,9 +154,9 @@ describe( 'DowncastWriter', () => {
 			new ContainerElement( 'p', null, [ uiElement, attributeElement ] ); // eslint-disable-line no-new
 			const range = Range._createFromParentsAndOffsets( uiElement, 0, attributeElement, 0 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.remove( range );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+			}, 'view-writer-cannot-break-ui-element', document );
 		} );
 
 		it( 'should remove single text node (as item)', () => {
@@ -201,9 +203,9 @@ describe( 'DowncastWriter', () => {
 		it( 'should throw when item has no parent container', () => {
 			const el = new AttributeElement( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.remove( el );
-			} ).to.throw( CKEditorError, 'view-position-before-root' );
+			}, 'view-position-before-root' );
 		} );
 	} );
 } );

+ 16 - 14
packages/ckeditor5-engine/tests/view/downcastwriter/unwrap.js

@@ -12,13 +12,14 @@ import UIElement from '../../../src/view/uielement';
 import Position from '../../../src/view/position';
 import Range from '../../../src/view/range';
 import Text from '../../../src/view/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import { stringify, parse } from '../../../src/dev-utils/view';
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'unwrap()', () => {
-		let writer;
+		let writer, document;
 
 		// Executes test using `parse` and `stringify` utils functions.
 		//
@@ -32,8 +33,9 @@ describe( 'DowncastWriter', () => {
 			expect( stringify( view.root, newRange, { showType: true, showPriority: true } ) ).to.equal( expected );
 		}
 
-		before( () => {
-			writer = new DowncastWriter( new Document() );
+		beforeEach( () => {
+			document = new Document();
+			writer = new DowncastWriter( document );
 		} );
 
 		it( 'should do nothing on collapsed ranges', () => {
@@ -60,9 +62,9 @@ describe( 'DowncastWriter', () => {
 			);
 			const b = new Element( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.unwrap( range, b );
-			} ).to.throw( CKEditorError, 'view-writer-unwrap-invalid-attribute' );
+			}, 'view-writer-unwrap-invalid-attribute', document );
 		} );
 
 		it( 'should throw error when range placed in two containers', () => {
@@ -74,18 +76,18 @@ describe( 'DowncastWriter', () => {
 			);
 			const b = new AttributeElement( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.unwrap( range, b );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+			}, 'view-writer-invalid-range-container', document );
 		} );
 
 		it( 'should throw when range has no parent container', () => {
 			const el = new AttributeElement( 'b' );
 			const b = new AttributeElement( 'b' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.unwrap( Range._createFromParentsAndOffsets( el, 0, el, 0 ), b );
-			} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+			}, 'view-writer-invalid-range-container', document );
 		} );
 
 		it( 'should unwrap single node', () => {
@@ -399,9 +401,9 @@ describe( 'DowncastWriter', () => {
 			const container = new ContainerElement( 'p', null, [ empty, attribute ] );
 			const range = Range._createFromParentsAndOffsets( empty, 0, container, 2 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.unwrap( range, attribute );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+			}, 'view-writer-cannot-break-empty-element', document );
 		} );
 
 		it( 'should unwrap UIElement', () => {
@@ -418,9 +420,9 @@ describe( 'DowncastWriter', () => {
 			const container = new ContainerElement( 'p', null, [ uiElement, attribute ] );
 			const range = Range._createFromParentsAndOffsets( uiElement, 0, container, 2 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				writer.unwrap( range, attribute );
-			} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+			}, 'view-writer-cannot-break-ui-element', document );
 		} );
 
 		it( 'should unwrap if both elements have same id', () => {

+ 18 - 16
packages/ckeditor5-engine/tests/view/downcastwriter/wrap.js

@@ -14,17 +14,19 @@ import UIElement from '../../../src/view/uielement';
 import Position from '../../../src/view/position';
 import Range from '../../../src/view/range';
 import Text from '../../../src/view/text';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import { stringify, parse } from '../../../src/dev-utils/view';
 import createViewRoot from '../_utils/createroot';
 import Document from '../../../src/view/document';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'DowncastWriter', () => {
 	describe( 'wrap()', () => {
-		let writer;
+		let writer, document;
 
-		before( () => {
-			writer = new DowncastWriter( new Document() );
+		beforeEach( () => {
+			document = new Document();
+			writer = new DowncastWriter( document );
 		} );
 
 		describe( 'non-collapsed range', () => {
@@ -67,9 +69,9 @@ describe( 'DowncastWriter', () => {
 				);
 				const b = new Element( 'b' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.wrap( range, b );
-				} ).to.throw( CKEditorError, 'view-writer-wrap-invalid-attribute' );
+				}, 'view-writer-wrap-invalid-attribute', document );
 			} );
 
 			it( 'should throw error when range placed in two containers', () => {
@@ -81,18 +83,18 @@ describe( 'DowncastWriter', () => {
 				);
 				const b = new AttributeElement( 'b' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.wrap( range, b );
-				} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+				}, 'view-writer-invalid-range-container', document );
 			} );
 
 			it( 'should throw when range has no parent container', () => {
 				const el = new AttributeElement( 'b' );
 				const b = new AttributeElement( 'b' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.wrap( Range._createFromParentsAndOffsets( el, 0, el, 0 ), b );
-				} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
+				}, 'view-writer-invalid-range-container', document );
 			} );
 
 			it( 'wraps part of a single text node #1', () => {
@@ -396,9 +398,9 @@ describe( 'DowncastWriter', () => {
 				const container = new ContainerElement( 'p', null, emptyElement );
 				const range = Range._createFromParentsAndOffsets( emptyElement, 0, container, 1 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.wrap( range, new AttributeElement( 'b' ) );
-				} ).to.throw( CKEditorError, 'view-writer-cannot-break-empty-element' );
+				}, 'view-writer-cannot-break-empty-element', document );
 			} );
 
 			it( 'should wrap UIElement', () => {
@@ -414,9 +416,9 @@ describe( 'DowncastWriter', () => {
 				const container = new ContainerElement( 'p', null, uiElement );
 				const range = Range._createFromParentsAndOffsets( uiElement, 0, container, 1 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.wrap( range, new AttributeElement( 'b' ) );
-				} ).to.throw( CKEditorError, 'view-writer-cannot-break-ui-element' );
+				}, 'view-writer-cannot-break-ui-element', document );
 			} );
 
 			it( 'should keep stable hierarchy when wrapping with attribute with same priority', () => {
@@ -551,9 +553,9 @@ describe( 'DowncastWriter', () => {
 				const position = new Position( container, 0 );
 				const b = new Element( 'b' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					writer.wrap( new Range( position ), b );
-				} ).to.throw( CKEditorError, 'view-writer-wrap-invalid-attribute' );
+				}, 'view-writer-wrap-invalid-attribute', document );
 			} );
 
 			it( 'should wrap position at the beginning of text node', () => {

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

@@ -4,9 +4,10 @@
  */
 
 import createDocumentMock from '../../tests/view/_utils/createdocumentmock';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import RootEditableElement from '../../src/view/rooteditableelement';
 import Range from '../../src/view/range';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'EditableElement', () => {
 	describe( 'document', () => {
@@ -31,9 +32,9 @@ describe( 'EditableElement', () => {
 			element._document = docMock;
 			const newDoc = createDocumentMock();
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				element._document = newDoc;
-			} ).to.throw( CKEditorError, 'view-editableelement-document-already-set: View document is already set.' );
+			}, 'view-editableelement-document-already-set: View document is already set.', docMock );
 		} );
 
 		it( 'should be cloned properly', () => {

+ 11 - 8
packages/ckeditor5-engine/tests/view/emptyelement.js

@@ -5,7 +5,8 @@
 
 import EmptyElement from '../../src/view/emptyelement';
 import Element from '../../src/view/element';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'EmptyElement', () => {
 	let element, emptyElement;
@@ -49,24 +50,26 @@ describe( 'EmptyElement', () => {
 	} );
 
 	it( 'should throw if child elements are passed to constructor', () => {
-		expect( () => {
-			new EmptyElement( 'img', null, [ new Element( 'i' ) ] ); // eslint-disable-line no-new
-		} ).to.throw( CKEditorError, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
+		const el = new Element( 'i' );
+
+		expectToThrowCKEditorError( () => {
+			new EmptyElement( 'img', null, [ el ] ); // eslint-disable-line no-new
+		}, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', el );
 	} );
 
 	describe( '_appendChild', () => {
 		it( 'should throw when try to append new child element', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				emptyElement._appendChild( element );
-			} ).to.throw( CKEditorError, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
+			}, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', element );
 		} );
 	} );
 
 	describe( '_insertChild', () => {
 		it( 'should throw when try to insert new child element', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				emptyElement._insertChild( 0, element );
-			} ).to.throw( CKEditorError, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.' );
+			}, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', element );
 		} );
 	} );
 

+ 4 - 6
packages/ckeditor5-engine/tests/view/node.js

@@ -8,9 +8,9 @@ import Text from '../../src/view/text';
 import Node from '../../src/view/node';
 import DocumentFragment from '../../src/view/documentfragment';
 import RootEditableElement from '../../src/view/rooteditableelement';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import createDocumentMock from '../../tests/view/_utils/createdocumentmock';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Node', () => {
 	let root,
@@ -215,11 +215,9 @@ describe( 'Node', () => {
 
 			f.parent = bar;
 
-			expect(
-				() => {
-					f.index;
-				}
-			).to.throw( CKEditorError, /view-node-not-found-in-parent/ );
+			expectToThrowCKEditorError( () => {
+				f.index;
+			}, /view-node-not-found-in-parent/, bar );
 		} );
 	} );
 

+ 14 - 9
packages/ckeditor5-engine/tests/view/position.js

@@ -12,13 +12,12 @@ import Document from '../../src/view/document';
 import Text from '../../src/view/text';
 import TextProxy from '../../src/view/textproxy';
 
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
-
 import { parse, stringify } from '../../src/dev-utils/view';
 import TreeWalker from '../../src/view/treewalker';
 import createViewRoot from './_utils/createroot';
 import AttributeElement from '../../src/view/attributeelement';
 import ContainerElement from '../../src/view/containerelement';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Position', () => {
 	const parentMock = {};
@@ -383,7 +382,9 @@ describe( 'Position', () => {
 			it( 'should throw if no offset is passed', () => {
 				const element = new Element( 'p' );
 
-				expect( () => Position._createAt( element ) ).to.throw( CKEditorError, /view-createPositionAt-offset-required/ );
+				expectToThrowCKEditorError( () => {
+					Position._createAt( element );
+				}, /view-createPositionAt-offset-required/ );
 			} );
 
 			it( 'should create positions from positions', () => {
@@ -449,9 +450,11 @@ describe( 'Position', () => {
 
 		describe( '_createBefore()', () => {
 			it( 'should throw error if one try to create positions before root', () => {
-				expect( () => {
-					Position._createBefore( parse( '<p></p>' ) );
-				} ).to.throw( CKEditorError, /view-position-before-root/ );
+				const paragraph = parse( '<p></p>' );
+
+				expectToThrowCKEditorError( () => {
+					Position._createBefore( paragraph );
+				}, /view-position-before-root/, paragraph );
 			} );
 
 			it( 'should create positions before `Node`', () => {
@@ -474,9 +477,11 @@ describe( 'Position', () => {
 
 		describe( '_createAfter()', () => {
 			it( 'should throw error if one try to create positions after root', () => {
-				expect( () => {
-					Position._createAfter( parse( '<p></p>' ) );
-				} ).to.throw( CKEditorError, /view-position-after-root/ );
+				const paragraph = parse( '<p></p>' );
+
+				expectToThrowCKEditorError( () => {
+					Position._createAfter( paragraph );
+				}, /view-position-after-root/, paragraph );
 			} );
 
 			it( 'should create positions after `Node`', () => {

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

@@ -19,7 +19,7 @@ import DomConverter from '../../src/view/domconverter';
 import Renderer from '../../src/view/renderer';
 import DocumentFragment from '../../src/view/documentfragment';
 import DowncastWriter from '../../src/view/downcastwriter';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import { parse, setData as setViewData, getData as getViewData } from '../../src/dev-utils/view';
 import { INLINE_FILLER, INLINE_FILLER_LENGTH, isBlockFiller, BR_FILLER } from '../../src/view/filler';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
@@ -27,6 +27,7 @@ import createViewRoot from './_utils/createroot';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
 import env from '@ckeditor/ckeditor5-utils/src/env';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Renderer', () => {
 	let selection, domConverter, renderer;
@@ -106,9 +107,9 @@ describe( 'Renderer', () => {
 		} );
 
 		it( 'should throw if the type is unknown', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				renderer.markToSync( 'UNKNOWN', viewRoot );
-			} ).to.throw( CKEditorError, /^view-renderer-unknown-type/ );
+			}, /^view-renderer-unknown-type/, selection );
 		} );
 	} );
 
@@ -1300,9 +1301,9 @@ describe( 'Renderer', () => {
 			selection._setTo( null );
 			renderer.markToSync( 'children', viewB );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				renderer.render();
-			} ).to.throw( CKEditorError, /^view-renderer-filler-was-lost/ );
+			}, /^view-renderer-filler-was-lost/, selection );
 		} );
 
 		// #1014.

+ 20 - 19
packages/ckeditor5-engine/tests/view/selection.js

@@ -10,11 +10,12 @@ import Document from '../../src/view/document';
 import Element from '../../src/view/element';
 import Text from '../../src/view/text';
 import Position from '../../src/view/position';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
 import count from '@ckeditor/ckeditor5-utils/src/count';
 import createViewRoot from './_utils/createroot';
 import { parse } from '../../src/dev-utils/view';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'Selection', () => {
 	let selection, el, range1, range2, range3;
@@ -113,27 +114,27 @@ describe( 'Selection', () => {
 		} );
 
 		it( 'should throw an error when range is invalid', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new Selection( [ { invalid: 'range' } ] );
-			} ).to.throw( CKEditorError, /view-selection-add-range-not-range/ );
+			}, /view-selection-add-range-not-range/ );
 		} );
 
 		it( 'should throw an error when ranges intersects', () => {
 			const text = el.getChild( 0 );
 			const range2 = Range._createFromParentsAndOffsets( text, 7, text, 15 );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new Selection( [ range1, range2 ] );
-			} ).to.throw( CKEditorError, 'view-selection-range-intersects' );
+			}, 'view-selection-range-intersects' );
 		} );
 
 		it( 'should throw an error when trying to set to not selectable', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new Selection( {} );
-			} ).to.throw( /view-selection-setTo-not-selectable/ );
+			}, /view-selection-setTo-not-selectable/ );
 		} );
 	} );
 
@@ -203,9 +204,9 @@ describe( 'Selection', () => {
 		it( 'throws if there are no ranges in selection', () => {
 			const endPos = Position._createAt( el, 'end' );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				selection.setFocus( endPos );
-			} ).to.throw( CKEditorError, /view-selection-setFocus-no-ranges/ );
+			}, /view-selection-setFocus-no-ranges/ );
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
@@ -679,17 +680,17 @@ describe( 'Selection', () => {
 			it( 'should throw an error when trying to set to not selectable', () => {
 				const otherSelection = new Selection();
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					otherSelection.setTo( {} );
-				} ).to.throw( /view-selection-setTo-not-selectable/ );
+				}, /view-selection-setTo-not-selectable/ );
 			} );
 
 			it( 'should throw an error when trying to set to not selectable #2', () => {
 				const otherSelection = new Selection();
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					otherSelection.setTo();
-				} ).to.throw( /view-selection-setTo-not-selectable/ );
+				}, /view-selection-setTo-not-selectable/ );
 			} );
 		} );
 
@@ -731,9 +732,9 @@ describe( 'Selection', () => {
 			it( 'should throw an error when the second parameter is not passed and first is an item', () => {
 				const foo = new Text( 'foo' );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					selection.setTo( foo );
-				} ).to.throw( CKEditorError, /view-selection-setTo-required-second-parameter/ );
+				}, /view-selection-setTo-required-second-parameter/ );
 			} );
 
 			it( 'should collapse selection at node and flag', () => {
@@ -878,18 +879,18 @@ describe( 'Selection', () => {
 
 		describe( 'throwing errors', () => {
 			it( 'should throw an error when range is invalid', () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					selection.setTo( [ { invalid: 'range' } ] );
-				} ).to.throw( CKEditorError, /view-selection-add-range-not-range/ );
+				}, /view-selection-add-range-not-range/ );
 			} );
 
 			it( 'should throw when range is intersecting with already added range', () => {
 				const text = el.getChild( 0 );
 				const range2 = Range._createFromParentsAndOffsets( text, 7, text, 15 );
 
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					selection.setTo( [ range1, range2 ] );
-				} ).to.throw( CKEditorError, 'view-selection-range-intersects' );
+				}, 'view-selection-range-intersects' );
 			} );
 		} );
 

+ 9 - 9
packages/ckeditor5-engine/tests/view/textproxy.js

@@ -8,9 +8,9 @@ import Text from '../../src/view/text';
 import ContainerElement from '../../src/view/containerelement';
 import DocumentFragment from '../../src/view/documentfragment';
 import RootEditableElement from '../../src/view/rooteditableelement';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 
 import createDocumentMock from '../../tests/view/_utils/createdocumentmock';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'TextProxy', () => {
 	let text, parent, wrapper, textProxy;
@@ -41,23 +41,23 @@ describe( 'TextProxy', () => {
 		} );
 
 		it( 'should throw if wrong offsetInText is passed', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TextProxy( text, -1, 2 ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /view-textproxy-wrong-offsetintext/ );
+			}, /view-textproxy-wrong-offsetintext/ );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TextProxy( text, 9, 1 ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /view-textproxy-wrong-offsetintext/ );
+			}, /view-textproxy-wrong-offsetintext/ );
 		} );
 
 		it( 'should throw if wrong length is passed', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TextProxy( text, 2, -1 ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /view-textproxy-wrong-length/ );
+			}, /view-textproxy-wrong-length/ );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TextProxy( text, 2, 9 ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /view-textproxy-wrong-length/ );
+			}, /view-textproxy-wrong-length/ );
 		} );
 	} );
 

+ 9 - 9
packages/ckeditor5-engine/tests/view/treewalker.js

@@ -12,7 +12,7 @@ import TreeWalker from '../../src/view/treewalker';
 import Position from '../../src/view/position';
 import Range from '../../src/view/range';
 import createViewRoot from './_utils/createroot';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'TreeWalker', () => {
 	let doc, root, img1, paragraph, bold, textAbcd, charY, img2, charX, rootBeginning, rootEnding;
@@ -50,23 +50,23 @@ describe( 'TreeWalker', () => {
 
 	describe( 'constructor()', () => {
 		it( 'should throw if neither boundaries nor starting position is set', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker(); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^view-tree-walker-no-start-position/ );
+			}, /^view-tree-walker-no-start-position/, null );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker( {} ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^view-tree-walker-no-start-position/ );
+			}, /^view-tree-walker-no-start-position/, null );
 
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker( { singleCharacters: true } ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^view-tree-walker-no-start-position/ );
+			}, /^view-tree-walker-no-start-position/, null );
 		} );
 
 		it( 'should throw if walking direction is unknown', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new TreeWalker( { startPosition: rootBeginning, direction: 'unknown' } ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, /^view-tree-walker-unknown-direction/ );
+			}, /^view-tree-walker-unknown-direction/, doc );
 		} );
 	} );
 

+ 7 - 7
packages/ckeditor5-engine/tests/view/uielement.js

@@ -7,7 +7,7 @@
 
 import UIElement from '../../src/view/uielement';
 import Element from '../../src/view/element';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'UIElement', () => {
 	let uiElement;
@@ -31,9 +31,9 @@ describe( 'UIElement', () => {
 		} );
 
 		it( 'should throw if child elements are passed to constructor', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				new UIElement( 'img', null, [ new Element( 'i' ) ] ); // eslint-disable-line no-new
-			} ).to.throw( CKEditorError, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
+			}, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
 		} );
 	} );
 
@@ -68,17 +68,17 @@ describe( 'UIElement', () => {
 
 	describe( '_appendChild()', () => {
 		it( 'should throw when try to append new child element', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				uiElement._appendChild( new Element( 'i' ) );
-			} ).to.throw( CKEditorError, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
+			}, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
 		} );
 	} );
 
 	describe( '_insertChild()', () => {
 		it( 'should throw when try to insert new child element', () => {
-			expect( () => {
+			expectToThrowCKEditorError( () => {
 				uiElement._insertChild( 0, new Element( 'i' ) );
-			} ).to.throw( CKEditorError, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
+			}, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' );
 		} );
 	} );
 

+ 6 - 4
packages/ckeditor5-engine/tests/view/view/view.js

@@ -19,7 +19,6 @@ import ViewElement from '../../../src/view/element';
 import ViewPosition from '../../../src/view/position';
 import ViewSelection from '../../../src/view/selection';
 import { isBlockFiller, BR_FILLER } from '../../../src/view/filler';
-import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 
 import count from '@ckeditor/ckeditor5-utils/src/count';
@@ -27,6 +26,7 @@ import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 import createViewRoot from '../_utils/createroot';
 import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'view', () => {
 	const DEFAULT_OBSERVERS_COUNT = 7;
@@ -620,7 +620,9 @@ describe( 'view', () => {
 				const ui = writer.createUIElement( 'span', null, function( domDocument ) {
 					const element = this.toDomElement( domDocument );
 
-					expect( () => view.change( () => {} ) ).to.throw( CKEditorError, /^cannot-change-view-tree/ );
+					expectToThrowCKEditorError( () => {
+						view.change( () => {} );
+					}, /^cannot-change-view-tree/, view );
 					renderingCalled = true;
 
 					return element;
@@ -639,9 +641,9 @@ describe( 'view', () => {
 			view.attachDomRoot( domDiv );
 
 			viewDocument.registerPostFixer( () => {
-				expect( () => {
+				expectToThrowCKEditorError( () => {
 					view.change( () => {} );
-				} ).to.throw( CKEditorError, /^cannot-change-view-tree/ );
+				}, /^cannot-change-view-tree/, view );
 			} );
 
 			view.forceRender();