Browse Source

Improved tests, fixed small error in the Watchdog.

Maciej Bukowski 6 years ago
parent
commit
111b9aac1e

+ 1 - 0
packages/ckeditor5-watchdog/package.json

@@ -13,6 +13,7 @@
     "lodash-es": "^4.17.10"
   },
   "devDependencies": {
+    "@ckeditor/ckeditor5-paragraph": "^11.0.2",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^1.0.11",
     "husky": "^2.4.1",

+ 2 - 1
packages/ckeditor5-watchdog/src/watchdog.js

@@ -144,7 +144,7 @@ export default class Watchdog {
 	}
 
 	/**
-	 * @param {HTMLElement} element
+	 * @param {HTMLElement|module:core/editor/editorconfig~EditorConfig} element
 	 * @param {module:core/editor/editorconfig~EditorConfig} [config]
 	 *
 	 * @returns {Promise.<Watchdog>}
@@ -308,6 +308,7 @@ function shouldNodeBeSkipped( obj ) {
 
 	return (
 		type === '[object Number]' ||
+		type === '[object Boolean]' ||
 		type === '[object String]' ||
 		type === '[object Function]' ||
 		type === '[object Date]' ||

+ 57 - 76
packages/ckeditor5-watchdog/tests/watchdog.js

@@ -6,6 +6,7 @@
 import Watchdog from '../src/watchdog';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 
 describe( 'Watchdog', () => {
 	afterEach( () => sinon.restore() );
@@ -14,10 +15,10 @@ describe( 'Watchdog', () => {
 		it( 'should create an editor instance', () => {
 			const watchdog = new Watchdog();
 
-			const editorCreateSpy = sinon.spy( VirtualTestEditor, 'create' );
-			const editorDestroySpy = sinon.spy( VirtualTestEditor.prototype, 'destroy' );
+			const editorCreateSpy = sinon.spy( FakeEditor, 'create' );
+			const editorDestroySpy = sinon.spy( FakeEditor.prototype, 'destroy' );
 
-			watchdog.setCreator( ( el, config ) => VirtualTestEditor.create( el, config ) );
+			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
 
 			return watchdog.create( document.createElement( 'div' ), {} )
@@ -42,7 +43,7 @@ describe( 'Watchdog', () => {
 
 		it( 'should throw an error when the destructor is not defined', () => {
 			const watchdog = new Watchdog();
-			watchdog.setCreator( ( el, config ) => VirtualTestEditor.create( el, config ) );
+			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 
 			expect( () => watchdog.create() ).to.throw( CKEditorError, /^watchdog-destructor-not-defined/ );
 		} );
@@ -52,10 +53,10 @@ describe( 'Watchdog', () => {
 		it( 'should restart the editor', () => {
 			const watchdog = new Watchdog();
 
-			const editorCreateSpy = sinon.spy( VirtualTestEditor, 'create' );
-			const editorDestroySpy = sinon.spy( VirtualTestEditor.prototype, 'destroy' );
+			const editorCreateSpy = sinon.spy( FakeEditor, 'create' );
+			const editorDestroySpy = sinon.spy( FakeEditor.prototype, 'destroy' );
 
-			watchdog.setCreator( ( el, config ) => VirtualTestEditor.create( el, config ) );
+			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
 
 			return watchdog.create( document.createElement( 'div' ), {} )
@@ -76,21 +77,20 @@ describe( 'Watchdog', () => {
 		it( 'should restart the editor with the same data', () => {
 			const watchdog = new Watchdog();
 
-			// VirtualTestEditor doesn't handle the `config.initialData` properly.
-			// See https://github.com/ckeditor/ckeditor5-core/issues/180.
-			const FakeEditor = getFakeEditor();
-
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
 
-			return watchdog.create( document.createElement( 'div' ), { initialData: 'foo' } )
+			return watchdog.create( document.createElement( 'div' ), {
+				initialData: '<p>foo</p>',
+				plugins: [ Paragraph ]
+			} )
 				.then( () => {
-					expect( watchdog.editor.getData() ).to.equal( 'foo' );
+					expect( watchdog.editor.getData() ).to.equal( '<p>foo</p>' );
 
 					return watchdog.restart();
 				} )
 				.then( () => {
-					expect( watchdog.editor.getData() ).to.equal( 'foo' );
+					expect( watchdog.editor.getData() ).to.equal( '<p>foo</p>' );
 
 					return watchdog.destroy();
 				} );
@@ -101,7 +101,7 @@ describe( 'Watchdog', () => {
 		it( 'should be the current editor instance', () => {
 			const watchdog = new Watchdog();
 
-			watchdog.setCreator( ( el, config ) => VirtualTestEditor.create( el, config ) );
+			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
 
 			expect( watchdog.editor ).to.be.null;
@@ -111,12 +111,12 @@ describe( 'Watchdog', () => {
 			return watchdog.create( document.createElement( 'div' ), {} )
 				.then( () => {
 					oldEditor = watchdog.editor;
-					expect( watchdog.editor ).to.be.instanceOf( VirtualTestEditor );
+					expect( watchdog.editor ).to.be.instanceOf( FakeEditor );
 
 					return watchdog.restart();
 				} )
 				.then( () => {
-					expect( watchdog.editor ).to.be.instanceOf( VirtualTestEditor );
+					expect( watchdog.editor ).to.be.instanceOf( FakeEditor );
 					expect( watchdog.editor ).to.not.equal( oldEditor );
 
 					return watchdog.destroy();
@@ -132,7 +132,7 @@ describe( 'Watchdog', () => {
 			const watchdog = new Watchdog();
 
 			watchdog.setCreator( el =>
-				VirtualTestEditor.create( el )
+				FakeEditor.create( el )
 					.then( () => Promise.reject( new Error( 'foo' ) ) )
 			);
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -149,7 +149,7 @@ describe( 'Watchdog', () => {
 		it( 'Watchdog should not restart editor during the destroy', () => {
 			const watchdog = new Watchdog();
 
-			watchdog.setCreator( el => VirtualTestEditor.create( el ) );
+			watchdog.setCreator( el => FakeEditor.create( el ) );
 			watchdog.setDestructor( () => Promise.reject( new Error( 'foo' ) ) );
 
 			return Promise.resolve()
@@ -166,7 +166,6 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should intercept editor errors and restart the editor during the runtime', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -176,7 +175,7 @@ describe( 'Watchdog', () => {
 			window.onerror = undefined;
 
 			return watchdog.create( document.createElement( 'div' ) ).then( () => {
-				setTimeout( () => { watchdog.editor.throwEditorError() } );
+				setTimeout( () => { throw new CKEditorError( 'foo', undefined, watchdog.editor ); } );
 
 				return new Promise( res => {
 					watchdog.on( 'restart', () => {
@@ -190,7 +189,6 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should not hide intercepted errors', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -201,7 +199,7 @@ describe( 'Watchdog', () => {
 			window.onerror = windowErrorSpy
 
 			return watchdog.create( document.createElement( 'div' ) ).then( () => {
-				setTimeout( () => { watchdog.editor.throwEditorError() } );
+				setTimeout( () => { throw new CKEditorError( 'foo', undefined, watchdog.editor ); } );
 
 				return new Promise( res => {
 					watchdog.on( 'restart', () => {
@@ -218,7 +216,6 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should intercept editor errors and restart the editor during the runtime', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -228,7 +225,7 @@ describe( 'Watchdog', () => {
 			window.onerror = undefined;
 
 			return watchdog.create( document.createElement( 'div' ) ).then( () => {
-				setTimeout( () => { watchdog.editor.throwEditorError() } );
+				setTimeout( () => { throw new CKEditorError( 'foo', undefined, watchdog.editor ); } );
 
 				return new Promise( res => {
 					watchdog.on( 'restart', () => {
@@ -242,7 +239,6 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should not intercept non-editor errors', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -272,13 +268,11 @@ describe( 'Watchdog', () => {
 		it( 'Watchdog should not intercept other editor errors', () => {
 			const watchdog1 = new Watchdog();
 			const watchdog2 = new Watchdog();
-			const FakeEditor1 = getFakeEditor();
-			const FakeEditor2 = getFakeEditor();
 
-			watchdog1.setCreator( ( el, config ) => FakeEditor1.create( el, config ) );
+			watchdog1.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog1.setDestructor( editor => editor.destroy() );
 
-			watchdog2.setCreator( ( el, config ) => FakeEditor2.create( el, config ) );
+			watchdog2.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog2.setDestructor( editor => editor.destroy() );
 
 			// sinon.stub( window, 'onerror' ).value( undefined ); and similar don't work.
@@ -316,14 +310,13 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should intercept editor errors and restart the editor during the runtime if the editor can be found from the ctx', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
 
 			// sinon.stub( window, 'onerror' ).value( undefined ); and similar don't work.
 			const originalErrorHandler = window.onerror;
-			window.onerror = undefined;
+			window.onerror = undefined
 
 			return watchdog.create( document.createElement( 'div' ) ).then( () => {
 				setTimeout( () => { throw new CKEditorError( 'foo', undefined, watchdog.editor.model.document ); } );
@@ -340,7 +333,6 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should intercept editor errors and restart the editor during the runtime if the editor can be found from the ctx #2', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -364,7 +356,6 @@ describe( 'Watchdog', () => {
 
 		it( 'editor should be restarted maximum 3 times by default', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -401,7 +392,6 @@ describe( 'Watchdog', () => {
 
 		it( 'editor should be restarted maximum of `crashNumberLimit` if the option is set', () => {
 			const watchdog = new Watchdog( { crashNumberLimit: 2 } );
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -438,7 +428,6 @@ describe( 'Watchdog', () => {
 
 		it( 'editor should be reinitialized with the last data', () => {
 			const watchdog = new Watchdog( { crashNumberLimit: 2 } );
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -475,7 +464,6 @@ describe( 'Watchdog', () => {
 
 		it( 'Watchdog should warn if the CKEditorError missing its context', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -503,12 +491,39 @@ describe( 'Watchdog', () => {
 				} );
 			} );
 		} );
+
+		it( 'editor should be restarted with the correct data when an error occurs #1', () => {
+			const watchdog = new Watchdog();
+
+			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
+			watchdog.setDestructor( editor => editor.destroy() );
+
+			// sinon.stub( window, 'onerror' ).value( undefined ); and similar don't work.
+			const originalErrorHandler = window.onerror;
+			window.onerror = undefined;
+
+			return watchdog.create( document.createElement( 'div' ), {
+				initialData: '<p>foo</p>',
+				plugins: [ Paragraph ]
+			} ).then( () => {
+				setTimeout( () => { throw new CKEditorError( 'foo', undefined, watchdog.editor ); } );
+
+				return new Promise( res => {
+					watchdog.on( 'restart', () => {
+						window.onerror = originalErrorHandler;
+
+						expect( watchdog.editor.getData() ).to.equal( '<p>foo</p>' );
+
+						watchdog.destroy().then( res );
+					} );
+				} );
+			} );
+		} );
 	} );
 
 	describe( 'crashes', () => {
 		it( 'should be an array of caught errors by the Watchdog', () => {
 			const watchdog = new Watchdog();
-			const FakeEditor = getFakeEditor();
 
 			watchdog.setCreator( ( el, config ) => FakeEditor.create( el, config ) );
 			watchdog.setDestructor( editor => editor.destroy() );
@@ -537,43 +552,9 @@ describe( 'Watchdog', () => {
 	} );
 } );
 
-function getFakeEditor() {
-	return class FakeEditor {
-		static create( el, config ) {
-			const editor = new this();
-
-			return Promise.resolve()
-				.then( () => editor.create( el, config ) );
-		}
-
-		create( el, config = {} ) {
-			this.el = el;
-			this.config = config;
-			this._data = config.initialData || '';
-
-			return this;
-		}
-
-		constructor() {
-			this.model = {
-				document: {
-					version: 0
-				}
-			};
-		}
-
-		getData() {
-			return this._data;
-		}
-
-		destroy() {
-			this.el.remove();
-
-			return Promise.resolve();
-		}
-
-		throwEditorError() {
-			throw new CKEditorError( 'foo', undefined, this );
-		}
+// Wrap Editor to follow the API.
+class FakeEditor extends VirtualTestEditor {
+	static create( elementOrData, config ) {
+		return super.create( config );
 	}
 }