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

Make the Watchdog#restart() method private #14

Merged
merged 1 commit into from
Jul 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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