diff --git a/src/watchdog.js b/src/watchdog.js index a2d011f..d02ef49 100644 --- a/src/watchdog.js +++ b/src/watchdog.js @@ -164,7 +164,7 @@ export default class Watchdog { * @param {HTMLElement|String} elementOrData * @param {module:core/editor/editorconfig~EditorConfig} [config] * - * @returns {Promise.} + * @returns {Promise} */ create( elementOrData, config ) { if ( !this._creator ) { @@ -214,44 +214,13 @@ export default class Watchdog { this._lastDocumentVersion = editor.model.document.version; this._data = editor.data.get(); - - return this; - } ); - } - - /** - * Restarts the editor instance. This method is also called whenever an editor error occurs. - * It fires the `restart` event. - * - * @fires restart - * @returns {Promise} - */ - restart() { - this._throttledSave.flush(); - - return Promise.resolve() - .then( () => this.destroy() ) - .catch( err => console.error( 'An error happened during the editor destructing.', err ) ) - .then( () => { - if ( typeof this._elementOrData === 'string' ) { - return this.create( this._data, this._config ); - } - - const updatedConfig = Object.assign( {}, this._config, { - initialData: this._data - } ); - - return this.create( this._elementOrData, updatedConfig ); - } ) - .then( () => { - this.fire( 'restart' ); } ); } /** * Destroys the current editor instance by using the destructor passed to the {@link #setDestructor `setDestructor()`} method. * - * @returns {Promise.} + * @returns {Promise} */ destroy() { window.removeEventListener( 'error', this._boundErrorHandler ); @@ -261,8 +230,6 @@ export default class Watchdog { .then( () => this._destructor( this._editor ) ) .then( () => { this._editor = null; - - return this; } ); } @@ -329,11 +296,40 @@ export default class Watchdog { this.fire( 'error' ); if ( this.crashes.length <= this._crashNumberLimit ) { - this.restart(); + this._restart(); } } } + /** + * Restarts the editor instance. This method is called whenever an editor error occurs. It fires the `restart` event. + * + * @private + * @fires restart + * @returns {Promise} + */ + _restart() { + this._throttledSave.flush(); + + return Promise.resolve() + .then( () => this.destroy() ) + .catch( err => console.error( 'An error happened during the editor destructing.', err ) ) + .then( () => { + if ( typeof this._elementOrData === 'string' ) { + return this.create( this._data, this._config ); + } + + const updatedConfig = Object.assign( {}, this._config, { + initialData: this._data + } ); + + return this.create( this._elementOrData, updatedConfig ); + } ) + .then( () => { + this.fire( 'restart' ); + } ); + } + /** * Traverses both structures to find out whether the error context is connected * with the current editor. @@ -373,7 +369,7 @@ export default class Watchdog { */ /** - * Fired after the watchdog restarts the error in case of a crash or when the `restart()` method was called explicitly. + * Fired after the watchdog restarts the error in case of a crash. * * @event restart */ diff --git a/tests/manual/watchdog.js b/tests/manual/watchdog.js index 1708423..b13896e 100644 --- a/tests/manual/watchdog.js +++ b/tests/manual/watchdog.js @@ -14,7 +14,6 @@ import Watchdog from '../../src/watchdog'; const firstEditorElement = document.getElementById( 'editor-1' ); const secondEditorElement = document.getElementById( 'editor-2' ); -const restartButton = document.getElementById( 'restart' ); const randomErrorButton = document.getElementById( 'random-error' ); class TypingError { @@ -55,9 +54,7 @@ const editorConfig = { const watchdog1 = Watchdog.for( ClassicEditor ); window.watchdog1 = watchdog1; -watchdog1.create( firstEditorElement, editorConfig ).then( () => { - console.log( 'First editor created.' ); -} ); +watchdog1.create( firstEditorElement, editorConfig ); watchdog1.on( 'error', () => { console.log( 'First editor crashed!' ); @@ -72,9 +69,7 @@ watchdog1.on( 'restart', () => { const watchdog2 = Watchdog.for( ClassicEditor ); window.watchdog2 = watchdog2; -watchdog2.create( secondEditorElement, editorConfig ).then( () => { - console.log( 'Second editor created.' ); -} ); +watchdog2.create( secondEditorElement, editorConfig ); watchdog2.on( 'error', () => { console.log( 'Second editor crashed!' ); @@ -84,11 +79,6 @@ watchdog2.on( 'restart', () => { console.log( 'Second editor restarted.' ); } ); -restartButton.addEventListener( 'click', () => { - watchdog1.restart(); - watchdog2.restart(); -} ); - randomErrorButton.addEventListener( 'click', () => { throw new Error( 'foo' ); } ); diff --git a/tests/manual/watchdog.md b/tests/manual/watchdog.md index 84e4793..8ff5590 100644 --- a/tests/manual/watchdog.md +++ b/tests/manual/watchdog.md @@ -5,5 +5,3 @@ 1. Click `Simulate a random error` No editor should be restarted. 1. Refresh page and type `1` in the first editor 4 times. The last time the editor should not be restarted. - -1. Run `restart both editor`. Both editors should be restarted. diff --git a/tests/watchdog.js b/tests/watchdog.js index e3899ed..f6731d1 100644 --- a/tests/watchdog.js +++ b/tests/watchdog.js @@ -84,66 +84,30 @@ describe( 'Watchdog', () => { expect( watchdog.editor.config._config.bar ).to.equal( config.bar ); } ); } ); - } ); - - describe( 'restart()', () => { - it( 'should restart the editor', () => { - const watchdog = new Watchdog(); - - const editorCreateSpy = sinon.spy( ClassicTestEditor, 'create' ); - const editorDestroySpy = sinon.spy( ClassicTestEditor.prototype, 'destroy' ); - - watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); - - return watchdog.create( element, {} ) - .then( () => { - sinon.assert.calledOnce( editorCreateSpy ); - sinon.assert.notCalled( editorDestroySpy ); - - return watchdog.restart(); - } ) - .then( () => { - sinon.assert.calledTwice( editorCreateSpy ); - sinon.assert.calledOnce( editorDestroySpy ); - - return watchdog.destroy(); - } ); - } ); - - it( 'should restart the editor with the same data', () => { - const watchdog = new Watchdog(); - - watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); - - return watchdog.create( element, { - initialData: '

foo

', - plugins: [ Paragraph ] - } ) - .then( () => { - expect( watchdog.editor.getData() ).to.equal( '

foo

' ); - - return watchdog.restart(); - } ) - .then( () => { - expect( watchdog.editor.getData() ).to.equal( '

foo

' ); - return watchdog.destroy(); - } ); - } ); - - it( 'should support editor data passed as the `Editor.create()` as the first argument', () => { + it( 'should support editor data passed as the first argument', () => { const watchdog = new Watchdog(); watchdog.setCreator( ( data, config ) => ClassicTestEditor.create( data, config ) ); watchdog.setDestructor( editor => editor.destroy() ); + // sinon.stub( window, 'onerror' ).value( undefined ); and similar do not work. + const originalErrorHandler = window.onerror; + const windowErrorSpy = sinon.spy(); + window.onerror = windowErrorSpy; + return watchdog.create( '

foo

', { plugins: [ Paragraph ] } ) .then( () => { expect( watchdog.editor.getData() ).to.equal( '

foo

' ); - return watchdog.restart(); + return new Promise( res => { + setTimeout( () => throwCKEditorError( 'foo', watchdog.editor ) ); + + watchdog.on( 'restart', () => { + window.onerror = originalErrorHandler; + res(); + } ); + } ); } ) .then( () => { expect( watchdog.editor.getData() ).to.equal( '

foo

' ); @@ -155,10 +119,12 @@ describe( 'Watchdog', () => { describe( 'editor', () => { it( 'should be the current editor instance', () => { - const watchdog = new Watchdog(); + const watchdog = Watchdog.for( ClassicTestEditor ); - watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); + // sinon.stub( window, 'onerror' ).value( undefined ); and similar do not work. + const originalErrorHandler = window.onerror; + const windowErrorSpy = sinon.spy(); + window.onerror = windowErrorSpy; expect( watchdog.editor ).to.be.null; @@ -169,7 +135,14 @@ describe( 'Watchdog', () => { oldEditor = watchdog.editor; expect( watchdog.editor ).to.be.instanceOf( ClassicTestEditor ); - return watchdog.restart(); + return new Promise( res => { + setTimeout( () => throwCKEditorError( 'foo', watchdog.editor ) ); + + watchdog.on( 'restart', () => { + window.onerror = originalErrorHandler; + res(); + } ); + } ); } ) .then( () => { expect( watchdog.editor ).to.be.instanceOf( ClassicTestEditor );