8
0
فهرست منبع

Align feature class naming to a new scheme.

Maciej Gołaszewski 8 سال پیش
والد
کامیت
17bfa786fe

+ 7 - 53
packages/ckeditor5-undo/src/undo.js

@@ -8,14 +8,14 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import UndoEngine from './undoengine';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
-
-import undoIcon from '../theme/icons/undo.svg';
-import redoIcon from '../theme/icons/redo.svg';
+import UndoEditing from './undoediting';
+import UndoUI from './undoui';
 
 /**
- * The undo feature. It introduces the Undo and Redo buttons to the editor.
+ * The undo feature.
+ *
+ * It loads the {@link module:undo/undoediting~UndoEditing undo editing feature}
+ * and {@link module:undo/undoui~UndoUI undo UI feature}.
  *
  * Below is the explanation of the undo mechanism working together with {@link module:engine/model/history~History History}:
  *
@@ -106,7 +106,7 @@ export default class Undo extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ UndoEngine ];
+		return [ UndoEditing, UndoUI ];
 	}
 
 	/**
@@ -115,50 +115,4 @@ export default class Undo extends Plugin {
 	static get pluginName() {
 		return 'Undo';
 	}
-
-	/**
-	 * @inheritDoc
-	 */
-	init() {
-		const editor = this.editor;
-		const t = editor.t;
-
-		this._addButton( 'undo', t( 'Undo' ), 'CTRL+Z', undoIcon );
-		this._addButton( 'redo', t( 'Redo' ), 'CTRL+Y', redoIcon );
-
-		editor.keystrokes.set( 'CTRL+Z', 'undo' );
-		editor.keystrokes.set( 'CTRL+Y', 'redo' );
-		editor.keystrokes.set( 'CTRL+SHIFT+Z', 'redo' );
-	}
-
-	/**
-	 * Creates a button for the specified command.
-	 *
-	 * @private
-	 * @param {String} name Command name.
-	 * @param {String} label Button label.
-	 * @param {String} keystroke Command keystroke.
-	 * @param {String} Icon Source of the icon.
-	 */
-	_addButton( name, label, keystroke, Icon ) {
-		const editor = this.editor;
-		const command = editor.commands.get( name );
-
-		editor.ui.componentFactory.add( name, locale => {
-			const view = new ButtonView( locale );
-
-			view.set( {
-				label,
-				icon: Icon,
-				keystroke,
-				tooltip: true
-			} );
-
-			view.bind( 'isEnabled' ).to( command, 'isEnabled' );
-
-			this.listenTo( view, 'execute', () => editor.execute( name ) );
-
-			return view;
-		} );
-	}
 }

+ 15 - 9
packages/ckeditor5-undo/src/undoengine.js → packages/ckeditor5-undo/src/undoediting.js

@@ -4,7 +4,7 @@
  */
 
 /**
- * @module undo/undoengine
+ * @module undo/undoediting
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
@@ -19,7 +19,7 @@ import RedoCommand from './redocommand';
  *
  * @extends module:core/plugin~Plugin
  */
