Core_view.spec.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. describe('Core_view', () => {
  2. const id = 'testContainer';
  3. beforeEach(function() {
  4. this.$container = $(`<div id="${id}"></div>`).appendTo('body');
  5. });
  6. afterEach(function() {
  7. if (this.$container) {
  8. destroy();
  9. this.$container.remove();
  10. }
  11. });
  12. it('should focus cell after viewport is scrolled using down arrow', () => {
  13. spec().$container[0].style.width = '400px';
  14. spec().$container[0].style.height = '60px';
  15. handsontable({
  16. startRows: 20
  17. });
  18. selectCell(0, 0);
  19. keyDown('arrow_down');
  20. keyDown('arrow_down');
  21. keyDown('arrow_down');
  22. keyDown('arrow_down');
  23. expect(getSelected()).toEqual([[4, 0, 4, 0]]);
  24. keyDown('enter');
  25. expect(isEditorVisible()).toEqual(true);
  26. });
  27. it('should scroll viewport if selected cell is out of the viewport and renderAllRows is enabled', () => {
  28. spec().$container[0].style.width = '400px';
  29. spec().$container[0].style.height = '50px';
  30. spec().$container[0].style.overflow = 'hidden';
  31. const hot = handsontable({
  32. startRows: 20,
  33. renderAllRows: true,
  34. });
  35. selectCell(0, 0);
  36. const scrollableElement = hot.view.wt.wtOverlays.topOverlay.mainTableScrollableElement;
  37. const initialScrollTop = scrollableElement.scrollTop;
  38. keyDown('arrow_down');
  39. keyDown('arrow_down');
  40. keyDown('arrow_down');
  41. keyDown('arrow_down');
  42. expect(scrollableElement.scrollTop).toBeGreaterThan(initialScrollTop);
  43. });
  44. it('should not render "undefined" class name', () => {
  45. spec().$container[0].style.width = '501px';
  46. spec().$container[0].style.height = '100px';
  47. spec().$container[0].style.overflow = 'hidden';
  48. handsontable({
  49. startRows: 10,
  50. startCols: 5,
  51. colWidths: [47, 47, 47, 47, 47],
  52. rowHeaders: true,
  53. colHeaders: true,
  54. stretchH: 'all'
  55. });
  56. selectCell(0, 0);
  57. expect(spec().$container.find('.undefined').length).toBe(0);
  58. });
  59. it('should scroll viewport when partially visible cell is clicked', () => {
  60. spec().$container[0].style.width = '400px';
  61. spec().$container[0].style.height = '60px';
  62. const hot = handsontable({
  63. data: Handsontable.helper.createSpreadsheetData(10, 3),
  64. height: 60
  65. });
  66. const htCore = getHtCore();
  67. const scrollTop = hot.rootElement.querySelector('.wtHolder').scrollTop;
  68. expect(scrollTop).toBe(0);
  69. expect(spec().$container.height()).toEqual(60);
  70. expect(spec().$container.find('.wtHolder .wtHider').height()).toBeGreaterThan(60);
  71. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  72. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  73. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  74. htCore.find('tr:eq(3) td:eq(0)').simulate('mousedown');
  75. expect(hot.rootElement.querySelector('.wtHolder').scrollTop).toBeGreaterThan(scrollTop);
  76. expect(getSelected()).toEqual([[3, 0, 3, 0]]);
  77. });
  78. it('should scroll viewport without cell selection', () => {
  79. spec().$container[0].style.width = '400px';
  80. const hot1 = handsontable({
  81. data: Handsontable.helper.createSpreadsheetData(20, 20),
  82. height: 100
  83. });
  84. hot1.scrollViewportTo(10, 10);
  85. const wtHolder = spec().$container.find('.ht_master .wtHolder');
  86. expect(wtHolder[0].scrollTop).toEqual(230);
  87. expect(wtHolder[0].scrollLeft).toEqual(500);
  88. });
  89. it('should not throw error while scrolling viewport to 0, 0 (empty data)', () => {
  90. spec().$container[0].style.width = '400px';
  91. const hot1 = handsontable({
  92. data: [],
  93. height: 100
  94. });
  95. expect(() => {
  96. hot1.view.scrollViewport({ row: 0, col: 0 });
  97. }).not.toThrow();
  98. });
  99. it('should throw error while scrolling viewport below 0 (empty data)', () => {
  100. spec().$container[0].style.width = '400px';
  101. const hot1 = handsontable({
  102. data: [],
  103. height: 100
  104. });
  105. expect(hot1.view.scrollViewport({ row: -1, col: 0 })).toBe(false);
  106. expect(hot1.view.scrollViewport({ row: 0, col: -1 })).toBe(false);
  107. expect(hot1.view.scrollViewport({ row: -1, col: -1 })).toBe(false);
  108. });
  109. it('should scroll viewport, respecting fixed rows', () => {
  110. spec().$container[0].style.width = '400px';
  111. spec().$container[0].style.height = '60px';
  112. const hot = handsontable({
  113. data: Handsontable.helper.createSpreadsheetData(10, 9),
  114. fixedRowsTop: 1,
  115. height: 60
  116. });
  117. const htCore = getHtCore();
  118. const scrollTop = hot.rootElement.querySelector('.wtHolder').scrollTop;
  119. expect(scrollTop).toBe(0);
  120. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  121. expect(htCore.find('tr:eq(0) td:eq(1)').html()).toEqual('B1');
  122. expect(htCore.find('tr:eq(0) td:eq(2)').html()).toEqual('C1');
  123. selectCell(0, 0);
  124. keyDown('arrow_down');
  125. keyDown('arrow_down');
  126. keyDown('arrow_down');
  127. keyDown('arrow_down');
  128. expect(hot.rootElement.querySelector('.wtHolder').scrollTop).toBeGreaterThan(scrollTop);
  129. });
  130. it('should enable to change fixedRowsTop with updateSettings', () => {
  131. spec().$container[0].style.width = '400px';
  132. spec().$container[0].style.height = '60px';
  133. const HOT = handsontable({
  134. data: Handsontable.helper.createSpreadsheetData(10, 9),
  135. fixedRowsTop: 1,
  136. width: 200,
  137. height: 100
  138. });
  139. selectCell(0, 0);
  140. const htCore = getHtCore();
  141. const topClone = getTopClone();
  142. expect(topClone.find('tr').length).toEqual(1);
  143. expect(topClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  144. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  145. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  146. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  147. expect(htCore.find('tr:eq(3) td:eq(0)').html()).toEqual('A4');
  148. keyDown('arrow_down');
  149. keyDown('arrow_down');
  150. keyDown('arrow_down');
  151. keyDown('arrow_down');
  152. expect(topClone.find('tr').length).toEqual(1);
  153. expect(topClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  154. HOT.updateSettings({
  155. fixedRowsTop: 2
  156. });
  157. expect(topClone.find('tr').length).toEqual(2);
  158. expect(topClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  159. expect(topClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  160. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  161. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  162. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  163. expect(htCore.find('tr:eq(3) td:eq(0)').html()).toEqual('A4');
  164. });
  165. it('should scroll viewport, respecting fixed columns', () => {
  166. spec().$container[0].style.width = '200px';
  167. spec().$container[0].style.height = '100px';
  168. handsontable({
  169. data: Handsontable.helper.createSpreadsheetData(10, 9),
  170. fixedColumnsLeft: 1
  171. });
  172. const htCore = getHtCore();
  173. const leftClone = spec().$container.find('.ht_clone_left');
  174. expect(leftClone.find('tr:eq(0) td').length).toEqual(1);
  175. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  176. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  177. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  178. expect(htCore.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  179. expect(htCore.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  180. expect(htCore.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  181. selectCell(0, 3);
  182. keyDown('arrow_right');
  183. keyDown('arrow_right');
  184. keyDown('arrow_right');
  185. keyDown('arrow_right');
  186. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  187. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  188. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  189. });
  190. it('should enable to change fixedColumnsLeft with updateSettings', () => {
  191. spec().$container[0].style.width = '200px';
  192. spec().$container[0].style.height = '100px';
  193. const HOT = handsontable({
  194. data: Handsontable.helper.createSpreadsheetData(10, 9),
  195. fixedColumnsLeft: 1
  196. });
  197. selectCell(0, 0);
  198. const leftClone = spec().$container.find('.ht_clone_left');
  199. expect(leftClone.find('tr:eq(0) td').length).toEqual(1);
  200. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  201. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  202. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  203. keyDown('arrow_right');
  204. keyDown('arrow_right');
  205. keyDown('arrow_right');
  206. keyDown('arrow_right');
  207. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  208. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  209. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  210. selectCell(0, 0);
  211. HOT.updateSettings({
  212. fixedColumnsLeft: 2
  213. });
  214. expect(leftClone.find('tr:eq(0) td').length).toEqual(2);
  215. expect(leftClone.find('tr:eq(0) td:eq(0)').html()).toEqual('A1');
  216. expect(leftClone.find('tr:eq(0) td:eq(1)').html()).toEqual('B1');
  217. expect(leftClone.find('tr:eq(1) td:eq(0)').html()).toEqual('A2');
  218. expect(leftClone.find('tr:eq(1) td:eq(1)').html()).toEqual('B2');
  219. expect(leftClone.find('tr:eq(2) td:eq(0)').html()).toEqual('A3');
  220. expect(leftClone.find('tr:eq(2) td:eq(1)').html()).toEqual('B3');
  221. });
  222. it('should not scroll viewport when last cell is clicked', () => {
  223. handsontable({
  224. startRows: 40
  225. });
  226. $(window).scrollTop(10000);
  227. const lastScroll = $(window).scrollTop();
  228. render(); // renders synchronously so we don't have to put stuff in waits/runs
  229. selectCell(39, 0);
  230. expect($(window).scrollTop()).toEqual(lastScroll);
  231. keyDown('arrow_right');
  232. expect(getSelected()).toEqual([[39, 1, 39, 1]]);
  233. expect($(window).scrollTop()).toEqual(lastScroll);
  234. });
  235. it('should not shrink table when width and height is not specified for container', async() => {
  236. spec().$container[0].style.overflow = 'hidden';
  237. spec().$container.wrap('<div style="width: 50px;"></div>');
  238. handsontable({
  239. startRows: 10,
  240. startCols: 10
  241. });
  242. await sleep(250);
  243. const initHeight = spec().$container.height();
  244. await sleep(250);
  245. expect(spec().$container.height()).toEqual(initHeight);
  246. });
  247. it('should allow height to be a number', () => {
  248. handsontable({
  249. startRows: 10,
  250. startCols: 10,
  251. height: 107
  252. });
  253. expect(spec().$container.height()).toEqual(107);
  254. });
  255. it('should allow height to be a function', () => {
  256. handsontable({
  257. startRows: 10,
  258. startCols: 10,
  259. height() {
  260. return 107;
  261. }
  262. });
  263. expect(spec().$container.height()).toEqual(107);
  264. });
  265. it('should allow width to be a number', () => {
  266. handsontable({
  267. startRows: 10,
  268. startCols: 10,
  269. width: 107,
  270. });
  271. expect(spec().$container.width()).toEqual(107); // rootElement is full width but this should do the trick
  272. });
  273. it('should allow width to be a function', () => {
  274. handsontable({
  275. startRows: 10,
  276. startCols: 10,
  277. width() {
  278. return 107;
  279. }
  280. });
  281. expect(spec().$container.width()).toEqual(107); // rootElement is full width but this should do the trick
  282. });
  283. it('should fire beforeRender event after table has been scrolled', async() => {
  284. spec().$container[0].style.width = '400px';
  285. spec().$container[0].style.height = '60px';
  286. spec().$container[0].style.overflow = 'hidden';
  287. const hot = handsontable({
  288. data: Handsontable.helper.createSpreadsheetData(100, 3)
  289. });
  290. const beforeRenderCallback = jasmine.createSpy('beforeRenderCallback');
  291. hot.addHook('beforeRender', beforeRenderCallback);
  292. spec().$container.find('.ht_master .wtHolder').scrollTop(1000);
  293. await sleep(200);
  294. expect(beforeRenderCallback.calls.count()).toBe(1);
  295. });
  296. it('should fire afterRender event after table has been scrolled', async() => {
  297. spec().$container[0].style.width = '400px';
  298. spec().$container[0].style.height = '60px';
  299. spec().$container[0].style.overflow = 'hidden';
  300. const hot = handsontable({
  301. data: Handsontable.helper.createSpreadsheetData(20, 3)
  302. });
  303. const afterRenderCallback = jasmine.createSpy('afterRenderCallback');
  304. hot.addHook('afterRender', afterRenderCallback);
  305. spec().$container.find('.ht_master .wtHolder').first().scrollTop(1000);
  306. await sleep(200);
  307. expect(afterRenderCallback.calls.count()).toBe(1);
  308. });
  309. it('should fire afterRender event after table physically rendered', async() => {
  310. spec().$container[0].style.width = '400px';
  311. spec().$container[0].style.height = '60px';
  312. spec().$container[0].style.overflow = 'hidden';
  313. const hot = handsontable({
  314. data: Handsontable.helper.createSpreadsheetData(20, 3)
  315. });
  316. hot.addHook('afterRender', () => {
  317. hot.view.wt.wtTable.holder.style.overflow = 'scroll';
  318. hot.view.wt.wtTable.holder.style.width = '220px';
  319. });
  320. spec().$container.find('.ht_master .wtHolder').first().scrollTop(1000);
  321. await sleep(100);
  322. // after afterRender hook triggered element style shouldn't changed
  323. expect(hot.view.wt.wtTable.holder.style.overflow).toBe('scroll');
  324. expect(hot.view.wt.wtTable.holder.style.width).toBe('220px');
  325. });
  326. // TODO fix these tests - https://github.com/handsontable/handsontable/issues/1559
  327. describe('maximumVisibleElementWidth', () => {
  328. it('should return maximum width until right edge of the viewport', () => {
  329. const hot = handsontable({
  330. startRows: 2,
  331. startCols: 10,
  332. width: 100,
  333. height: 100,
  334. });
  335. expect(hot.view.maximumVisibleElementWidth(0)).toEqual(100);
  336. });
  337. it('should return maximum width until right edge of the viewport (excluding the scrollbar)', () => {
  338. const hot = handsontable({
  339. startRows: 10,
  340. startCols: 10,
  341. width: 100,
  342. height: 100,
  343. });
  344. expect(hot.view.maximumVisibleElementWidth(200)).toBeLessThan(100);
  345. });
  346. });
  347. describe('maximumVisibleElementHeight', () => {
  348. it('should return maximum height until bottom edge of the viewport', () => {
  349. const hot = handsontable({
  350. startRows: 10,
  351. startCols: 2,
  352. width: 120,
  353. height: 100,
  354. });
  355. expect(hot.view.maximumVisibleElementHeight(0)).toEqual(100);
  356. });
  357. it('should return maximum height until bottom edge of the viewport (excluding the scrollbar)', () => {
  358. const hot = handsontable({
  359. startRows: 10,
  360. startCols: 10,
  361. width: 120,
  362. height: 100,
  363. });
  364. expect(hot.view.maximumVisibleElementHeight()).toBeLessThan(100);
  365. });
  366. });
  367. describe('fixed column row heights', () => {
  368. it('should be the same as the row heights in the main table', () => {
  369. const hot = handsontable({
  370. data: [['A', 'B', 'C', 'D'], ['a', 'b', 'c\nc', 'd'], ['aa', 'bb', 'cc', 'dd']],
  371. startRows: 3,
  372. startCols: 4,
  373. fixedColumnsLeft: 2,
  374. });
  375. expect(hot.getCell(1, 2).clientHeight).toEqual(hot.getCell(1, 1).clientHeight);
  376. hot.setDataAtCell(1, 2, 'c');
  377. expect(hot.getCell(1, 2).clientHeight).toEqual(hot.getCell(1, 1).clientHeight);
  378. });
  379. it('should be the same as the row heights in the main table (after scroll)', () => {
  380. const myData = Handsontable.helper.createSpreadsheetData(20, 4);
  381. myData[1][3] = 'very\nlong\ntext';
  382. myData[5][3] = 'very\nlong\ntext';
  383. myData[10][3] = 'very\nlong\ntext';
  384. myData[15][3] = 'very\nlong\ntext';
  385. const hot = handsontable({
  386. data: myData,
  387. startRows: 3,
  388. startCols: 4,
  389. fixedRowsTop: 2,
  390. fixedColumnsLeft: 2,
  391. width: 200,
  392. height: 200
  393. });
  394. const mainHolder = hot.view.wt.wtTable.holder;
  395. $(mainHolder).scrollTop(200);
  396. hot.render();
  397. const masterTD = spec().$container.find('.ht_master tbody tr:eq(5) td:eq(1)')[0];
  398. const cloneTD = spec().$container.find('.ht_clone_left tbody tr:eq(5) td:eq(1)')[0];
  399. expect(cloneTD.clientHeight).toEqual(masterTD.clientHeight);
  400. });
  401. it('should be the same as the row heights in the main table (after scroll, in corner)', () => {
  402. const myData = Handsontable.helper.createSpreadsheetData(20, 4);
  403. myData[1][3] = 'very\nlong\ntext';
  404. myData[5][3] = 'very\nlong\ntext';
  405. myData[10][3] = 'very\nlong\ntext';
  406. myData[15][3] = 'very\nlong\ntext';
  407. const hot = handsontable({
  408. data: myData,
  409. startRows: 3,
  410. startCols: 4,
  411. fixedRowsTop: 2,
  412. fixedColumnsLeft: 2,
  413. width: 200,
  414. height: 200
  415. });
  416. const rowHeight = hot.getCell(1, 3).clientHeight;
  417. const mainHolder = hot.view.wt.wtTable.holder;
  418. expect(spec().$container.find('.ht_clone_top_left_corner tbody tr:eq(1) td:eq(1)')[0].clientHeight).toEqual(rowHeight);
  419. $(mainHolder).scrollTop(200);
  420. hot.render();
  421. expect(spec().$container.find('.ht_clone_top_left_corner tbody tr:eq(1) td:eq(1)')[0].clientHeight).toEqual(rowHeight);
  422. });
  423. });
  424. describe('fixed column widths', () => {
  425. it('should set the columns width correctly after changes made during updateSettings', () => {
  426. const hot = handsontable({
  427. startRows: 2,
  428. fixedColumnsLeft: 2,
  429. columns: [{
  430. width: 50
  431. }, {
  432. width: 80
  433. }, {
  434. width: 110
  435. }, {
  436. width: 140
  437. }, {
  438. width: 30
  439. }, {
  440. width: 30
  441. }, {
  442. width: 30
  443. }]
  444. });
  445. const leftClone = spec().$container.find('.ht_clone_left');
  446. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  447. hot.updateSettings({
  448. manualColumnMove: [2, 0, 1],
  449. fixedColumnsLeft: 1
  450. });
  451. expect(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0]).toBe(undefined);
  452. hot.updateSettings({
  453. manualColumnMove: false,
  454. fixedColumnsLeft: 2
  455. });
  456. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  457. });
  458. it('should set the columns width correctly after changes made during updateSettings when columns is a function', () => {
  459. const hot = handsontable({
  460. startCols: 7,
  461. startRows: 2,
  462. fixedColumnsLeft: 2,
  463. columns(column) {
  464. let colMeta = {};
  465. if (column === 0) {
  466. colMeta.width = 50;
  467. } else if (column === 1) {
  468. colMeta.width = 80;
  469. } else if (column === 2) {
  470. colMeta.width = 110;
  471. } else if (column === 3) {
  472. colMeta.width = 140;
  473. } else if ([4, 5, 6].indexOf(column) > -1) {
  474. colMeta.width = 30;
  475. } else {
  476. colMeta = null;
  477. }
  478. return colMeta;
  479. }
  480. });
  481. const leftClone = spec().$container.find('.ht_clone_left');
  482. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  483. hot.updateSettings({
  484. manualColumnMove: [2, 0, 1],
  485. fixedColumnsLeft: 1
  486. });
  487. expect(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0]).toBe(undefined);
  488. hot.updateSettings({
  489. manualColumnMove: false,
  490. fixedColumnsLeft: 2
  491. });
  492. expect(Handsontable.dom.outerWidth(leftClone.find('tbody tr:nth-child(1) td:nth-child(2)')[0])).toEqual(80);
  493. });
  494. });
  495. describe('stretchH', () => {
  496. it('should stretch all visible columns with the ratio appropriate to the container\'s width', () => {
  497. spec().$container[0].style.width = '300px';
  498. const hot = handsontable({
  499. startRows: 5,
  500. startCols: 5,
  501. rowHeaders: true,
  502. colHeaders: true,
  503. stretchH: 'all'
  504. });
  505. const rowHeaderWidth = hot.view.wt.wtViewport.getRowHeaderWidth();
  506. let expectedCellWidth = (parseInt(spec().$container[0].style.width, 10) - rowHeaderWidth) / 5;
  507. expect(getCell(0, 0).offsetWidth).toEqual(expectedCellWidth);
  508. expect(getCell(0, 1).offsetWidth).toEqual(expectedCellWidth);
  509. expect(getCell(0, 2).offsetWidth).toEqual(expectedCellWidth);
  510. expect(getCell(0, 3).offsetWidth).toEqual(expectedCellWidth);
  511. expect(getCell(0, 4).offsetWidth).toEqual(expectedCellWidth);
  512. spec().$container[0].style.width = '';
  513. spec().$container.wrap('<div class="temp_wrapper" style="width:400px;"></div>');
  514. hot.render();
  515. expectedCellWidth = (parseInt($('.temp_wrapper')[0].style.width, 10) - rowHeaderWidth) / 5;
  516. expect(getCell(0, 0).offsetWidth).toEqual(expectedCellWidth);
  517. expect(getCell(0, 1).offsetWidth).toEqual(expectedCellWidth);
  518. expect(getCell(0, 2).offsetWidth).toEqual(expectedCellWidth);
  519. expect(getCell(0, 3).offsetWidth).toEqual(expectedCellWidth);
  520. expect(getCell(0, 4).offsetWidth).toEqual(expectedCellWidth);
  521. spec().$container.unwrap();
  522. });
  523. it('should stretch all visible columns with overflow hidden', () => {
  524. spec().$container[0].style.width = '501px';
  525. spec().$container[0].style.height = '100px';
  526. spec().$container[0].style.overflow = 'hidden';
  527. handsontable({
  528. startRows: 10,
  529. startCols: 5,
  530. colWidths: [47, 47, 47, 47, 47],
  531. rowHeaders: true,
  532. colHeaders: true,
  533. stretchH: 'all'
  534. });
  535. const masterTH = spec().$container[0].querySelectorAll('.ht_master thead tr th');
  536. const overlayTH = spec().$container[0].querySelectorAll('.ht_clone_top thead tr th');
  537. expect(masterTH[0].offsetWidth).toEqual(50);
  538. expect(overlayTH[0].offsetWidth).toEqual(50);
  539. expect(masterTH[1].offsetWidth).toBeInArray([86, 87, 88, 90]);
  540. expect(overlayTH[1].offsetWidth).toBeInArray([86, 87, 88, 90]); // if you get 90, it means it is calculated before scrollbars were applied, or show scroll on scrolling is enabled
  541. expect(masterTH[2].offsetWidth).toEqual(overlayTH[2].offsetWidth);
  542. expect(masterTH[3].offsetWidth).toEqual(overlayTH[3].offsetWidth);
  543. expect(masterTH[4].offsetWidth).toEqual(overlayTH[4].offsetWidth);
  544. expect(masterTH[5].offsetWidth).toEqual(overlayTH[5].offsetWidth);
  545. });
  546. it('should respect stretched widths returned in beforeStretchingColumnWidth hook', () => {
  547. spec().$container[0].style.width = '501px';
  548. spec().$container[0].style.height = '100px';
  549. spec().$container[0].style.overflow = 'hidden';
  550. const callbackSpy = jasmine.createSpy();
  551. callbackSpy.and.callFake((width, column) => {
  552. if (column === 1) {
  553. return 150;
  554. }
  555. return width;
  556. });
  557. handsontable({
  558. startRows: 2,
  559. startCols: 5,
  560. rowHeaders: true,
  561. colHeaders: true,
  562. stretchH: 'all',
  563. beforeStretchingColumnWidth: callbackSpy
  564. });
  565. const $columnHeaders = spec().$container.find('thead tr:eq(0) th');
  566. expect($columnHeaders.eq(0).width()).toEqual(48);
  567. expect($columnHeaders.eq(1).width()).toEqual(73);
  568. expect($columnHeaders.eq(2).width()).toEqual(149);
  569. expect($columnHeaders.eq(3).width()).toEqual(74);
  570. expect($columnHeaders.eq(4).width()).toEqual(74);
  571. expect(callbackSpy).toHaveBeenCalled();
  572. // First cycle to check what columns has permanent width
  573. expect(callbackSpy.calls.argsFor(0)[0]).not.toBeDefined();
  574. expect(callbackSpy.calls.argsFor(0)[1]).toBe(0);
  575. expect(callbackSpy.calls.argsFor(1)[0]).not.toBeDefined();
  576. expect(callbackSpy.calls.argsFor(1)[1]).toBe(1);
  577. expect(callbackSpy.calls.argsFor(2)[0]).not.toBeDefined();
  578. expect(callbackSpy.calls.argsFor(2)[1]).toBe(2);
  579. expect(callbackSpy.calls.argsFor(3)[0]).not.toBeDefined();
  580. expect(callbackSpy.calls.argsFor(3)[1]).toBe(3);
  581. expect(callbackSpy.calls.argsFor(4)[0]).not.toBeDefined();
  582. expect(callbackSpy.calls.argsFor(4)[1]).toBe(4);
  583. // // Second cycle retrieve stretched width or permanent width
  584. expect(callbackSpy.calls.argsFor(5)[0]).toBe(75);
  585. expect(callbackSpy.calls.argsFor(6)[0]).toBe(75);
  586. expect(callbackSpy.calls.argsFor(7)[0]).toBe(75);
  587. expect(callbackSpy.calls.argsFor(8)[0]).toBe(75);
  588. expect(callbackSpy.calls.argsFor(9)[0]).toBe(75);
  589. });
  590. });
  591. });