tableutils.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor';
  6. import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  7. import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
  8. import { downcastInsertTable } from '../src/converters/downcast';
  9. import upcastTable from '../src/converters/upcasttable';
  10. import { formatTable, formattedModelTable, modelTable } from './_utils/utils';
  11. import TableUtils from '../src/tableutils';
  12. describe( 'TableUtils', () => {
  13. let editor, model, root, tableUtils;
  14. beforeEach( () => {
  15. return ModelTestEditor.create( {
  16. plugins: [ TableUtils ]
  17. } ).then( newEditor => {
  18. editor = newEditor;
  19. model = editor.model;
  20. root = model.document.getRoot( 'main' );
  21. tableUtils = editor.plugins.get( TableUtils );
  22. const conversion = editor.conversion;
  23. const schema = model.schema;
  24. schema.register( 'table', {
  25. allowWhere: '$block',
  26. allowAttributes: [ 'headingRows' ],
  27. isBlock: true,
  28. isObject: true
  29. } );
  30. schema.register( 'tableRow', {
  31. allowIn: 'table',
  32. allowAttributes: [],
  33. isBlock: true,
  34. isLimit: true
  35. } );
  36. schema.register( 'tableCell', {
  37. allowIn: 'tableRow',
  38. allowContentOf: '$block',
  39. allowAttributes: [ 'colspan', 'rowspan' ],
  40. isBlock: true,
  41. isLimit: true
  42. } );
  43. model.schema.register( 'p', { inheritAllFrom: '$block' } );
  44. // Table conversion.
  45. conversion.for( 'upcast' ).add( upcastTable() );
  46. conversion.for( 'downcast' ).add( downcastInsertTable() );
  47. // Table row upcast only since downcast conversion is done in `downcastTable()`.
  48. conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableRow', view: 'tr' } ) );
  49. // Table cell conversion.
  50. conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
  51. conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
  52. conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
  53. conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
  54. } );
  55. } );
  56. afterEach( () => {
  57. return editor.destroy();
  58. } );
  59. describe( 'getCellLocation()', () => {
  60. it( 'should return proper table cell location', () => {
  61. setData( model, modelTable( [
  62. [ { rowspan: 2, colspan: 2, contents: '00[]' }, '02' ],
  63. [ '12' ]
  64. ] ) );
  65. expect( tableUtils.getCellLocation( root.getNodeByPath( [ 0, 0, 0 ] ) ) ).to.deep.equal( { row: 0, column: 0 } );
  66. expect( tableUtils.getCellLocation( root.getNodeByPath( [ 0, 0, 1 ] ) ) ).to.deep.equal( { row: 0, column: 2 } );
  67. expect( tableUtils.getCellLocation( root.getNodeByPath( [ 0, 1, 0 ] ) ) ).to.deep.equal( { row: 1, column: 2 } );
  68. } );
  69. } );
  70. describe( 'insertRows()', () => {
  71. it( 'should insert row in given table at given index', () => {
  72. setData( model, modelTable( [
  73. [ '11[]', '12' ],
  74. [ '21', '22' ]
  75. ] ) );
  76. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 1 } );
  77. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  78. [ '11[]', '12' ],
  79. [ '', '' ],
  80. [ '21', '22' ]
  81. ] ) );
  82. } );
  83. it( 'should insert row in given table at default index', () => {
  84. setData( model, modelTable( [
  85. [ '11[]', '12' ],
  86. [ '21', '22' ]
  87. ] ) );
  88. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ) );
  89. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  90. [ '', '' ],
  91. [ '11[]', '12' ],
  92. [ '21', '22' ]
  93. ] ) );
  94. } );
  95. it( 'should update table heading rows attribute when inserting row in headings section', () => {
  96. setData( model, modelTable( [
  97. [ '11[]', '12' ],
  98. [ '21', '22' ],
  99. [ '31', '32' ]
  100. ], { headingRows: 2 } ) );
  101. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 1 } );
  102. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  103. [ '11[]', '12' ],
  104. [ '', '' ],
  105. [ '21', '22' ],
  106. [ '31', '32' ]
  107. ], { headingRows: 3 } ) );
  108. } );
  109. it( 'should not update table heading rows attribute when inserting row after headings section', () => {
  110. setData( model, modelTable( [
  111. [ '11[]', '12' ],
  112. [ '21', '22' ],
  113. [ '31', '32' ]
  114. ], { headingRows: 2 } ) );
  115. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 2 } );
  116. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  117. [ '11[]', '12' ],
  118. [ '21', '22' ],
  119. [ '', '' ],
  120. [ '31', '32' ]
  121. ], { headingRows: 2 } ) );
  122. } );
  123. it( 'should expand rowspan of a cell that overlaps inserted rows', () => {
  124. setData( model, modelTable( [
  125. [ { colspan: 2, contents: '11[]' }, '13', '14' ],
  126. [ { colspan: 2, rowspan: 4, contents: '21' }, '23', '24' ],
  127. [ '33', '34' ]
  128. ], { headingColumns: 3, headingRows: 1 } ) );
  129. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 2, rows: 3 } );
  130. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  131. [ { colspan: 2, contents: '11[]' }, '13', '14' ],
  132. [ { colspan: 2, rowspan: 7, contents: '21' }, '23', '24' ],
  133. [ '', '' ],
  134. [ '', '' ],
  135. [ '', '' ],
  136. [ '33', '34' ]
  137. ], { headingColumns: 3, headingRows: 1 } ) );
  138. } );
  139. it( 'should not expand rowspan of a cell that does not overlaps inserted rows', () => {
  140. setData( model, modelTable( [
  141. [ { rowspan: 2, contents: '11[]' }, '12', '13' ],
  142. [ '22', '23' ],
  143. [ '31', '32', '33' ]
  144. ], { headingColumns: 3, headingRows: 1 } ) );
  145. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 2, rows: 3 } );
  146. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  147. [ { rowspan: 2, contents: '11[]' }, '12', '13' ],
  148. [ '22', '23' ],
  149. [ '', '', '' ],
  150. [ '', '', '' ],
  151. [ '', '', '' ],
  152. [ '31', '32', '33' ]
  153. ], { headingColumns: 3, headingRows: 1 } ) );
  154. } );
  155. it( 'should properly calculate columns if next row has colspans', () => {
  156. setData( model, modelTable( [
  157. [ { rowspan: 2, contents: '11[]' }, '12', '13' ],
  158. [ '22', '23' ],
  159. [ { colspan: 3, contents: '31' } ]
  160. ], { headingColumns: 3, headingRows: 1 } ) );
  161. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 2, rows: 3 } );
  162. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  163. [ { rowspan: 2, contents: '11[]' }, '12', '13' ],
  164. [ '22', '23' ],
  165. [ '', '', '' ],
  166. [ '', '', '' ],
  167. [ '', '', '' ],
  168. [ { colspan: 3, contents: '31' } ]
  169. ], { headingColumns: 3, headingRows: 1 } ) );
  170. } );
  171. it( 'should insert rows at the end of a table', () => {
  172. setData( model, modelTable( [
  173. [ '11[]', '12' ],
  174. [ '21', '22' ]
  175. ] ) );
  176. tableUtils.insertRows( root.getNodeByPath( [ 0 ] ), { at: 2, rows: 3 } );
  177. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  178. [ '11[]', '12' ],
  179. [ '21', '22' ],
  180. [ '', '' ],
  181. [ '', '' ],
  182. [ '', '' ]
  183. ] ) );
  184. } );
  185. } );
  186. describe( 'insertColumns()', () => {
  187. it( 'should insert column in given table at given index', () => {
  188. setData( model, modelTable( [
  189. [ '11[]', '12' ],
  190. [ '21', '22' ]
  191. ] ) );
  192. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 1 } );
  193. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  194. [ '11[]', '', '12' ],
  195. [ '21', '', '22' ]
  196. ] ) );
  197. } );
  198. it( 'should insert column in given table with default values', () => {
  199. setData( model, modelTable( [
  200. [ '11[]', '12' ],
  201. [ '21', '22' ]
  202. ] ) );
  203. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ) );
  204. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  205. [ '', '11[]', '12' ],
  206. [ '', '21', '22' ]
  207. ] ) );
  208. } );
  209. it( 'should insert column in given table at default index', () => {
  210. setData( model, modelTable( [
  211. [ '11[]', '12' ],
  212. [ '21', '22' ]
  213. ] ) );
  214. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ) );
  215. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  216. [ '', '11[]', '12' ],
  217. [ '', '21', '22' ]
  218. ] ) );
  219. } );
  220. it( 'should insert columns at the end of a row', () => {
  221. setData( model, modelTable( [
  222. [ '00[]', '01' ],
  223. [ { colspan: 2, contents: '10' } ],
  224. [ '20', { rowspan: 2, contents: '21' } ],
  225. [ '30' ]
  226. ] ) );
  227. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 2, columns: 2 } );
  228. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  229. [ '00[]', '01', '', '' ],
  230. [ { colspan: 2, contents: '10' }, '', '' ],
  231. [ '20', { rowspan: 2, contents: '21' }, '', '' ],
  232. [ '30', '', '' ]
  233. ] ) );
  234. } );
  235. it( 'should insert columns at the beginning of a row', () => {
  236. setData( model, modelTable( [
  237. [ '00[]', '01' ],
  238. [ { colspan: 2, contents: '10' } ],
  239. [ '20', { rowspan: 2, contents: '21' } ],
  240. [ { rowspan: 2, contents: '30' } ],
  241. [ '41' ]
  242. ] ) );
  243. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 0, columns: 2 } );
  244. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  245. [ '', '', '00[]', '01' ],
  246. [ '', '', { colspan: 2, contents: '10' } ],
  247. [ '', '', '20', { rowspan: 2, contents: '21' } ],
  248. [ '', '', { rowspan: 2, contents: '30' } ],
  249. [ '', '', '41' ]
  250. ] ) );
  251. } );
  252. it( 'should update table heading columns attribute when inserting column in headings section', () => {
  253. setData( model, modelTable( [
  254. [ '11[]', '12' ],
  255. [ '21', '22' ],
  256. [ '31', '32' ]
  257. ], { headingColumns: 2 } ) );
  258. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 1 } );
  259. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  260. [ '11[]', '', '12' ],
  261. [ '21', '', '22' ],
  262. [ '31', '', '32' ]
  263. ], { headingColumns: 3 } ) );
  264. } );
  265. it( 'should not update table heading columns attribute when inserting column after headings section', () => {
  266. setData( model, modelTable( [
  267. [ '11[]', '12', '13' ],
  268. [ '21', '22', '23' ],
  269. [ '31', '32', '33' ]
  270. ], { headingColumns: 2 } ) );
  271. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 2 } );
  272. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  273. [ '11[]', '12', '', '13' ],
  274. [ '21', '22', '', '23' ],
  275. [ '31', '32', '', '33' ]
  276. ], { headingColumns: 2 } ) );
  277. } );
  278. it( 'should expand spanned columns', () => {
  279. setData( model, modelTable( [
  280. [ '11[]', '12' ],
  281. [ { colspan: 2, contents: '21' } ],
  282. [ '31', '32' ]
  283. ], { headingColumns: 2 } ) );
  284. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 1 } );
  285. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  286. [ '11[]', '', '12' ],
  287. [ { colspan: 3, contents: '21' } ],
  288. [ '31', '', '32' ]
  289. ], { headingColumns: 3 } ) );
  290. } );
  291. it( 'should skip wide spanned columns', () => {
  292. setData( model, modelTable( [
  293. [ '11[]', '12', '13', '14', '15' ],
  294. [ '21', '22', { colspan: 2, contents: '23' }, '25' ],
  295. [ { colspan: 4, contents: '31' }, { colspan: 2, contents: '34' } ]
  296. ], { headingColumns: 4 } ) );
  297. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 2, columns: 2 } );
  298. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  299. [ '11[]', '12', '', '', '13', '14', '15' ],
  300. [ '21', '22', '', '', { colspan: 2, contents: '23' }, '25' ],
  301. [ { colspan: 6, contents: '31' }, { colspan: 2, contents: '34' } ]
  302. ], { headingColumns: 6 } ) );
  303. } );
  304. it( 'should skip row & column spanned cells', () => {
  305. setData( model, modelTable( [
  306. [ { colspan: 2, rowspan: 2, contents: '00[]' }, '02' ],
  307. [ '12' ],
  308. [ '20', '21', '22' ]
  309. ], { headingColumns: 2 } ) );
  310. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 1, columns: 2 } );
  311. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  312. [ { colspan: 4, rowspan: 2, contents: '00[]' }, '02' ],
  313. [ '12' ],
  314. [ '20', '', '', '21', '22' ]
  315. ], { headingColumns: 4 } ) );
  316. } );
  317. it( 'should properly insert column while table has rowspanned cells', () => {
  318. setData( model, modelTable( [
  319. [ { rowspan: 4, contents: '00[]' }, { rowspan: 2, contents: '01' }, '02' ],
  320. [ '12' ],
  321. [ { rowspan: 2, contents: '21' }, '22' ],
  322. [ '32' ]
  323. ], { headingColumns: 2 } ) );
  324. tableUtils.insertColumns( root.getNodeByPath( [ 0 ] ), { at: 1, columns: 1 } );
  325. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  326. [ { rowspan: 4, contents: '00[]' }, '', { rowspan: 2, contents: '01' }, '02' ],
  327. [ '', '12' ],
  328. [ '', { rowspan: 2, contents: '21' }, '22' ],
  329. [ '', '32' ]
  330. ], { headingColumns: 3 } ) );
  331. } );
  332. } );
  333. describe( 'splitCellHorizontally()', () => {
  334. it( 'should split table cell to given table cells number', () => {
  335. setData( model, modelTable( [
  336. [ '00', '01', '02' ],
  337. [ '10', '[]11', '12' ],
  338. [ '20', { colspan: 2, contents: '21' } ],
  339. [ { colspan: 2, contents: '30' }, '32' ]
  340. ] ) );
  341. tableUtils.splitCellHorizontally( root.getNodeByPath( [ 0, 1, 1 ] ), 3 );
  342. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  343. [ '00', { colspan: 3, contents: '01' }, '02' ],
  344. [ '10', '[]11', '', '', '12' ],
  345. [ '20', { colspan: 4, contents: '21' } ],
  346. [ { colspan: 4, contents: '30' }, '32' ]
  347. ] ) );
  348. } );
  349. it( 'should split table cell for two table cells as a default', () => {
  350. setData( model, modelTable( [
  351. [ '00', '01', '02' ],
  352. [ '10', '[]11', '12' ],
  353. [ '20', { colspan: 2, contents: '21' } ],
  354. [ { colspan: 2, contents: '30' }, '32' ]
  355. ] ) );
  356. tableUtils.splitCellHorizontally( root.getNodeByPath( [ 0, 1, 1 ] ) );
  357. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  358. [ '00', { colspan: 2, contents: '01' }, '02' ],
  359. [ '10', '[]11', '', '12' ],
  360. [ '20', { colspan: 3, contents: '21' } ],
  361. [ { colspan: 3, contents: '30' }, '32' ]
  362. ] ) );
  363. } );
  364. it( 'should unsplit table cell if split is equal to colspan', () => {
  365. setData( model, modelTable( [
  366. [ '00', '01', '02' ],
  367. [ '10', '11', '12' ],
  368. [ '20', { colspan: 2, contents: '21[]' } ],
  369. [ { colspan: 2, contents: '30' }, '32' ]
  370. ] ) );
  371. tableUtils.splitCellHorizontally( root.getNodeByPath( [ 0, 2, 1 ] ), 2 );
  372. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  373. [ '00', '01', '02' ],
  374. [ '10', '11', '12' ],
  375. [ '20', '21[]', '' ],
  376. [ { colspan: 2, contents: '30' }, '32' ]
  377. ] ) );
  378. } );
  379. it( 'should properly unsplit table cell if split is uneven', () => {
  380. setData( model, modelTable( [
  381. [ '00', '01', '02' ],
  382. [ { colspan: 3, contents: '10[]' } ]
  383. ] ) );
  384. tableUtils.splitCellHorizontally( root.getNodeByPath( [ 0, 1, 0 ] ), 2 );
  385. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  386. [ '00', '01', '02' ],
  387. [ { colspan: 2, contents: '10[]' }, '' ]
  388. ] ) );
  389. } );
  390. it( 'should properly set colspan of inserted cells', () => {
  391. setData( model, modelTable( [
  392. [ '00', '01', '02', '03' ],
  393. [ { colspan: 4, contents: '10[]' } ]
  394. ] ) );
  395. tableUtils.splitCellHorizontally( root.getNodeByPath( [ 0, 1, 0 ] ), 2 );
  396. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  397. [ '00', '01', '02', '03' ],
  398. [ { colspan: 2, contents: '10[]' }, { colspan: 2, contents: '' } ]
  399. ] ) );
  400. } );
  401. it( 'should keep rowspan attribute for newly inserted cells', () => {
  402. setData( model, modelTable( [
  403. [ '00', '01', '02', '03', '04', '05' ],
  404. [ { colspan: 5, rowspan: 2, contents: '10[]' }, '15' ],
  405. [ '25' ]
  406. ] ) );
  407. tableUtils.splitCellHorizontally( root.getNodeByPath( [ 0, 1, 0 ] ), 2 );
  408. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  409. [ '00', '01', '02', '03', '04', '05' ],
  410. [ { colspan: 3, rowspan: 2, contents: '10[]' }, { colspan: 2, rowspan: 2, contents: '' }, '15' ],
  411. [ '25' ]
  412. ] ) );
  413. } );
  414. } );
  415. describe( 'splitCellVertically()', () => {
  416. it( 'should split table cell to default table cells number', () => {
  417. setData( model, modelTable( [
  418. [ '00', '01', '02' ],
  419. [ '10', '[]11', '12' ],
  420. [ '20', '21', '22' ]
  421. ] ) );
  422. tableUtils.splitCellVertically( root.getNodeByPath( [ 0, 1, 1 ] ) );
  423. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  424. [ '00', '01', '02' ],
  425. [ { rowspan: 2, contents: '10' }, '[]11', { rowspan: 2, contents: '12' } ],
  426. [ '' ],
  427. [ '20', '21', '22' ]
  428. ] ) );
  429. } );
  430. it( 'should split table cell to given table cells number', () => {
  431. setData( model, modelTable( [
  432. [ '00', '01', '02' ],
  433. [ '10', '[]11', '12' ],
  434. [ '20', '21', '22' ]
  435. ] ) );
  436. tableUtils.splitCellVertically( root.getNodeByPath( [ 0, 1, 1 ] ), 4 );
  437. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  438. [ '00', '01', '02' ],
  439. [ { rowspan: 4, contents: '10' }, '[]11', { rowspan: 4, contents: '12' } ],
  440. [ '' ],
  441. [ '' ],
  442. [ '' ],
  443. [ '20', '21', '22' ]
  444. ] ) );
  445. } );
  446. it( 'should properly update rowspanned cells overlapping selected cell', () => {
  447. setData( model, modelTable( [
  448. [ { rowspan: 2, contents: '00' }, '01', { rowspan: 3, contents: '02' } ],
  449. [ '[]11' ],
  450. [ '20', '21' ]
  451. ] ) );
  452. tableUtils.splitCellVertically( root.getNodeByPath( [ 0, 1, 0 ] ), 3 );
  453. expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
  454. [ { rowspan: 4, contents: '00' }, '01', { rowspan: 5, contents: '02' } ],
  455. [ '[]11' ],
  456. [ '' ],
  457. [ '' ],
  458. [ '20', '21' ]
  459. ] ) );
  460. } );
  461. } );
  462. describe( 'getColumns()', () => {
  463. it( 'should return proper number of columns', () => {
  464. setData( model, modelTable( [
  465. [ '00', { colspan: 3, contents: '01' }, '04' ]
  466. ] ) );
  467. expect( tableUtils.getColumns( root.getNodeByPath( [ 0 ] ) ) ).to.equal( 5 );
  468. } );
  469. } );
  470. } );