diff --git a/docs/features/watchdog.md b/docs/features/watchdog.md index 4c51754..81b7255 100644 --- a/docs/features/watchdog.md +++ b/docs/features/watchdog.md @@ -54,7 +54,7 @@ In other words, your goal is to create a watchdog instance and make the watchdog ### Controlling editor creation and destruction -For more control over the creation and destruction of editor instances, you can use the {@link module:watchdog/watchdog~Watchdog#setCreator `Watchdog#setCreator()`} and {@link module:watchdog/watchdog~Watchdog#setDestructor `Watchdog#setDestructor()`} methods: +For more control over the creation and destruction of editor instances, you can use the {@link module:watchdog/watchdog~Watchdog#setCreator `Watchdog#setCreator()`} and, if needed, the {@link module:watchdog/watchdog~Watchdog#setDestructor `Watchdog#setDestructor()`} methods: ```js // Instantiate the watchdog manually (do not use the for() helper). @@ -81,6 +81,10 @@ watchdog.setDestructor( editor => { watchdog.create( elementOrData, editorConfig ); ``` + + The default (not overridden) editor destructor is the `editor => editor.destroy()` function. + + ### API Other useful {@link module:watchdog/watchdog~Watchdog methods, properties and events}: diff --git a/src/watchdog.js b/src/watchdog.js index 8959a9d..9a55c1c 100644 --- a/src/watchdog.js +++ b/src/watchdog.js @@ -135,6 +135,7 @@ export default class Watchdog { * @member {Function} #_destructor * @see #setDestructor */ + this._destructor = editor => editor.destroy(); /** * The latest saved editor data represented as a root name -> root data object. @@ -189,9 +190,18 @@ export default class Watchdog { /** * Sets the function that is responsible for the editor destruction. + * Overrides the default destruction function, which destroys only the editor instance. * It expects a function that should return a promise or `undefined`. * - * watchdog.setDestructor( editor => editor.destroy() ); + * watchdog.setDestructor( editor => { + * // Do something before the editor is destroyed. + * + * return editor + * .destroy() + * .then( () => { + * // Do something after the editor is destroyed. + * } ); + * } ); * * @param {Function} destructor */ @@ -223,20 +233,6 @@ export default class Watchdog { ); } - if ( !this._destructor ) { - /** - * The watchdog's editor destructor is not defined. Define it by using - * {@link module:watchdog/watchdog~Watchdog#setDestructor `Watchdog#setDestructor()`} or - * the {@link module:watchdog/watchdog~Watchdog.for `Watchdog.for()`} helper. - * - * @error watchdog-destructor-not-defined - */ - throw new CKEditorError( - 'watchdog-destructor-not-defined: The watchdog\'s editor destructor is not defined.', - null - ); - } - this._elementOrData = elementOrData; // Clone configuration because it might be shared within multiple watchdog instances. Otherwise, @@ -473,7 +469,6 @@ export default class Watchdog { const watchdog = new Watchdog( watchdogConfig ); watchdog.setCreator( ( elementOrData, config ) => Editor.create( elementOrData, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); return watchdog; } diff --git a/tests/watchdog.js b/tests/watchdog.js index 4200f0b..6c1e382 100644 --- a/tests/watchdog.js +++ b/tests/watchdog.js @@ -34,7 +34,6 @@ describe( 'Watchdog', () => { 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( () => { @@ -51,7 +50,6 @@ describe( 'Watchdog', () => { it( 'should throw an error when the creator is not defined', () => { const watchdog = new Watchdog(); - watchdog.setDestructor( editor => editor.destroy() ); expectToThrowCKEditorError( () => watchdog.create(), @@ -60,21 +58,16 @@ describe( 'Watchdog', () => { ); } ); - it( 'should throw an error when the destructor is not defined', () => { + it( 'should not throw an error when the destructor is not defined', () => { const watchdog = new Watchdog(); watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - expectToThrowCKEditorError( - () => watchdog.create(), - /^watchdog-destructor-not-defined/, - null - ); + expect( () => watchdog.create() ).to.not.throw(); } ); it( 'should properly copy the config', () => { const watchdog = new Watchdog(); watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); const config = { foo: [], @@ -91,7 +84,6 @@ describe( 'Watchdog', () => { 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; @@ -166,7 +158,6 @@ describe( 'Watchdog', () => { ClassicTestEditor.create( el ) .then( () => Promise.reject( new Error( 'foo' ) ) ) ); - watchdog.setDestructor( editor => editor.destroy() ); return watchdog.create( element ).then( () => { throw new Error( '`watchdog.create()` should throw an error.' ); }, @@ -199,7 +190,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -228,7 +218,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -251,7 +240,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); const editorErrorSpy = sinon.spy(); watchdog.on( 'error', editorErrorSpy ); @@ -322,7 +310,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -345,7 +332,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -378,7 +364,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); const errorSpy = sinon.spy(); watchdog.on( 'error', errorSpy ); @@ -415,7 +400,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog( { crashNumberLimit: 2, minimumNonErrorTimePeriod: 1000 } ); watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); const errorSpy = sinon.spy(); watchdog.on( 'error', errorSpy ); @@ -451,7 +435,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog( { crashNumberLimit: 2, minimumNonErrorTimePeriod: 0 } ); watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); - watchdog.setDestructor( editor => editor.destroy() ); const errorSpy = sinon.spy(); watchdog.on( 'error', errorSpy ); @@ -487,7 +470,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -519,7 +501,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -547,7 +528,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -575,7 +555,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -609,7 +588,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -648,7 +626,6 @@ describe( 'Watchdog', () => { const watchdog = new Watchdog(); 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; @@ -698,6 +675,35 @@ describe( 'Watchdog', () => { } ); } ); } ); + + it( 'should use the custom destructor if passed', () => { + const watchdog = new Watchdog(); + const destructionSpy = sinon.spy(); + + watchdog.setCreator( ( el, config ) => ClassicTestEditor.create( el, config ) ); + watchdog.setDestructor( editor => { + destructionSpy(); + return editor.destroy(); + } ); + + // sinon.stub( window, 'onerror' ).value( undefined ); and similar do not work. + const originalErrorHandler = window.onerror; + window.onerror = undefined; + + return watchdog.create( element ).then( () => { + setTimeout( () => throwCKEditorError( 'foo', watchdog.editor ) ); + + return new Promise( res => { + watchdog.on( 'restart', () => { + window.onerror = originalErrorHandler; + + sinon.assert.calledOnce( destructionSpy ); + + watchdog.destroy().then( res ); + } ); + } ); + } ); + } ); } ); describe( 'async error handling', () => {