Parcourir la source

Added tests to ImageAlternateText.

Szymon Kupś il y a 9 ans
Parent
commit
bf775c1652

+ 22 - 20
packages/ckeditor5-image/src/imagealternatetext/imagealternatetext.js

@@ -8,13 +8,11 @@
  */
 
 import Plugin from 'ckeditor5-core/src/plugin';
-import ImageAlternateTextCommand from './imagealternatetextcommand';
 import ButtonView from 'ckeditor5-ui/src/button/buttonview';
+import ImageAlternateTextEngine from './imagealternatetextengine';
 import clickOutsideHandler from 'ckeditor5-ui/src/bindings/clickoutsidehandler';
 import escPressHandler from 'ckeditor5-ui/src/bindings/escpresshandler';
-
 import ImageToolbar from '../imagetoolbar';
-
 import AlternateTextFormView from './ui/alternatetextformview';
 import ImageBalloonPanel from '../ui/imageballoonpanel';
 
@@ -30,15 +28,21 @@ export default class ImageAlternateText extends Plugin {
 	/**
 	 * @inheritDoc
 	 */
-	init() {
-		// TODO: Register ImageAlternateTextCommand in engine part.
-		this.editor.commands.set( 'imageAlternateText', new ImageAlternateTextCommand( this.editor ) );
+	static get requires() {
+		return [ ImageAlternateTextEngine ];
+	}
 
+	/**
+	 * @inheritDoc
+	 */
+	init() {
 		// TODO: docs for this._panel and this._form.
-		return Promise.all( [
-			this._createButton(),
-			this._createBalloonPanel()
-		] );
+		this._createButton();
+
+		return this._createBalloonPanel().then( panel => {
+			this.balloonPanel = panel;
+			this.form = panel.content.get( 0 );
+		} );
 	}
 
 	/**
@@ -52,7 +56,7 @@ export default class ImageAlternateText extends Plugin {
 		const command = editor.commands.get( 'imageAlternateText' );
 		const t = editor.t;
 
-		return editor.ui.componentFactory.add( 'imageAlternateText', ( locale ) => {
+		editor.ui.componentFactory.add( 'imageAlternateText', ( locale ) => {
 			const view = new ButtonView( locale );
 
 			view.set( {
@@ -72,7 +76,7 @@ export default class ImageAlternateText extends Plugin {
 		const editor = this.editor;
 
 		const panel = new ImageBalloonPanel( editor );
-		const form = this._form = new AlternateTextFormView( editor.locale );
+		const form = new AlternateTextFormView( editor.locale );
 
 		this.listenTo( form, 'submit', () => {
 			editor.execute( 'imageAlternateText', { newValue: form.labeledTextarea.inputView.element.value } );
@@ -96,12 +100,10 @@ export default class ImageAlternateText extends Plugin {
 			callback: () => this._hideBalloonPanel()
 		} );
 
-		this._panel = panel;
-
 		return Promise.all( [
-			panel.content.add( this._form ),
+			panel.content.add( form ),
 			editor.ui.view.body.add( panel )
-		] );
+		] ).then( () => panel ) ;
 	}
 
 	_showBalloonPanel() {
@@ -113,14 +115,14 @@ export default class ImageAlternateText extends Plugin {
 			imageToolbar.hide();
 		}
 
-		this._form.labeledTextarea.value = command.value || '';
-		this._form.labeledTextarea.select();
-		this._panel.attach();
+		this.form.labeledTextarea.value = command.value || '';
+		this.balloonPanel.attach();
+		this.form.labeledTextarea.select();
 	}
 
 	_hideBalloonPanel() {
 		const editor = this.editor;
-		this._panel.detach();
+		this.balloonPanel.detach();
 		editor.editing.view.focus();
 
 		const imageToolbar = editor.plugins.get( ImageToolbar );

+ 26 - 0
packages/ckeditor5-image/src/imagealternatetext/imagealternatetextengine.js

@@ -0,0 +1,26 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module image/imagealternatetext/engine
+ */
+
+import ImageAlternateTextCommand from './imagealternatetextcommand';
+import Plugin from 'ckeditor5-core/src/plugin';
+
+/**
+ * The image engine plugin.
+ * Registers `imageAlternateText` command.
+ *
+ * @extends module:core/plugin~Plugin
+ */
+export default class ImageEngine extends Plugin {
+	/**
+	 * @inheritDoc
+	 */
+	init() {
+		this.editor.commands.set( 'imageAlternateText', new ImageAlternateTextCommand( this.editor ) );
+	}
+}

+ 7 - 2
packages/ckeditor5-image/tests/image.js

@@ -9,6 +9,7 @@ import ClassicTestEditor from 'ckeditor5-core/tests/_utils/classictesteditor';
 import Image from 'ckeditor5-image/src/image';
 import ImageEngine from 'ckeditor5-image/src/imageengine';
 import Widget from 'ckeditor5-image/src/widget/widget';
+import ImageAlternateText from 'ckeditor5-image/src/imagealternatetext/imagealternatetext';
 
 describe( 'Image', () => {
 	let editor;
@@ -29,11 +30,15 @@ describe( 'Image', () => {
 		expect( editor.plugins.get( Image ) ).to.instanceOf( Image );
 	} );
 
-	it( 'should load ImageEngine feature', () => {
+	it( 'should load ImageEngine plugin', () => {
 		expect( editor.plugins.get( ImageEngine ) ).to.instanceOf( ImageEngine );
 	} );
 
-	it( 'should load Widget feature', () => {
+	it( 'should load Widget plugin', () => {
 		expect( editor.plugins.get( Widget ) ).to.instanceOf( Widget );
 	} );
+
+	it( 'should load ImageAlternateText plugin', () => {
+		expect( editor.plugins.get( ImageAlternateText ) ).to.instanceOf( ImageAlternateText );
+	} );
 } );

+ 191 - 0
packages/ckeditor5-image/tests/imagealternatetext/imagealternatetext.js

@@ -0,0 +1,191 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global Event */
+
+import ClassicTestEditor from 'ckeditor5-core/tests/_utils/classictesteditor';
+import Image from 'ckeditor5-image/src/image';
+import ImageToolbar from 'ckeditor5-image/src/imagetoolbar';
+import ImageAlternateText from 'ckeditor5-image/src/imagealternatetext/imagealternatetext';
+import ImageAlternateTextEngine from 'ckeditor5-image/src/imagealternatetext/imagealternatetextengine';
+import ButtonView from 'ckeditor5-ui/src/button/buttonview';
+import global from 'ckeditor5-utils/src/dom/global';
+import { setData } from 'ckeditor5-engine/src/dev-utils/model';
+import { keyCodes } from 'ckeditor5-utils/src/keyboard';
+
+describe( 'ImageAlternateText', () => {
+	let editor, plugin, command, balloonPanel, form;
+
+	beforeEach( () => {
+		const editorElement = global.document.createElement( 'div' );
+		global.document.body.appendChild( editorElement );
+
+		return ClassicTestEditor.create( editorElement, {
+			plugins: [ ImageAlternateText, Image ]
+		} )
+		.then( newEditor => {
+			editor = newEditor;
+			newEditor.editing.view.attachDomRoot( editorElement );
+			plugin = editor.plugins.get( ImageAlternateText );
+			command = editor.commands.get( 'imageAlternateText' );
+			balloonPanel = plugin.balloonPanel;
+			form = plugin.form;
+		} );
+	} );
+
+	afterEach( () => {
+		return editor.destroy();
+	} );
+
+	it( 'should be loaded', () => {
+		expect( plugin ).to.be.instanceOf( ImageAlternateText );
+	} );
+
+	it( 'should load ImageAlternateTextEngine plugin', () => {
+		expect( editor.plugins.get( ImageAlternateTextEngine ) ).to.be.instanceOf( ImageAlternateTextEngine );
+	} );
+
+	describe( 'toolbar button', () => {
+		let button;
+
+		beforeEach( () => {
+			button = editor.ui.componentFactory.create( 'imageAlternateText' );
+		} );
+
+		it( 'should be registered in component factory', () => {
+			expect( button ).to.be.instanceOf( ButtonView );
+		} );
+
+		it( 'should have isEnabled property bind to command\'s isEnabled property', () => {
+			command.isEnabled = true;
+			expect( button.isEnabled ).to.be.true;
+
+			command.isEnabled = false;
+			expect( button.isEnabled ).to.be.false;
+		} );
+
+		it( 'should show balloon panel on execute', () => {
+			const spy = sinon.spy( balloonPanel, 'attach' );
+			setData( editor.document, '[<image src="" alt="foo bar"></image>]' );
+			button.fire( 'execute' );
+
+			sinon.assert.calledOnce( spy );
+		} );
+
+		it( 'should hide ImageToolbar on execute', () => {
+			const editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+
+			return ClassicTestEditor.create( editorElement, {
+				plugins: [ ImageAlternateText, Image, ImageToolbar ],
+				image: {
+					toolbar: [ 'imageAlternateText' ]
+				}
+			} )
+			.then( newEditor => {
+				newEditor.editing.view.attachDomRoot( editorElement );
+				const button = newEditor.ui.componentFactory.create( 'imageAlternateText' );
+				const toolbarPlugin = newEditor.plugins.get( ImageToolbar );
+
+				const spy = sinon.spy( toolbarPlugin, 'hide' );
+				setData( newEditor.document, '[<image src="" alt="foo bar"></image>]' );
+				button.fire( 'execute' );
+
+				sinon.assert.calledOnce( spy );
+
+				newEditor.destroy();
+			} );
+		} );
+
+		it( 'should set alt attribute value to textarea and select it', () => {
+			const spy = sinon.spy( form.labeledTextarea, 'select' );
+			setData( editor.document, '[<image src="" alt="foo bar"></image>]' );
+			button.fire( 'execute' );
+
+			sinon.assert.calledOnce( spy );
+			expect( plugin.form.labeledTextarea.value ).equals( 'foo bar' );
+		} );
+
+		it( 'should set empty text to textarea and select it when there is no alt attribute', () => {
+			const spy = sinon.spy( form.labeledTextarea, 'select' );
+			setData( editor.document, '[<image src=""></image>]' );
+			button.fire( 'execute' );
+
+			sinon.assert.calledOnce( spy );
+			expect( plugin.form.labeledTextarea.value ).equals( '' );
+		} );
+	} );
+
+	describe( 'balloon panel form', () => {
+		it( 'should execute command on submit', () => {
+			const spy = sinon.spy( editor, 'execute' );
+			form.fire( 'submit' );
+
+			sinon.assert.calledOnce( spy );
+			sinon.assert.calledWithExactly( spy, 'imageAlternateText', { newValue: form.labeledTextarea.inputView.element.value } );
+		} );
+
+		it( 'should detach panel on cancel', () => {
+			const spy = sinon.spy( balloonPanel, 'detach' );
+			form.fire( 'cancel' );
+
+			sinon.assert.called( spy );
+		} );
+
+		it( 'should show ImageToolbar on cancel if present', () => {
+			const editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+
+			return ClassicTestEditor.create( editorElement, {
+				plugins: [ ImageAlternateText, Image, ImageToolbar ],
+				image: {
+					toolbar: [ 'imageAlternateText' ]
+				}
+			} )
+			.then( newEditor => {
+				newEditor.editing.view.attachDomRoot( editorElement );
+				const plugin = newEditor.plugins.get( ImageAlternateText );
+				const toolbarPlugin = newEditor.plugins.get( ImageToolbar );
+				const form = plugin.form;
+
+				const spy = sinon.spy( toolbarPlugin, 'show' );
+				form.fire( 'cancel' );
+
+				sinon.assert.called( spy );
+			} );
+		} );
+
+		describe( 'close listeners', () => {
+			let hidePanelSpy;
+
+			beforeEach( () => {
+				hidePanelSpy = sinon.spy( balloonPanel, 'detach' );
+			} );
+
+			describe( 'keyboard', () => {
+				it( 'should close after `ESC` press', () => {
+					balloonPanel.isVisible = true;
+					const keyCode = keyCodes.esc;
+					const event = global.document.createEvent( 'Events' );
+					event.initEvent( 'keydown', true, true );
+					event.which = keyCode;
+					event.keyCode = keyCode;
+					global.document.dispatchEvent( event );
+
+					sinon.assert.called( hidePanelSpy );
+				} );
+			} );
+
+			describe( 'mouse', () => {
+				it( 'should close on click outside the panel', () => {
+					balloonPanel.isVisible = true;
+					global.document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
+
+					sinon.assert.called( hidePanelSpy );
+				} );
+			} );
+		} );
+	} );
+} );