Browse Source

Test: Add table selection tests in table editing.

Maciej Gołaszewski 7 years ago
parent
commit
80fc88db08

+ 1 - 1
packages/ckeditor5-table/src/commands/removecolumncommand.js

@@ -12,7 +12,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
 import TableWalker from '../tablewalker';
 import TableUtils from '../tableutils';
 import { findAncestor, updateNumericAttribute } from './utils';
-import Range from '../../../ckeditor5-engine/src/model/range';
+import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 
 /**
  * The remove column command.

+ 10 - 2
packages/ckeditor5-table/tests/_utils/utils.js

@@ -250,20 +250,26 @@ function makeRows( tableData, options ) {
 				let contents = isObject ? tableCellData.contents : tableCellData;
 
 				let resultingCellElement = cellElement;
+				let isSelected = false;
 
 				if ( isObject ) {
 					if ( tableCellData.isHeading ) {
 						resultingCellElement = headingElement;
 					}
 
+					isSelected = !!tableCellData.isSelected;
+
 					delete tableCellData.contents;
 					delete tableCellData.isHeading;
+					delete tableCellData.isSelected;
 				}
 
 				const attributes = isObject ? tableCellData : {};
 
 				if ( asWidget ) {
-					attributes.class = 'ck-editor__editable ck-editor__nested-editable';
+					attributes.class = attributes.class ? ' ' + attributes.class : '';
+					attributes.class = 'ck-editor__editable ck-editor__nested-editable' + attributes.class;
+
 					attributes.contenteditable = 'true';
 				}
 
@@ -272,7 +278,9 @@ function makeRows( tableData, options ) {
 				}
 
 				const formattedAttributes = formatAttributes( attributes );
-				tableRowString += `<${ resultingCellElement }${ formattedAttributes }>${ contents }</${ resultingCellElement }>`;
+				const tableCell = `<${ resultingCellElement }${ formattedAttributes }>${ contents }</${ resultingCellElement }>`;
+
+				tableRowString += isSelected ? `[${ tableCell }]` : tableCell;
 
 				return tableRowString;
 			}, '' );

+ 1 - 1
packages/ckeditor5-table/tests/commands/mergecellscommand.js

@@ -10,7 +10,7 @@ import MergeCellsCommand from '../../src/commands/mergecellscommand';
 import { defaultConversion, defaultSchema, formatTable, formattedModelTable, modelTable } from '../_utils/utils';
 import TableUtils from '../../src/tableutils';
 import TableSelection from '../../src/tableselection';
-import Range from '../../../ckeditor5-engine/src/model/range';
+import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 
 describe( 'MergeCellsCommand', () => {
 	let editor, model, command, root;

+ 58 - 58
packages/ckeditor5-table/tests/converters/downcast.js

@@ -34,7 +34,7 @@ function paragraphInTableCell() {
 }
 
 describe( 'downcast converters', () => {
-	let editor, model, doc, root, viewDocument;
+	let editor, model, doc, root, view;
 
 	testUtils.createSinonSandbox();
 
@@ -48,7 +48,7 @@ describe( 'downcast converters', () => {
 				model = editor.model;
 				doc = model.document;
 				root = doc.getRoot( 'main' );
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
 
 				defaultSchema( model.schema );
 				defaultConversion( editor.conversion );
@@ -59,7 +59,7 @@ describe( 'downcast converters', () => {
 		it( 'should create table with tbody', () => {
 			setModelData( model, modelTable( [ [ '' ] ] ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table">' +
 					'<table>' +
 						'<tbody>' +
@@ -76,7 +76,7 @@ describe( 'downcast converters', () => {
 				[ '10' ]
 			], { headingRows: 1 } ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table">' +
 					'<table>' +
 						'<thead>' +
@@ -96,7 +96,7 @@ describe( 'downcast converters', () => {
 				[ '10' ]
 			], { headingRows: 2 } ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table">' +
 					'<table>' +
 						'<thead>' +
@@ -114,7 +114,7 @@ describe( 'downcast converters', () => {
 				[ '10', '11', '12', '13' ]
 			], { headingColumns: 3, headingRows: 1 } ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table">' +
 					'<table>' +
 						'<thead>' +
@@ -133,7 +133,7 @@ describe( 'downcast converters', () => {
 				[ '<paragraph>00</paragraph><paragraph>foo</paragraph>', '01' ]
 			] ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table">' +
 					'<table>' +
 						'<tbody>' +
@@ -164,7 +164,7 @@ describe( 'downcast converters', () => {
 
 			setModelData( model, modelTable( [ [ '' ] ] ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<table foo="bar">' +
 					'<tr><td><p></p></td></tr>' +
 				'</table>'
@@ -178,7 +178,7 @@ describe( 'downcast converters', () => {
 					[ '10', '11', '12' ]
 				], { headingColumns: 2 } ) );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="table">' +
 						'<table>' +
 							'<tbody>' +
@@ -196,7 +196,7 @@ describe( 'downcast converters', () => {
 					[ { colspan: 2, contents: '10' }, '12', '13' ]
 				], { headingColumns: 3 } ) );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="table">' +
 						'<table>' +
 							'<tbody>' +
@@ -230,7 +230,7 @@ describe( 'downcast converters', () => {
 					[ '32', '33' ]
 				], { headingColumns: 3 } ) );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="table">' +
 						'<table>' +
 							'<tbody>' +
@@ -253,7 +253,7 @@ describe( 'downcast converters', () => {
 						model = editor.model;
 						doc = model.document;
 						root = doc.getRoot( 'main' );
-						viewDocument = editor.editing.view;
+						view = editor.editing.view;
 
 						defaultSchema( model.schema );
 						defaultConversion( editor.conversion, true );
@@ -263,7 +263,7 @@ describe( 'downcast converters', () => {
 			it( 'should create table as a widget', () => {
 				setModelData( model, modelTable( [ [ '' ] ] ) );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="ck-widget ck-widget_selectable table" contenteditable="false">' +
 					'<div class="ck ck-widget__selection-handler"></div>' +
 						'<table>' +
@@ -296,7 +296,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ]
 			] ) );
@@ -318,7 +318,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ]
 			] ) );
@@ -332,7 +332,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ],
 				[ '', '' ]
@@ -357,7 +357,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ],
 				[ '21', '22' ],
@@ -383,7 +383,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ],
 				[ '21', '22' ],
@@ -409,7 +409,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ],
 				[ '21', '22' ],
@@ -432,7 +432,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { rowspan: 3, contents: '00' }, '01' ],
 				[ '22' ],
 				[ '' ]
@@ -460,7 +460,7 @@ describe( 'downcast converters', () => {
 				writer.insert( writer.createElement( 'tableCell' ), secondRow, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { rowspan: 3, contents: '00', isHeading: true }, '01' ],
 				[ '22' ],
 				[ '' ],
@@ -476,7 +476,7 @@ describe( 'downcast converters', () => {
 						model = editor.model;
 						doc = model.document;
 						root = doc.getRoot( 'main' );
-						viewDocument = editor.editing.view;
+						view = editor.editing.view;
 
 						defaultSchema( model.schema );
 						defaultConversion( editor.conversion, true );
@@ -496,7 +496,7 @@ describe( 'downcast converters', () => {
 				} );
 
 				expect( formatTable(
-					getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+					getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="ck-widget ck-widget_selectable table" contenteditable="false">' +
 						'<div class="ck ck-widget__selection-handler"></div>' +
 						'<table>' +
@@ -531,7 +531,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 1 );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '', '01' ]
 			] ) );
 		} );
@@ -549,7 +549,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', row, 1 );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { colspan: 2, contents: '00' }, '', '13' ]
 			] ) );
 		} );
@@ -567,7 +567,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', table.getChild( 1 ), 0 );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { rowspan: 2, contents: '00' }, '', '13' ],
 				[ '', '11', '12' ]
 			] ) );
@@ -589,7 +589,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'colspan', 2, secondRow.getChild( 0 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '', '01' ],
 				[ { colspan: 2, contents: '10' }, '11' ]
 			] ) );
@@ -610,7 +610,7 @@ describe( 'downcast converters', () => {
 				writer.remove( firstRow.getChild( 1 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { colspan: 2, contents: '00' } ],
 				[ '10', '11' ]
 			] ) );
@@ -624,7 +624,7 @@ describe( 'downcast converters', () => {
 						model = editor.model;
 						doc = model.document;
 						root = doc.getRoot( 'main' );
-						viewDocument = editor.editing.view;
+						view = editor.editing.view;
 
 						defaultSchema( model.schema );
 						defaultConversion( editor.conversion, true );
@@ -642,7 +642,7 @@ describe( 'downcast converters', () => {
 					writer.insert( writer.createElement( 'tableCell' ), row, 'end' );
 				} );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="ck-widget ck-widget_selectable table" contenteditable="false">' +
 					'<div class="ck ck-widget__selection-handler"></div>' +
 						'<table>' +
@@ -674,7 +674,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingColumns', 1, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { isHeading: true, contents: '00' }, '01' ],
 				[ { isHeading: true, contents: '10' }, '11' ]
 			], { headingColumns: 1 } ) );
@@ -692,7 +692,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingColumns', 3, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { isHeading: true, contents: '00' }, { isHeading: true, contents: '01' }, { isHeading: true, contents: '02' }, '03' ],
 				[ { isHeading: true, contents: '10' }, { isHeading: true, contents: '11' }, { isHeading: true, contents: '12' }, '13' ]
 			] ) );
@@ -710,7 +710,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingColumns', 1, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ { isHeading: true, contents: '00' }, '01', '02', '03' ],
 				[ { isHeading: true, contents: '10' }, '11', '12', '13' ]
 			], { headingColumns: 3 } ) );
@@ -727,7 +727,7 @@ describe( 'downcast converters', () => {
 				writer.removeAttribute( 'headingColumns', table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '10', '11' ]
 			] ) );
@@ -743,7 +743,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingColumns', 1, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table" headingColumns="1">' +
 					'<table>' +
 						'<tbody>' +
@@ -772,7 +772,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', table.getChild( 2 ), 1 );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[
 					{ isHeading: true, rowspan: 2, contents: '00' },
 					{ isHeading: true, contents: '01' },
@@ -803,7 +803,7 @@ describe( 'downcast converters', () => {
 						model = editor.model;
 						doc = model.document;
 						root = doc.getRoot( 'main' );
-						viewDocument = editor.editing.view;
+						view = editor.editing.view;
 
 						defaultSchema( model.schema );
 						defaultConversion( editor.conversion, true );
@@ -819,7 +819,7 @@ describe( 'downcast converters', () => {
 					writer.setAttribute( 'headingRows', 1, table );
 				} );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="ck-widget ck-widget_selectable table" contenteditable="false">' +
 					'<div class="ck ck-widget__selection-handler"></div>' +
 						'<table>' +
@@ -851,7 +851,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingRows', 2, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '10', '11' ],
 				[ '20', '21' ]
@@ -871,7 +871,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingRows', 2, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '10', '11' ],
 				[ '20', '21' ]
@@ -892,7 +892,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingRows', 2, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '10', '11' ],
 				[ '20', '21' ],
@@ -912,7 +912,7 @@ describe( 'downcast converters', () => {
 				writer.removeAttribute( 'headingRows', table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '10', '11' ]
 			] ) );
@@ -930,7 +930,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingRows', 2, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '10', '11' ]
 			], { headingRows: 2 } ) );
@@ -946,7 +946,7 @@ describe( 'downcast converters', () => {
 				writer.setAttribute( 'headingRows', 1, table );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 				'<figure class="table" headingRows="1">' +
 					'<table>' +
 						'<tbody>' +
@@ -975,7 +975,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', tableRow, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '', '' ],
 				[ '00', '01' ],
 				[ '10', '11' ]
@@ -1001,7 +1001,7 @@ describe( 'downcast converters', () => {
 				writer.insertElement( 'tableCell', tableRow, 'end' );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ],
 				[ '', '' ],
 				[ '10', '11' ],
@@ -1017,7 +1017,7 @@ describe( 'downcast converters', () => {
 						model = editor.model;
 						doc = model.document;
 						root = doc.getRoot( 'main' );
-						viewDocument = editor.editing.view;
+						view = editor.editing.view;
 
 						defaultSchema( model.schema );
 						defaultConversion( editor.conversion, true );
@@ -1033,7 +1033,7 @@ describe( 'downcast converters', () => {
 					writer.setAttribute( 'headingColumns', 1, table );
 				} );
 
-				expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
+				expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formatTable(
 					'<figure class="ck-widget ck-widget_selectable table" contenteditable="false">' +
 					'<div class="ck ck-widget__selection-handler"></div>' +
 						'<table>' +
@@ -1064,7 +1064,7 @@ describe( 'downcast converters', () => {
 				writer.remove( table.getChild( 1 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ]
 			] ) );
 		} );
@@ -1081,7 +1081,7 @@ describe( 'downcast converters', () => {
 				writer.remove( table.getChild( 0 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '10', '11' ]
 			] ) );
 		} );
@@ -1098,7 +1098,7 @@ describe( 'downcast converters', () => {
 				writer.remove( table.getChild( 1 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ]
 			], { headingRows: 2 } ) );
 		} );
@@ -1115,7 +1115,7 @@ describe( 'downcast converters', () => {
 				writer.remove( table.getChild( 0 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '10', '11' ]
 			], { headingRows: 2 } ) );
 		} );
@@ -1133,7 +1133,7 @@ describe( 'downcast converters', () => {
 				writer.remove( table.getChild( 0 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '10', '11' ]
 			] ) );
 		} );
@@ -1150,7 +1150,7 @@ describe( 'downcast converters', () => {
 				writer.remove( table.getChild( 1 ) );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00', '01' ]
 			], { headingRows: 1 } ) );
 		} );
@@ -1164,7 +1164,7 @@ describe( 'downcast converters', () => {
 					model = editor.model;
 					doc = model.document;
 					root = doc.getRoot( 'main' );
-					viewDocument = editor.editing.view;
+					view = editor.editing.view;
 
 					defaultSchema( model.schema );
 					defaultConversion( editor.conversion, true );
@@ -1178,7 +1178,7 @@ describe( 'downcast converters', () => {
 				[ '00[]' ]
 			] ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '00' ]
 			], { asWidget: true } ) );
 
@@ -1194,7 +1194,7 @@ describe( 'downcast converters', () => {
 				writer.setSelection( nodeByPath.nextSibling, 0 );
 			} );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '<p>00</p><p></p>' ]
 			], { asWidget: true } ) );
 		} );
@@ -1207,7 +1207,7 @@ describe( 'downcast converters', () => {
 				[ '<paragraph foo="bar">00[]</paragraph>' ]
 			] ) );
 
-			expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 				[ '<p foo="bar">00</p>' ]
 			], { asWidget: true } ) );
 		} );

+ 325 - 15
packages/ckeditor5-table/tests/tableediting.js

@@ -6,11 +6,12 @@
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
 import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
 import ImageEditing from '@ckeditor/ckeditor5-image/src/image/imageediting';
 
 import TableEditing from '../src/tableediting';
-import { formatTable, formattedModelTable, modelTable } from './_utils/utils';
+import { formatTable, formattedModelTable, formattedViewTable, modelTable } from './_utils/utils';
 import InsertRowCommand from '../src/commands/insertrowcommand';
 import InsertTableCommand from '../src/commands/inserttablecommand';
 import InsertColumnCommand from '../src/commands/insertcolumncommand';
@@ -21,6 +22,7 @@ import MergeCellsCommand from '../src/commands/mergecellscommand';
 import SetHeaderRowCommand from '../src/commands/setheaderrowcommand';
 import SetHeaderColumnCommand from '../src/commands/setheadercolumncommand';
 import TableSelection from '../src/tableselection';
+import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 
 describe( 'TableEditing', () => {
 	let editor, model;
@@ -132,11 +134,11 @@ describe( 'TableEditing', () => {
 
 				expect( editor.getData() ).to.equal(
 					'<figure class="table">' +
-						'<table>' +
-							'<tbody>' +
-								'<tr><td>foo</td></tr>' +
-							'</tbody>' +
-						'</table>' +
+					'<table>' +
+					'<tbody>' +
+					'<tr><td>foo</td></tr>' +
+					'</tbody>' +
+					'</table>' +
 					'</figure>'
 				);
 			} );
@@ -149,11 +151,11 @@ describe( 'TableEditing', () => {
 
 				expect( editor.getData() ).to.equal(
 					'<figure class="table">' +
-						'<table>' +
-							'<thead>' +
-								'<tr><th>foo</th></tr>' +
-							'</thead>' +
-						'</table>' +
+					'<table>' +
+					'<thead>' +
+					'<tr><th>foo</th></tr>' +
+					'</thead>' +
+					'</table>' +
 					'</figure>'
 				);
 			} );
@@ -274,7 +276,7 @@ describe( 'TableEditing', () => {
 
 			it( 'should move to the next table cell if part of block content is selected', () => {
 				setModelData( model, modelTable( [
-					[ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ],
+					[ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ]
 				] ) );
 
 				editor.editing.view.document.fire( 'keydown', domEvtDataStub );
@@ -284,7 +286,7 @@ describe( 'TableEditing', () => {
 						'11',
 						'<paragraph>12</paragraph><paragraph>foo</paragraph><paragraph>bar</paragraph>',
 						'[13]'
-					],
+					]
 				] ) );
 			} );
 
@@ -423,7 +425,7 @@ describe( 'TableEditing', () => {
 
 			it( 'should move to the previous table cell if part of block content is selected', () => {
 				setModelData( model, modelTable( [
-					[ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ],
+					[ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ]
 				] ) );
 
 				editor.editing.view.document.fire( 'keydown', domEvtDataStub );
@@ -433,7 +435,7 @@ describe( 'TableEditing', () => {
 						'[11]',
 						'<paragraph>12</paragraph><paragraph>foo</paragraph><paragraph>bar</paragraph>',
 						'13'
-					],
+					]
 				] ) );
 			} );
 		} );
@@ -512,4 +514,312 @@ describe( 'TableEditing', () => {
 			] ) );
 		} );
 	} );
+
+	describe.only( 'table selection', () => {
+		let view, domEvtDataStub;
+
+		beforeEach( () => {
+			view = editor.editing.view;
+
+			domEvtDataStub = {
+				domEvent: {
+					buttons: 1
+				},
+				target: undefined,
+				preventDefault: sinon.spy(),
+				stopPropagation: sinon.spy()
+			};
+		} );
+
+		it( 'should not start table selection when mouse move is inside one table cell', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+		} );
+
+		it( 'should start table selection when mouse move expands over two cells', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ '10', '11' ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
+				[ '10', '11' ]
+			], { asWidget: true } ) );
+		} );
+
+		it( 'should select rectangular table cells when mouse moved to diagonal cell (up -> down)', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ { contents: '10', isSelected: true }, { contents: '11', isSelected: true } ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
+				[ { contents: '10', class: 'selected', isSelected: true }, { contents: '11', class: 'selected', isSelected: true } ]
+			], { asWidget: true } ) );
+		} );
+
+		it( 'should select rectangular table cells when mouse moved to diagonal cell (down -> up)', () => {
+			setModelData( model, modelTable( [
+				[ '00', '01' ],
+				[ '10', '[]11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '00', '01' ],
+				[ '10', '[]11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ { contents: '10', isSelected: true }, { contents: '11', isSelected: true } ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
+				[ { contents: '10', class: 'selected', isSelected: true }, { contents: '11', class: 'selected', isSelected: true } ]
+			], { asWidget: true } ) );
+		} );
+
+		it( 'should update view selection after changing selection rect', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01', '02' ],
+				[ '10', '11', '12' ],
+				[ '20', '21', '22' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 2, 2 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true }, { contents: '02', isSelected: true } ],
+				[ { contents: '10', isSelected: true }, { contents: '11', isSelected: true }, { contents: '12', isSelected: true } ],
+				[ { contents: '20', isSelected: true }, { contents: '21', isSelected: true }, { contents: '22', isSelected: true } ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[
+					{ contents: '00', class: 'selected', isSelected: true },
+					{ contents: '01', class: 'selected', isSelected: true },
+					{ contents: '02', class: 'selected', isSelected: true }
+				],
+				[
+					{ contents: '10', class: 'selected', isSelected: true },
+					{ contents: '11', class: 'selected', isSelected: true },
+					{ contents: '12', class: 'selected', isSelected: true }
+				],
+				[
+					{ contents: '20', class: 'selected', isSelected: true },
+					{ contents: '21', class: 'selected', isSelected: true },
+					{ contents: '22', class: 'selected', isSelected: true }
+				]
+			], { asWidget: true } ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true }, '02' ],
+				[ { contents: '10', isSelected: true }, { contents: '11', isSelected: true }, '12' ],
+				[ '20', '21', '22' ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[
+					{ contents: '00', class: 'selected', isSelected: true },
+					{ contents: '01', class: 'selected', isSelected: true },
+					'02'
+				],
+				[
+					{ contents: '10', class: 'selected', isSelected: true },
+					{ contents: '11', class: 'selected', isSelected: true },
+					'12'
+				],
+				[
+					'20',
+					'21',
+					'22'
+				]
+			], { asWidget: true } ) );
+		} );
+
+		it( 'should stop selecting after "mouseup" event', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			view.document.fire( 'mouseup', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ '10', '11' ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
+				[ '10', '11' ]
+			], { asWidget: true } ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ '10', '11' ]
+			] ) );
+		} );
+
+		it( 'should stop selection mode on "mouseleve" event', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			view.document.fire( 'mouseleave', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ '10', '11' ]
+			] ) );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[ { contents: '00', class: 'selected', isSelected: true }, { contents: '01', class: 'selected', isSelected: true } ],
+				[ '10', '11' ]
+			], { asWidget: true } ) );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 1, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ { contents: '00', isSelected: true }, { contents: '01', isSelected: true } ],
+				[ '10', '11' ]
+			] ) );
+		} );
+
+		it( 'should clear view table selection after mouse click outside table', () => {
+			setModelData( model, modelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) + '<paragraph>foo</paragraph>' );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 0 );
+			view.document.fire( 'mousedown', domEvtDataStub );
+
+			expect( formatTable( getModelData( model ) ) ).to.equal( formattedModelTable( [
+				[ '[]00', '01' ],
+				[ '10', '11' ]
+			] ) + '<paragraph>foo</paragraph>' );
+
+			selectTableCell( domEvtDataStub, view, 0, 0, 0, 1 );
+			view.document.fire( 'mousemove', domEvtDataStub );
+
+			domEvtDataStub.target = view.document.getRoot().getChild( 1 );
+
+			view.document.fire( 'mousemove', domEvtDataStub );
+			view.document.fire( 'mousedown', domEvtDataStub );
+			view.document.fire( 'mouseup', domEvtDataStub );
+
+			// The click in the DOM would trigger selection change and it will set the selection:
+			model.change( writer => {
+				writer.setSelection( Range.createCollapsedAt( model.document.getRoot().getChild( 1 ) ) );
+			} );
+
+			expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+				[ '00', '01' ],
+				[ '10', '11' ]
+			], { asWidget: true } ) + '<p>{}foo</p>' );
+		} );
+	} );
 } );
+
+function selectTableCell( domEvtDataStub, view, tableIndex, sectionIndex, rowInSectionIndex, tableCellIndex ) {
+	domEvtDataStub.target = view.document.getRoot()
+		.getChild( tableIndex )
+		.getChild( 1 ) // Table is second in widget
+		.getChild( sectionIndex )
+		.getChild( rowInSectionIndex )
+		.getChild( tableCellIndex );
+}

+ 0 - 277
packages/ckeditor5-table/tests/tableselection.js

@@ -1,277 +0,0 @@
-/**
- * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
-import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
-
-import { defaultConversion, defaultSchema, formatTable, modelTable } from './_utils/utils';
-
-import TableSelection from '../src/tableselection';
-import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
-
-describe( 'TableSelection', () => {
-	let editor, model, root, tableSelection;
-
-	beforeEach( () => {
-		return VirtualTestEditor.create( {
-			plugins: [ TableSelection ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-			root = model.document.getRoot( 'main' );
-			tableSelection = editor.plugins.get( TableSelection );
-
-			defaultSchema( model.schema );
-			defaultConversion( editor.conversion );
-		} );
-	} );
-
-	afterEach( () => {
-		return editor.destroy();
-	} );
-
-	describe( '#pluginName', () => {
-		it( 'should provide plugin name', () => {
-			expect( TableSelection.pluginName ).to.equal( 'TableSelection' );
-		} );
-	} );
-
-	describe( 'start()', () => {
-		it( 'should start selection', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01' ],
-				[ '10', '11' ]
-			] ) );
-
-			const nodeByPath = root.getNodeByPath( [ 0, 0, 0 ] );
-
-			tableSelection.startSelection( nodeByPath );
-
-			expect( tableSelection.isSelecting ).to.be.true;
-		} );
-
-		it( 'update selection to single table cell', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01' ],
-				[ '10', '11' ]
-			] ) );
-
-			const nodeByPath = root.getNodeByPath( [ 0, 0, 0 ] );
-
-			tableSelection.startSelection( nodeByPath );
-
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ nodeByPath ] );
-		} );
-	} );
-
-	describe( 'stop()', () => {
-		it( 'should stop selection', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01' ],
-				[ '10', '11' ]
-			] ) );
-
-			const nodeByPath = root.getNodeByPath( [ 0, 0, 0 ] );
-
-			tableSelection.startSelection( nodeByPath );
-			expect( tableSelection.isSelecting ).to.be.true;
-
-			tableSelection.stopSelection( nodeByPath );
-
-			expect( tableSelection.isSelecting ).to.be.false;
-		} );
-
-		it( 'update selection to passed table cell', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01' ],
-				[ '10', '11' ]
-			] ) );
-
-			const startNode = root.getNodeByPath( [ 0, 0, 0 ] );
-			const endNode = root.getNodeByPath( [ 0, 1, 1 ] );
-
-			tableSelection.startSelection( startNode );
-			tableSelection.stopSelection( endNode );
-
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [
-				startNode,
-				root.getNodeByPath( [ 0, 0, 1 ] ),
-				root.getNodeByPath( [ 0, 1, 0 ] ),
-				endNode
-			] );
-		} );
-
-		it( 'should not update selection if alredy stopped', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01', '02' ],
-				[ '10', '11', '12' ]
-			] ) );
-
-			const startNode = root.getNodeByPath( [ 0, 0, 0 ] );
-			const firstEndNode = root.getNodeByPath( [ 0, 0, 1 ] );
-
-			tableSelection.startSelection( startNode );
-			tableSelection.stopSelection( firstEndNode );
-
-			expect( tableSelection.isSelecting ).to.be.false;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ startNode, firstEndNode ] );
-
-			const secondEndNode = root.getNodeByPath( [ 0, 0, 2 ] );
-			tableSelection.stopSelection( secondEndNode );
-
-			expect( tableSelection.isSelecting ).to.be.false;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ startNode, firstEndNode ] );
-		} );
-
-		it( 'should not update selection if table cell is from another parent', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01' ]
-			] ) + modelTable( [
-				[ 'aa', 'bb' ]
-			] ) );
-
-			tableSelection.startSelection( root.getNodeByPath( [ 0, 0, 0 ] ) );
-			tableSelection.stopSelection( root.getNodeByPath( [ 1, 0, 1 ] ) );
-
-			expect( tableSelection.isSelecting ).to.be.false;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ root.getNodeByPath( [ 0, 0, 0 ] ) ] );
-		} );
-	} );
-
-	describe( 'update()', () => {
-		it( 'should update selection', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01', '02' ],
-				[ '10', '11', '12' ]
-			] ) );
-
-			const startNode = root.getNodeByPath( [ 0, 0, 0 ] );
-			const firstEndNode = root.getNodeByPath( [ 0, 0, 1 ] );
-
-			tableSelection.startSelection( startNode );
-			tableSelection.updateSelection( firstEndNode );
-
-			expect( tableSelection.isSelecting ).to.be.true;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ startNode, firstEndNode ] );
-
-			const secondEndNode = root.getNodeByPath( [ 0, 0, 2 ] );
-			tableSelection.updateSelection( secondEndNode );
-
-			expect( tableSelection.isSelecting ).to.be.true;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ startNode, firstEndNode, secondEndNode ] );
-		} );
-
-		it( 'should not update selection if stopped', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01', '02' ],
-				[ '10', '11', '12' ]
-			] ) );
-
-			const startNode = root.getNodeByPath( [ 0, 0, 0 ] );
-			const firstEndNode = root.getNodeByPath( [ 0, 0, 1 ] );
-
-			tableSelection.startSelection( startNode );
-			tableSelection.updateSelection( firstEndNode );
-
-			expect( tableSelection.isSelecting ).to.be.true;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ startNode, firstEndNode ] );
-
-			tableSelection.stopSelection( firstEndNode );
-			expect( tableSelection.isSelecting ).to.be.false;
-
-			const secondEndNode = root.getNodeByPath( [ 0, 0, 2 ] );
-			tableSelection.updateSelection( secondEndNode );
-
-			expect( tableSelection.isSelecting ).to.be.false;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ startNode, firstEndNode ] );
-		} );
-
-		it( 'should not update selection if table cell is from another parent', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01' ]
-			] ) + modelTable( [
-				[ 'aa', 'bb' ]
-			] ) );
-
-			tableSelection.startSelection( root.getNodeByPath( [ 0, 0, 0 ] ) );
-			tableSelection.updateSelection( root.getNodeByPath( [ 1, 0, 1 ] ) );
-
-			expect( tableSelection.isSelecting ).to.be.true;
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [ root.getNodeByPath( [ 0, 0, 0 ] ) ] );
-		} );
-
-		it( 'should update view selection', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01', '02' ],
-				[ '10', '11', '12' ]
-			] ) );
-
-			const startNode = root.getNodeByPath( [ 0, 0, 0 ] );
-			const firstEndNode = root.getNodeByPath( [ 0, 0, 1 ] );
-
-			tableSelection.startSelection( startNode );
-			tableSelection.updateSelection( firstEndNode );
-
-			expect( formatTable( getViewData( editor.editing.view ) ) ).to.equal( formatTable(
-				'<figure class="table">' +
-					'<table>' +
-						'<tbody>' +
-							'<tr>' +
-								'[<td class="selected">00</td>][<td class="selected">01</td>]<td>02</td>' +
-							'</tr>' +
-							'<tr>' +
-								'<td>10</td><td>11</td><td>12</td>' +
-							'</tr>' +
-						'</tbody>' +
-					'</table>' +
-				'</figure>'
-			) );
-		} );
-	} );
-
-	describe( 'getSelection()', () => {
-		it( 'should return empty array if not started', () => {
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [] );
-		} );
-
-		it( 'should return block of selected nodes', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01', '02', '03' ],
-				[ '10', '11', '12', '13' ],
-				[ '20', '21', '22', '23' ],
-				[ '30', '31', '32', '33' ]
-			] ) );
-
-			tableSelection.startSelection( root.getNodeByPath( [ 0, 1, 1 ] ) );
-			tableSelection.updateSelection( root.getNodeByPath( [ 0, 2, 2 ] ) );
-
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [
-				root.getNodeByPath( [ 0, 1, 1 ] ),
-				root.getNodeByPath( [ 0, 1, 2 ] ),
-				root.getNodeByPath( [ 0, 2, 1 ] ),
-				root.getNodeByPath( [ 0, 2, 2 ] )
-			] );
-		} );
-
-		it( 'should return block of selected nodes (inverted selection)', () => {
-			setData( model, modelTable( [
-				[ '00[]', '01', '02', '03' ],
-				[ '10', '11', '12', '13' ],
-				[ '20', '21', '22', '23' ],
-				[ '30', '31', '32', '33' ]
-			] ) );
-
-			tableSelection.startSelection( root.getNodeByPath( [ 0, 2, 2 ] ) );
-			tableSelection.updateSelection( root.getNodeByPath( [ 0, 1, 1 ] ) );
-
-			expect( Array.from( tableSelection.getSelection() ) ).to.deep.equal( [
-				root.getNodeByPath( [ 0, 1, 1 ] ),
-				root.getNodeByPath( [ 0, 1, 2 ] ),
-				root.getNodeByPath( [ 0, 2, 1 ] ),
-				root.getNodeByPath( [ 0, 2, 2 ] )
-			] );
-		} );
-	} );
-} );