-export default class UndoEngine extends Plugin {
+export default class UndoEditing extends Plugin {
 	/**
 	 * @inheritDoc
 	 */
@@ -31,7 +31,7 @@ export default class UndoEngine extends Plugin {
 		 * Created and registered during the {@link #init feature initialization}.
 		 *
 		 * @private
-		 * @member {undo.UndoEngineCommand} #_undoCommand
+		 * @member {undo.UndoEditingCommand} #_undoCommand
 		 */
 
 		/**
@@ -39,7 +39,7 @@ export default class UndoEngine extends Plugin {
 		 * Created and registered during the {@link #init feature initialization}.
 		 *
 		 * @private
-		 * @member {undo.UndoEngineCommand} #_redoCommand
+		 * @member {undo.UndoEditingCommand} #_redoCommand
 		 */
 
 		/**
@@ -55,15 +55,17 @@ export default class UndoEngine extends Plugin {
 	 * @inheritDoc
 	 */
 	init() {
+		const editor = this.editor;
+
 		// Create commands.
-		this._undoCommand = new UndoCommand( this.editor );
-		this._redoCommand = new RedoCommand( this.editor );
+		this._undoCommand = new UndoCommand( editor );
+		this._redoCommand = new RedoCommand( editor );
 
 		// Register command to the editor.
-		this.editor.commands.add( 'undo', this._undoCommand );
-		this.editor.commands.add( 'redo', this._redoCommand );
+		editor.commands.add( 'undo', this._undoCommand );
+		editor.commands.add( 'redo', this._redoCommand );
 
-		this.listenTo( this.editor.model, 'applyOperation', ( evt, args ) => {
+		this.listenTo( editor.model, 'applyOperation', ( evt, args ) => {
 			const operation = args[ 0 ];
 			const batch = operation.delta.batch;
 
@@ -89,5 +91,9 @@ export default class UndoEngine extends Plugin {
 		this.listenTo( this._undoCommand, 'revert', ( evt, undoneBatch, undoingBatch ) => {
 			this._redoCommand.addBatch( undoingBatch );
 		} );
+
+		editor.keystrokes.set( 'CTRL+Z', 'undo' );
+		editor.keystrokes.set( 'CTRL+Y', 'redo' );
+		editor.keystrokes.set( 'CTRL+SHIFT+Z', 'redo' );
 	}
 }

+ 63 - 0
packages/ckeditor5-undo/src/undoui.js

@@ -0,0 +1,63 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module undo/undoui
+ */
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+
+import undoIcon from '../theme/icons/undo.svg';
+import redoIcon from '../theme/icons/redo.svg';
+
+/**
+ * The undo UI feature. It introduces the Undo and Redo buttons to the editor.
+ *
+ * @extends module:core/plugin~Plugin
+ */
+export default class UndoUI extends Plugin {
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		const editor = this.editor;
+		const t = editor.t;
+
+		this._addButton( 'undo', t( 'Undo' ), 'CTRL+Z', undoIcon );
+		this._addButton( 'redo', t( 'Redo' ), 'CTRL+Y', redoIcon );
+	}
+
+	/**
+	 * Creates a button for the specified command.
+	 *
+	 * @private
+	 * @param {String} name Command name.
+	 * @param {String} label Button label.
+	 * @param {String} keystroke Command keystroke.
+	 * @param {String} Icon Source of the icon.
+	 */
+	_addButton( name, label, keystroke, Icon ) {
+		const editor = this.editor;
+
+		editor.ui.componentFactory.add( name, locale => {
+			const command = editor.commands.get( name );
+			const view = new ButtonView( locale );
+
+			view.set( {
+				label,
+				icon: Icon,
+				keystroke,
+				tooltip: true
+			} );
+
+			view.bind( 'isEnabled' ).to( command, 'isEnabled' );
+
+			this.listenTo( view, 'execute', () => editor.execute( name ) );
+
+			return view;
+		} );
+	}
+}

+ 6 - 125
packages/ckeditor5-undo/tests/undo.js

@@ -3,135 +3,16 @@
  * For licensing, see LICENSE.md.
  */
 
-/* globals document */
-
-import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
 import Undo from '../src/undo';
-import UndoEngine from '../src/undoengine';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
-import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
-import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
-
-testUtils.createSinonSandbox();
+import UndoEditing from '../src/undoediting';
+import UndoUI from '../src/undoui';
 
 describe( 'Undo', () => {
-	let editor, editorElement;
-
-	beforeEach( () => {
-		editorElement = document.createElement( 'div' );
-		document.body.appendChild( editorElement );
-
-		return ClassicTestEditor.create( editorElement, { plugins: [ Undo ] } )
-			.then( newEditor => {
-				editor = newEditor;
-			} );
-	} );
-
-	afterEach( () => {
-		editorElement.remove();
-
-		return editor.destroy();
-	} );
-
-	it( 'should be loaded', () => {
-		expect( editor.plugins.get( Undo ) ).to.be.instanceOf( Undo );
-	} );
-
-	it( 'should load UndoEngine', () => {
-		expect( editor.plugins.get( UndoEngine ) ).to.be.instanceOf( UndoEngine );
-	} );
-
-	testButton( 'undo', 'Undo', 'CTRL+Z' );
-	testButton( 'redo', 'Redo', 'CTRL+Y' );
-
-	it( 'should set CTRL+Z keystroke', () => {
-		const spy = sinon.stub( editor, 'execute' );
-
-		const wasHandled = editor.keystrokes.press( {
-			keyCode: keyCodes.z,
-			ctrlKey: true,
-			preventDefault: sinon.spy(),
-			stopPropagation: sinon.spy()
-		} );
-
-		expect( wasHandled ).to.be.true;
-		expect( spy.calledWithExactly( 'undo' ) ).to.be.true;
-	} );
-
-	it( 'should set CTRL+Y keystroke', () => {
-		const spy = sinon.stub( editor, 'execute' );
-
-		const wasHandled = editor.keystrokes.press( {
-			keyCode: keyCodes.y,
-			ctrlKey: true,
-			preventDefault: sinon.spy(),
-			stopPropagation: sinon.spy()
-		} );
-
-		expect( wasHandled ).to.be.true;
-		expect( spy.calledWithExactly( 'redo' ) ).to.be.true;
+	it( 'should be named', () => {
+		expect( Undo.pluginName ).to.equal( 'Undo' );
 	} );
 
-	it( 'should set CTRL+SHIFT+Z keystroke', () => {
-		const spy = sinon.stub( editor, 'execute' );
-		const keyEventData = {
-			keyCode: keyCodes.z,
-			ctrlKey: true,
-			shiftKey: true,
-			preventDefault: sinon.spy(),
-			stopPropagation: sinon.spy()
-		};
-
-		const wasHandled = editor.keystrokes.press( keyEventData );
-
-		expect( wasHandled ).to.be.true;
-		expect( spy.calledWithExactly( 'redo' ) ).to.be.true;
-		expect( keyEventData.preventDefault.calledOnce ).to.be.true;
+	it( 'should require UndoEditing and UndoUI', () => {
+		expect( Undo.requires ).to.deep.equal( [ UndoEditing, UndoUI ] );
 	} );
-
-	function testButton( featureName, label, featureKeystroke ) {
-		describe( `${ featureName } button`, () => {
-			let button;
-
-			beforeEach( () => {
-				button = editor.ui.componentFactory.create( featureName );
-			} );
-
-			it( 'should register feature component', () => {
-				expect( button ).to.be.instanceOf( ButtonView );
-			} );
-
-			it( 'should create UI component with correct attribute values', () => {
-				expect( button.isOn ).to.be.false;
-				expect( button.label ).to.equal( label );
-				expect( button.icon ).to.match( /<svg / );
-				expect( button.keystroke ).to.equal( featureKeystroke );
-			} );
-
-			it( `should execute ${ featureName } command on model execute event`, () => {
-				const executeSpy = testUtils.sinon.stub( editor, 'execute' );
-
-				button.fire( 'execute' );
-
-				sinon.assert.calledOnce( executeSpy );
-				sinon.assert.calledWithExactly( executeSpy, featureName );
-			} );
-
-			it( `should bind model to ${ featureName } command`, () => {
-				const command = editor.commands.get( featureName );
-
-				expect( button.isOn ).to.be.false;
-
-				const initState = command.isEnabled;
-				expect( button.isEnabled ).to.equal( initState );
-
-				command.isEnabled = !initState;
-				expect( button.isEnabled ).to.equal( !initState );
-			} );
-
-			it( 'should set keystroke in the model', () => {
-				expect( button.keystroke ).to.equal( featureKeystroke );
-			} );
-		} );
-	}
 } );

+ 5 - 5
packages/ckeditor5-undo/tests/undoengine-integration.js → packages/ckeditor5-undo/tests/undoediting-integration.js

@@ -10,28 +10,28 @@ import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'
 import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 import Position from '@ckeditor/ckeditor5-engine/src/model/position';
 import Batch from '@ckeditor/ckeditor5-engine/src/model/batch';
-import UndoEngine from '../src/undoengine';
+import UndoEditing from '../src/undoediting';
 
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
-import HeadingEngine from '@ckeditor/ckeditor5-heading/src/headingengine';
+import HeadingEditing from '@ckeditor/ckeditor5-heading/src/headingediting';
 import Typing from '@ckeditor/ckeditor5-typing/src/typing';
 import Enter from '@ckeditor/ckeditor5-enter/src/enter';
 import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
-import BoldEngine from '@ckeditor/ckeditor5-basic-styles/src/boldengine';
+import BoldEditing from '@ckeditor/ckeditor5-basic-styles/src/bold/boldediting';
 
 import { downcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
 import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
 
 import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
-describe( 'UndoEngine integration', () => {
+describe( 'UndoEditing integration', () => {
 	let editor, model, doc, root, div;
 
 	beforeEach( () => {
 		div = document.createElement( 'div' );
 		document.body.appendChild( div );
 
-		return ClassicEditor.create( div, { plugins: [ Paragraph, HeadingEngine, Typing, Enter, Clipboard, BoldEngine, UndoEngine ] } )
+		return ClassicEditor.create( div, { plugins: [ Paragraph, HeadingEditing, Typing, Enter, Clipboard, BoldEditing, UndoEditing ] } )
 			.then( newEditor => {
 				editor = newEditor;
 

+ 129 - 0
packages/ckeditor5-undo/tests/undoediting.js

@@ -0,0 +1,129 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor';
+import Batch from '@ckeditor/ckeditor5-engine/src/model/batch';
+import UndoEditing from '../src/undoediting';
+import { keyCodes } from '../../ckeditor5-utils/src/keyboard';
+
+describe( 'UndoEditing', () => {
+	let editor, undo, model, root;
+
+	beforeEach( () => {
+		editor = new ModelTestEditor();
+
+		model = editor.model;
+		root = model.document.getRoot();
+
+		undo = new UndoEditing( editor );
+		undo.init();
+	} );
+
+	afterEach( () => {
+		undo.destroy();
+	} );
+
+	it( 'should register undo command and redo command', () => {
+		expect( editor.commands.get( 'undo' ) ).to.equal( undo._undoCommand );
+		expect( editor.commands.get( 'redo' ) ).to.equal( undo._redoCommand );
+	} );
+
+	it( 'should add a batch to undo command and clear redo stack, if it\'s type is "default"', () => {
+		sinon.spy( undo._undoCommand, 'addBatch' );
+		sinon.spy( undo._redoCommand, 'clearStack' );
+
+		expect( undo._undoCommand.addBatch.called ).to.be.false;
+		expect( undo._redoCommand.clearStack.called ).to.be.false;
+
+		model.change( writer => {
+			writer.insertText( 'foobar', root );
+		} );
+
+		expect( undo._undoCommand.addBatch.calledOnce ).to.be.true;
+		expect( undo._redoCommand.clearStack.calledOnce ).to.be.true;
+	} );
+
+	it( 'should add each batch only once', () => {
+		sinon.spy( undo._undoCommand, 'addBatch' );
+
+		model.change( writer => {
+			writer.insertText( 'foobar', root );
+			writer.insertText( 'foobar', root );
+		} );
+
+		expect( undo._undoCommand.addBatch.calledOnce ).to.be.true;
+	} );
+
+	it( 'should add a batch to undo command, if it\'s type is undo and it comes from redo command', () => {
+		sinon.spy( undo._undoCommand, 'addBatch' );
+		sinon.spy( undo._redoCommand, 'clearStack' );
+
+		const batch = new Batch();
+
+		undo._redoCommand._createdBatches.add( batch );
+
+		model.enqueueChange( batch, writer => {
+			writer.insertText( 'foobar', root );
+		} );
+
+		expect( undo._undoCommand.addBatch.calledOnce ).to.be.true;
+		expect( undo._redoCommand.clearStack.called ).to.be.false;
+	} );
+
+	it( 'should add a batch to redo command on undo revert event', () => {
+		sinon.spy( undo._redoCommand, 'addBatch' );
+		sinon.spy( undo._redoCommand, 'clearStack' );
+
+		undo._undoCommand.fire( 'revert', null, new Batch() );
+
+		expect( undo._redoCommand.addBatch.calledOnce ).to.be.true;
+		expect( undo._redoCommand.clearStack.called ).to.be.false;
+	} );
+
+	it( 'should set CTRL+Z keystroke', () => {
+		const spy = sinon.stub( editor, 'execute' );
+
+		const wasHandled = editor.keystrokes.press( {
+			keyCode: keyCodes.z,
+			ctrlKey: true,
+			preventDefault: sinon.spy(),
+			stopPropagation: sinon.spy()
+		} );
+
+		expect( wasHandled ).to.be.true;
+		expect( spy.calledWithExactly( 'undo' ) ).to.be.true;
+	} );
+
+	it( 'should set CTRL+Y keystroke', () => {
+		const spy = sinon.stub( editor, 'execute' );
+
+		const wasHandled = editor.keystrokes.press( {
+			keyCode: keyCodes.y,
+			ctrlKey: true,
+			preventDefault: sinon.spy(),
+			stopPropagation: sinon.spy()
+		} );
+
+		expect( wasHandled ).to.be.true;
+		expect( spy.calledWithExactly( 'redo' ) ).to.be.true;
+	} );
+
+	it( 'should set CTRL+SHIFT+Z keystroke', () => {
+		const spy = sinon.stub( editor, 'execute' );
+		const keyEventData = {
+			keyCode: keyCodes.z,
+			ctrlKey: true,
+			shiftKey: true,
+			preventDefault: sinon.spy(),
+			stopPropagation: sinon.spy()
+		};
+
+		const wasHandled = editor.keystrokes.press( keyEventData );
+
+		expect( wasHandled ).to.be.true;
+		expect( spy.calledWithExactly( 'redo' ) ).to.be.true;
+		expect( keyEventData.preventDefault.calledOnce ).to.be.true;
+	} );
+} );

+ 0 - 85
packages/ckeditor5-undo/tests/undoengine.js

@@ -1,85 +0,0 @@
-/**
- * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor';
-import Batch from '@ckeditor/ckeditor5-engine/src/model/batch';
-import UndoEngine from '../src/undoengine';
-
-describe( 'UndoEngine', () => {
-	let editor, undo, model, root;
-
-	beforeEach( () => {
-		editor = new ModelTestEditor();
-
-		model = editor.model;
-		root = model.document.getRoot();
-
-		undo = new UndoEngine( editor );
-		undo.init();
-	} );
-
-	afterEach( () => {
-		undo.destroy();
-	} );
-
-	describe( 'UndoEngine', () => {
-		it( 'should register undo command and redo command', () => {
-			expect( editor.commands.get( 'undo' ) ).to.equal( undo._undoCommand );
-			expect( editor.commands.get( 'redo' ) ).to.equal( undo._redoCommand );
-		} );
-
-		it( 'should add a batch to undo command and clear redo stack, if it\'s type is "default"', () => {
-			sinon.spy( undo._undoCommand, 'addBatch' );
-			sinon.spy( undo._redoCommand, 'clearStack' );
-
-			expect( undo._undoCommand.addBatch.called ).to.be.false;
-			expect( undo._redoCommand.clearStack.called ).to.be.false;
-
-			model.change( writer => {
-				writer.insertText( 'foobar', root );
-			} );
-
-			expect( undo._undoCommand.addBatch.calledOnce ).to.be.true;
-			expect( undo._redoCommand.clearStack.calledOnce ).to.be.true;
-		} );
-
-		it( 'should add each batch only once', () => {
-			sinon.spy( undo._undoCommand, 'addBatch' );
-
-			model.change( writer => {
-				writer.insertText( 'foobar', root );
-				writer.insertText( 'foobar', root );
-			} );
-
-			expect( undo._undoCommand.addBatch.calledOnce ).to.be.true;
-		} );
-
-		it( 'should add a batch to undo command, if it\'s type is undo and it comes from redo command', () => {
-			sinon.spy( undo._undoCommand, 'addBatch' );
-			sinon.spy( undo._redoCommand, 'clearStack' );
-
-			const batch = new Batch();
-
-			undo._redoCommand._createdBatches.add( batch );
-
-			model.enqueueChange( batch, writer => {
-				writer.insertText( 'foobar', root );
-			} );
-
-			expect( undo._undoCommand.addBatch.calledOnce ).to.be.true;
-			expect( undo._redoCommand.clearStack.called ).to.be.false;
-		} );
-
-		it( 'should add a batch to redo command on undo revert event', () => {
-			sinon.spy( undo._redoCommand, 'addBatch' );
-			sinon.spy( undo._redoCommand, 'clearStack' );
-
-			undo._undoCommand.fire( 'revert', null, new Batch() );
-
-			expect( undo._redoCommand.addBatch.calledOnce ).to.be.true;
-			expect( undo._redoCommand.clearStack.called ).to.be.false;
-		} );
-	} );
-} );

+ 83 - 0
packages/ckeditor5-undo/tests/undoui.js

@@ -0,0 +1,83 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* globals document */
+
+import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
+import UndoEditing from '../src/undoediting';
+import UndoUI from '../src/undoui';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+
+testUtils.createSinonSandbox();
+
+describe( 'UndoUI', () => {
+	let editor, editorElement;
+
+	beforeEach( () => {
+		editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+
+		return ClassicTestEditor.create( editorElement, { plugins: [ UndoEditing, UndoUI ] } )
+			.then( newEditor => {
+				editor = newEditor;
+			} );
+	} );
+
+	afterEach( () => {
+		editorElement.remove();
+
+		return editor.destroy();
+	} );
+
+	testButton( 'undo', 'Undo', 'CTRL+Z' );
+	testButton( 'redo', 'Redo', 'CTRL+Y' );
+
+	function testButton( featureName, label, featureKeystroke ) {
+		describe( `${ featureName } button`, () => {
+			let button;
+
+			beforeEach( () => {
+				button = editor.ui.componentFactory.create( featureName );
+			} );
+
+			it( 'should register feature component', () => {
+				expect( button ).to.be.instanceOf( ButtonView );
+			} );
+
+			it( 'should create UI component with correct attribute values', () => {
+				expect( button.isOn ).to.be.false;
+				expect( button.label ).to.equal( label );
+				expect( button.icon ).to.match( /<svg / );
+				expect( button.keystroke ).to.equal( featureKeystroke );
+			} );
+
+			it( `should execute ${ featureName } command on model execute event`, () => {
+				const executeSpy = testUtils.sinon.stub( editor, 'execute' );
+
+				button.fire( 'execute' );
+
+				sinon.assert.calledOnce( executeSpy );
+				sinon.assert.calledWithExactly( executeSpy, featureName );
+			} );
+
+			it( `should bind model to ${ featureName } command`, () => {
+				const command = editor.commands.get( featureName );
+
+				expect( button.isOn ).to.be.false;
+
+				const initState = command.isEnabled;
+				expect( button.isEnabled ).to.equal( initState );
+
+				command.isEnabled = !initState;
+				expect( button.isEnabled ).to.equal( !initState );
+			} );
+
+			it( 'should set keystroke in the model', () => {
+				expect( button.keystroke ).to.equal( featureKeystroke );
+			} );
+		} );
+	}
+} );