table.spec.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. 'use strict';
  2. describe('WalkontableTable', function () {
  3. var $table,
  4. $container,
  5. $wrapper,
  6. debug = false;
  7. beforeEach(function () {
  8. $wrapper = $('<div></div>').css({ overflow: 'hidden', position: 'relative' });
  9. $wrapper.width(100).height(201);
  10. $container = $('<div></div>');
  11. $table = $('<table></table>'); // create a table that is not attached to document
  12. $wrapper.append($container);
  13. $container.append($table);
  14. $wrapper.appendTo('body');
  15. createDataArray();
  16. });
  17. afterEach(function () {
  18. if (!debug) {
  19. $('.wtHolder').remove();
  20. }
  21. $wrapper.remove();
  22. });
  23. it('should create as many rows as fits in height', function () {
  24. var wt = new Walkontable.Core({
  25. table: $table[0],
  26. data: getData,
  27. totalRows: getTotalRows,
  28. totalColumns: getTotalColumns
  29. });
  30. wt.draw();
  31. expect($table.find('tbody tr').length).toBe(9);
  32. });
  33. it('should create as many rows as in `totalRows` if it is smaller than `height`', function () {
  34. this.data.splice(5, this.data.length - 5);
  35. var wt = new Walkontable.Core({
  36. table: $table[0],
  37. data: getData,
  38. totalRows: getTotalRows,
  39. totalColumns: getTotalColumns
  40. });
  41. wt.draw();
  42. expect($table.find('tbody tr').length).toBe(5);
  43. });
  44. it('first row should have as many columns as in THEAD', function () {
  45. var wt = new Walkontable.Core({
  46. table: $table[0],
  47. data: getData,
  48. totalRows: getTotalRows,
  49. totalColumns: getTotalColumns,
  50. columnHeaders: [function (col, TH) {
  51. TH.innerHTML = col + 1;
  52. }]
  53. });
  54. wt.draw();
  55. expect($table.find('tbody tr:first td').length).toBe($table.find('thead th').length);
  56. });
  57. it('should put a blank cell in the corner if both rowHeaders and colHeaders are set', function () {
  58. var wt = new Walkontable.Core({
  59. table: $table[0],
  60. data: getData,
  61. totalRows: getTotalRows,
  62. totalColumns: getTotalColumns,
  63. columnHeaders: [function (col, TH) {
  64. if (col > -1) {
  65. TH.innerHTML = 'Column';
  66. }
  67. }],
  68. rowHeaders: [function (row, TH) {
  69. if (row > -1) {
  70. TH.innerHTML = 'Row';
  71. }
  72. }]
  73. });
  74. wt.draw();
  75. expect($table.find('thead tr:first th').length).toBe(wt.wtTable.getRenderedColumnsCount() + 1); // 4 columns in THEAD + 1 empty cell in the corner
  76. expect($table.find('thead tr:first th:eq(0)')[0].innerHTML.replace(/&nbsp;/, '')).toBe(''); // corner row is empty (or contains only &nbsp;)
  77. expect($table.find('thead tr:first th:eq(1)')[0].innerHTML).toBe('Column');
  78. expect($table.find('tbody tr:first th:eq(0)')[0].innerHTML).toBe('Row');
  79. });
  80. it('getCell should only return cells from rendered rows', function () {
  81. var wt = new Walkontable.Core({
  82. table: $table[0],
  83. data: getData,
  84. totalRows: getTotalRows,
  85. totalColumns: getTotalColumns
  86. });
  87. wt.draw();
  88. expect(wt.wtTable.getCell(new Walkontable.CellCoords(7, 0)) instanceof HTMLElement).toBe(true);
  89. expect($table.find('tr:eq(8) td:first-child').text()).toEqual(this.data[8][0].toString());
  90. expect(wt.wtTable.getCell(new Walkontable.CellCoords(20, 0))).toBe(-2); // exit code
  91. expect(wt.wtTable.getCell(new Walkontable.CellCoords(25, 0))).toBe(-2); // exit code
  92. });
  93. it('getCoords should return coords of TD', function () {
  94. var wt = new Walkontable.Core({
  95. table: $table[0],
  96. data: getData,
  97. totalRows: getTotalRows,
  98. totalColumns: getTotalColumns
  99. });
  100. wt.draw();
  101. var $td2 = $table.find('tbody tr:eq(1) td:eq(1)');
  102. expect(wt.wtTable.getCoords($td2[0])).toEqual(new Walkontable.CellCoords(1, 1));
  103. });
  104. it('getCoords should return coords of TD (with row header)', function () {
  105. $wrapper.width(300);
  106. function plusOne(i) {
  107. return i + 1;
  108. }
  109. var wt = new Walkontable.Core({
  110. table: $table[0],
  111. data: getData,
  112. totalRows: getTotalRows,
  113. totalColumns: getTotalColumns,
  114. rowHeaders: [function (row, TH) {
  115. TH.innerHTML = plusOne(row);
  116. }]
  117. });
  118. wt.draw();
  119. var $td2 = $table.find('tbody tr:eq(1) td:eq(1)');
  120. expect(wt.wtTable.getCoords($td2[0])).toEqual(new Walkontable.CellCoords(1, 1));
  121. });
  122. it('getStretchedColumnWidth should return valid column width when stretchH is set as \'all\'', function () {
  123. var wt = new Walkontable.Core({
  124. table: $table[0],
  125. data: getData,
  126. totalRows: getTotalRows,
  127. totalColumns: getTotalColumns,
  128. rowHeaders: [function (row, TH) {
  129. TH.innerHTML = row + 1;
  130. }],
  131. stretchH: 'all'
  132. });
  133. wt.draw();
  134. wt.wtViewport.columnsRenderCalculator.refreshStretching(502);
  135. expect(wt.wtTable.getStretchedColumnWidth(0, 50)).toBe(125);
  136. expect(wt.wtTable.getStretchedColumnWidth(1, 50)).toBe(125);
  137. expect(wt.wtTable.getStretchedColumnWidth(2, 50)).toBe(125);
  138. expect(wt.wtTable.getStretchedColumnWidth(3, 50)).toBe(127);
  139. });
  140. it('getStretchedColumnWidth should return valid column width when stretchH is set as \'last\'', function () {
  141. var wt = new Walkontable.Core({
  142. table: $table[0],
  143. data: getData,
  144. totalRows: getTotalRows,
  145. totalColumns: getTotalColumns,
  146. rowHeaders: [function (row, TH) {
  147. TH.innerHTML = row + 1;
  148. }],
  149. stretchH: 'last'
  150. });
  151. wt.draw();
  152. wt.wtViewport.columnsRenderCalculator.refreshStretching(502);
  153. expect(wt.wtTable.getStretchedColumnWidth(0, 50)).toBe(50);
  154. expect(wt.wtTable.getStretchedColumnWidth(1, 50)).toBe(50);
  155. expect(wt.wtTable.getStretchedColumnWidth(2, 50)).toBe(50);
  156. expect(wt.wtTable.getStretchedColumnWidth(3, 50)).toBe(352);
  157. });
  158. it('should use custom cell renderer if provided', function () {
  159. var wt = new Walkontable.Core({
  160. table: $table[0],
  161. data: getData,
  162. totalRows: getTotalRows,
  163. totalColumns: getTotalColumns,
  164. cellRenderer: function cellRenderer(row, column, TD) {
  165. var cellData = getData(row, column);
  166. if (cellData === void 0) {
  167. TD.innerHTML = '';
  168. } else {
  169. TD.innerHTML = cellData;
  170. }
  171. TD.className = '';
  172. TD.style.backgroundColor = 'yellow';
  173. }
  174. });
  175. wt.draw();
  176. expect($table.find('td:first')[0].style.backgroundColor).toBe('yellow');
  177. });
  178. it('should remove rows if they were removed in data source', function () {
  179. this.data.splice(8, this.data.length - 8); // second param is required by IE8
  180. var wt = new Walkontable.Core({
  181. table: $table[0],
  182. data: getData,
  183. totalRows: getTotalRows,
  184. totalColumns: getTotalColumns
  185. });
  186. wt.draw();
  187. expect($table.find('tbody tr').length).toBe(8);
  188. this.data.splice(7, this.data.length - 7); // second param is required by IE8
  189. wt.draw();
  190. expect($table.find('tbody tr').length).toBe(7);
  191. });
  192. it('should render as much columns as the container width allows, if width is null', function () {
  193. var wt = new Walkontable.Core({
  194. table: $table[0],
  195. data: getData,
  196. totalRows: getTotalRows,
  197. totalColumns: getTotalColumns,
  198. columnHeaders: [function (col, TH) {
  199. TH.innerHTML = col + 1;
  200. }]
  201. });
  202. wt.draw();
  203. expect($table.find('thead tr:first').children().length).toBe(2);
  204. expect($table.find('tbody tr:first').children().length).toBe(2);
  205. $wrapper.width(200);
  206. wt.draw();
  207. expect($table.find('thead tr:first').children().length).toBe(4);
  208. expect($table.find('tbody tr:first').children().length).toBe(4);
  209. });
  210. it('should render as much columns as the container width allows, if width is null (with row header)', function () {
  211. var wt = new Walkontable.Core({
  212. table: $table[0],
  213. data: getData,
  214. totalRows: getTotalRows,
  215. totalColumns: getTotalColumns,
  216. rowHeaders: [function (row, TH) {
  217. TH.innerHTML = row + 1;
  218. }],
  219. columnHeaders: [function (col, TH) {
  220. TH.innerHTML = col + 1;
  221. }]
  222. });
  223. wt.draw();
  224. expect($table.find('thead tr:first').children().length).toBe(2);
  225. expect($table.find('tbody tr:first').children().length).toBe(2);
  226. $wrapper.width(200);
  227. wt.draw();
  228. expect($table.find('thead tr:first').children().length).toBe(4);
  229. expect($table.find('tbody tr:first').children().length).toBe(4);
  230. });
  231. it('should use column width function to get column width', function () {
  232. $wrapper.width(600);
  233. var wt = new Walkontable.Core({
  234. table: $table[0],
  235. data: getData,
  236. totalRows: getTotalRows,
  237. totalColumns: getTotalColumns,
  238. rowHeaders: [function (row, TH) {
  239. TH.innerHTML = row + 1;
  240. }],
  241. columnHeaders: [function (col, TH) {
  242. TH.innerHTML = col + 1;
  243. }],
  244. columnWidth: function columnWidth(column) {
  245. return (column + 1) * 50;
  246. }
  247. });
  248. wt.draw();
  249. expect($table.find('tbody tr:first td:eq(0)').outerWidth()).toBe(50);
  250. expect($table.find('tbody tr:first td:eq(1)').outerWidth()).toBe(100);
  251. expect($table.find('tbody tr:first td:eq(2)').outerWidth()).toBe(150);
  252. expect($table.find('tbody tr:first td:eq(3)').outerWidth()).toBe(200);
  253. });
  254. it('should use column width array to get column width', function () {
  255. $wrapper.width(600);
  256. var wt = new Walkontable.Core({
  257. table: $table[0],
  258. data: getData,
  259. totalRows: getTotalRows,
  260. totalColumns: getTotalColumns,
  261. rowHeaders: [function (row, TH) {
  262. TH.innerHTML = row + 1;
  263. }],
  264. columnHeaders: [function (col, TH) {
  265. TH.innerHTML = col + 1;
  266. }],
  267. columnWidth: [50, 100, 150, 201]
  268. });
  269. wt.draw();
  270. expect($table.find('tbody tr:first td:eq(0)').outerWidth()).toBe(50);
  271. expect($table.find('tbody tr:first td:eq(1)').outerWidth()).toBe(100);
  272. expect($table.find('tbody tr:first td:eq(2)').outerWidth()).toBe(150);
  273. expect($table.find('tbody tr:first td:eq(3)').outerWidth()).toBe(201);
  274. });
  275. it('should use column width integer to get column width', function () {
  276. $wrapper.width(600);
  277. var wt = new Walkontable.Core({
  278. table: $table[0],
  279. data: getData,
  280. totalRows: getTotalRows,
  281. totalColumns: getTotalColumns,
  282. rowHeaders: [function (row, TH) {
  283. TH.innerHTML = row + 1;
  284. }],
  285. columnHeaders: [function (col, TH) {
  286. TH.innerHTML = col + 1;
  287. }],
  288. columnWidth: 100
  289. });
  290. wt.draw();
  291. expect($table.find('tbody tr:first td:eq(0)').outerWidth()).toBe(100);
  292. expect($table.find('tbody tr:first td:eq(1)').outerWidth()).toBe(100);
  293. expect($table.find('tbody tr:first td:eq(2)').outerWidth()).toBe(100);
  294. expect($table.find('tbody tr:first td:eq(3)').outerWidth()).toBe(100);
  295. });
  296. it('should use column width also when there are no rows', function () {
  297. this.data.length = 0;
  298. $wrapper.width(600);
  299. var wt = new Walkontable.Core({
  300. table: $table[0],
  301. data: getData,
  302. totalRows: getTotalRows,
  303. totalColumns: 4,
  304. rowHeaders: [function (row, TH) {
  305. TH.innerHTML = row + 1;
  306. }],
  307. columnHeaders: [function (col, TH) {
  308. TH.innerHTML = col + 1;
  309. }],
  310. columnWidth: 100
  311. });
  312. wt.draw();
  313. // start from eq(1) because eq(0) is corner header
  314. expect($table.find('thead tr:first th:eq(1)').outerWidth()).toBe(100);
  315. expect($table.find('thead tr:first th:eq(2)').outerWidth()).toBe(100);
  316. expect($table.find('thead tr:first th:eq(3)').outerWidth()).toBe(100);
  317. expect($table.find('thead tr:first th:eq(4)').outerWidth()).toBe(100);
  318. });
  319. it('should render a cell that is outside of the viewport horizontally', function () {
  320. var wt = new Walkontable.Core({
  321. table: $table[0],
  322. data: getData,
  323. totalRows: getTotalRows,
  324. totalColumns: getTotalColumns
  325. });
  326. wt.draw();
  327. $table.find('tbody td').html('');
  328. wt.draw();
  329. expect($table.find('tbody tr:first td').length).toBe(2);
  330. });
  331. it('should not render a cell when fastDraw == true', function () {
  332. var count = 0,
  333. wt = new Walkontable.Core({
  334. table: $table[0],
  335. data: getData,
  336. totalRows: getTotalRows,
  337. totalColumns: getTotalColumns,
  338. cellRenderer: function cellRenderer(row, column, TD) {
  339. count++;
  340. return wt.wtSettings.defaults.cellRenderer(row, column, TD);
  341. }
  342. });
  343. wt.draw();
  344. var oldCount = count;
  345. wt.draw(true);
  346. expect(count).toBe(oldCount);
  347. });
  348. it('should not ignore fastDraw == true when grid was scrolled by amount of rows that doesn\'t exceed endRow', function () {
  349. var count = 0,
  350. wt = new Walkontable.Core({
  351. table: $table[0],
  352. data: getData,
  353. totalRows: getTotalRows,
  354. totalColumns: getTotalColumns,
  355. cellRenderer: function cellRenderer(row, column, TD) {
  356. count++;
  357. return wt.wtSettings.defaults.cellRenderer(row, column, TD);
  358. },
  359. viewportRowCalculatorOverride: function viewportRowCalculatorOverride(calc) {
  360. calc.endRow += 10;
  361. }
  362. });
  363. wt.draw();
  364. var oldCount = count;
  365. wt.scrollVertical(8);
  366. wt.draw(true);
  367. expect(count).not.toBeGreaterThan(oldCount);
  368. });
  369. it('should ignore fastDraw == true when grid was scrolled by amount of rows that exceeds endRow', function () {
  370. var count = 0,
  371. wt = new Walkontable.Core({
  372. table: $table[0],
  373. data: getData,
  374. totalRows: getTotalRows,
  375. totalColumns: getTotalColumns,
  376. cellRenderer: function cellRenderer(row, column, TD) {
  377. count++;
  378. return wt.wtSettings.defaults.cellRenderer(row, column, TD);
  379. },
  380. viewportRowCalculatorOverride: function viewportRowCalculatorOverride(calc) {
  381. calc.endRow += 10;
  382. }
  383. });
  384. wt.draw();
  385. var oldCount = count;
  386. wt.scrollVertical(10);
  387. wt.draw(true);
  388. expect(count).not.toBeGreaterThan(oldCount);
  389. wt.scrollVertical(11);
  390. wt.draw(true);
  391. expect(count).toBeGreaterThan(oldCount);
  392. });
  393. it('should not ignore fastDraw == true when grid was scrolled by amount of columns that doesn\'t exceed endColumn', function () {
  394. createDataArray(50, 50);
  395. var count = 0,
  396. wt = new Walkontable.Core({
  397. table: $table[0],
  398. data: getData,
  399. totalRows: getTotalRows,
  400. totalColumns: getTotalColumns,
  401. cellRenderer: function cellRenderer(row, column, TD) {
  402. count++;
  403. return wt.wtSettings.defaults.cellRenderer(row, column, TD);
  404. },
  405. viewportColumnCalculatorOverride: function viewportColumnCalculatorOverride(calc) {
  406. calc.endColumn += 10;
  407. }
  408. });
  409. wt.draw();
  410. var oldCount = count;
  411. wt.scrollHorizontal(8);
  412. wt.draw(true);
  413. expect(count).not.toBeGreaterThan(oldCount);
  414. });
  415. it('should ignore fastDraw == true when grid was scrolled by amount of columns that exceeds endColumn', function () {
  416. createDataArray(50, 50);
  417. var count = 0,
  418. wt = new Walkontable.Core({
  419. table: $table[0],
  420. data: getData,
  421. totalRows: getTotalRows,
  422. totalColumns: getTotalColumns,
  423. cellRenderer: function cellRenderer(row, column, TD) {
  424. count++;
  425. return wt.wtSettings.defaults.cellRenderer(row, column, TD);
  426. },
  427. viewportColumnCalculatorOverride: function viewportColumnCalculatorOverride(calc) {
  428. calc.endColumn += 10;
  429. }
  430. });
  431. wt.draw();
  432. var oldCount = count;
  433. wt.scrollHorizontal(10);
  434. wt.draw(true);
  435. expect(count).not.toBeGreaterThan(oldCount);
  436. wt.scrollHorizontal(11);
  437. wt.draw(true);
  438. expect(count).toBeGreaterThan(oldCount);
  439. });
  440. describe('cell header border', function () {
  441. it('should be correct visible in fixedColumns and without row header', function () {
  442. createDataArray(50, 50);
  443. $wrapper.width(500).height(400);
  444. var count = 0,
  445. wt = new Walkontable.Core({
  446. table: $table[0],
  447. data: getData,
  448. totalRows: getTotalRows,
  449. totalColumns: getTotalColumns,
  450. columnWidth: 70,
  451. fixedColumnsLeft: 2,
  452. columnHeaders: [function (col, TH) {}]
  453. });
  454. wt.draw();
  455. expect($('.ht_clone_top_left_corner thead tr th').eq(0).css('border-left-width')).toBe('1px');
  456. expect($('.ht_clone_top_left_corner thead tr th').eq(0).css('border-right-width')).toBe('1px');
  457. expect($('.ht_clone_top_left_corner thead tr th').eq(1).css('border-left-width')).toBe('0px');
  458. expect($('.ht_clone_top_left_corner thead tr th').eq(1).css('border-right-width')).toBe('1px');
  459. });
  460. });
  461. describe('isLastRowFullyVisible', function () {
  462. it('should be false because it is only partially visible', function () {
  463. createDataArray(8, 4);
  464. $wrapper.width(185).height(175);
  465. var wt = new Walkontable.Core({
  466. table: $table[0],
  467. data: getData,
  468. totalRows: getTotalRows,
  469. totalColumns: getTotalColumns
  470. });
  471. wt.draw();
  472. expect(wt.wtTable.isLastRowFullyVisible()).toEqual(false);
  473. });
  474. it('should be true because it is fully visible', function () {
  475. createDataArray(8, 4);
  476. $wrapper.width(185).height(185);
  477. var wt = new Walkontable.Core({
  478. table: $table[0],
  479. data: getData,
  480. totalRows: getTotalRows,
  481. totalColumns: getTotalColumns
  482. });
  483. wt.draw();
  484. wt.scrollVertical(7);
  485. wt.draw();
  486. expect(wt.wtTable.isLastRowFullyVisible()).toEqual(true);
  487. });
  488. });
  489. xdescribe('isLastColumnFullyVisible', function () {
  490. it('should be false because it is only partially visible', function () {
  491. createDataArray(18, 4);
  492. $wrapper.width(209).height(185);
  493. var wt = new Walkontable.Core({
  494. table: $table[0],
  495. data: getData,
  496. totalRows: getTotalRows,
  497. totalColumns: getTotalColumns
  498. });
  499. wt.draw();
  500. expect(wt.wtTable.isLastColumnFullyVisible()).toEqual(false); // few pixels are obstacled by scrollbar
  501. });
  502. it('should be true because it is fully visible', function () {
  503. createDataArray(18, 4);
  504. $wrapper.width(180).height(185);
  505. var wt = new Walkontable.Core({
  506. table: $table[0],
  507. data: getData,
  508. totalRows: getTotalRows,
  509. totalColumns: getTotalColumns
  510. });
  511. wt.draw();
  512. wt.scrollHorizontal(1);
  513. expect(wt.wtTable.isLastColumnFullyVisible()).toEqual(true);
  514. });
  515. });
  516. });