Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #14 from ckeditor/t/13
Browse files Browse the repository at this point in the history
Other: Made the `Watchdog#restart()` method private. Changed the signatures of `Watchdog#create()` and `Watchdog#destroy()`, so now these methods will return empty promises. Closes #13.

BREAKING CHANGE: `Watchdog#restart()` is no longer public.
  • Loading branch information
Reinmar authored Jul 22, 2019
2 parents e120e42 + aefb210 commit 69aef8b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 105 deletions.
70 changes: 33 additions & 37 deletions src/watchdog.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export default class Watchdog {
* @param {HTMLElement|String} elementOrData
* @param {module:core/editor/editorconfig~EditorConfig} [config]
*
* @returns {Promise.<module:watchdog/watchdog~Watchdog>}
* @returns {Promise}
*/
create( elementOrData, config ) {
if ( !this._creator ) {
Expand Down Expand Up @@ -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.<module:watchdog/watchdog~Watchdog>}
* @returns {Promise}
*/
destroy() {
window.removeEventListener( 'error', this._boundErrorHandler );
Expand All @@ -261,8 +230,6 @@ export default class Watchdog {
.then( () => this._destructor( this._editor ) )
.then( () => {
this._editor = null;

return this;
} );
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
*/
Expand Down
14 changes: 2 additions & 12 deletions tests/manual/watchdog.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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!' );
Expand All @@ -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!' );
Expand All @@ -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' );
} );
2 changes: 0 additions & 2 deletions tests/manual/watchdog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
81 changes: 27 additions & 54 deletions tests/watchdog.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: '<p>foo</p>',
plugins: [ Paragraph ]
} )
.then( () => {
expect( watchdog.editor.getData() ).to.equal( '<p>foo</p>' );

return watchdog.restart();
} )
.then( () => {
expect( watchdog.editor.getData() ).to.equal( '<p>foo</p>' );

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( '<p>foo</p>', { plugins: [ Paragraph ] } )
.then( () => {
expect( watchdog.editor.getData() ).to.equal( '<p>foo</p>' );

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( '<p>foo</p>' );
Expand All @@ -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;

Expand All @@ -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 );
Expand Down

0 comments on commit 69aef8b

Please sign in to comment.