numericEditor.spec.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. describe('NumericEditor', () => {
  2. var 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. var arrayOfObjects = function() {
  13. return [
  14. {id: 1, name: 'Ted', lastName: 'Right'},
  15. {id: 2, name: 'Frank', lastName: 'Honest'},
  16. {id: 3, name: 'Joan', lastName: 'Well'},
  17. {id: 4, name: 'Sid', lastName: 'Strong'},
  18. {id: 5, name: 'Jane', lastName: 'Neat'},
  19. {id: 6, name: 'Chuck', lastName: 'Jackson'},
  20. {id: 7, name: 'Meg', lastName: 'Jansen'},
  21. {id: 8, name: 'Rob', lastName: 'Norris'},
  22. {id: 9, name: 'Sean', lastName: 'O\'Hara'},
  23. {id: 10, name: 'Eve', lastName: 'Branson'}
  24. ];
  25. };
  26. it('should convert numeric value to number (object data source)', (done) => {
  27. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  28. handsontable({
  29. data: arrayOfObjects(),
  30. columns: [
  31. {data: 'id', type: 'numeric'},
  32. {data: 'name'},
  33. {data: 'lastName'}
  34. ],
  35. afterValidate: onAfterValidate
  36. });
  37. selectCell(2, 0);
  38. keyDown('enter');
  39. document.activeElement.value = '999';
  40. destroyEditor();
  41. setTimeout(() => {
  42. expect(typeof getDataAtCell(2, 0)).toEqual('number');
  43. expect(getDataAtCell(2, 0)).toEqual(999);
  44. done();
  45. }, 100);
  46. });
  47. it('should apply changes to editor after validation', (done) => {
  48. handsontable({
  49. data: arrayOfObjects(),
  50. columns: [
  51. {data: 'id', type: 'numeric'},
  52. ]
  53. });
  54. selectCell(0, 0);
  55. keyDown('delete');
  56. setTimeout(() => {
  57. expect(getActiveEditor().originalValue).toEqual('');
  58. done();
  59. }, 100);
  60. });
  61. it('should allow custom validator', (done) => {
  62. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  63. handsontable({
  64. data: arrayOfObjects(),
  65. allowInvalid: false,
  66. columns: [
  67. {
  68. data: 'id',
  69. type: 'numeric',
  70. validator(val, cb) {
  71. cb(parseInt(val, 10) > 100);
  72. }
  73. },
  74. {data: 'name'},
  75. {data: 'lastName'}
  76. ],
  77. afterValidate: onAfterValidate
  78. });
  79. selectCell(2, 0);
  80. keyDown('enter');
  81. document.activeElement.value = '99';
  82. destroyEditor();
  83. setTimeout(() => {
  84. expect(getDataAtCell(2, 0)).not.toEqual(99); // should be ignored
  85. document.activeElement.value = '999';
  86. onAfterValidate.calls.reset();
  87. destroyEditor();
  88. }, 100);
  89. setTimeout(() => {
  90. expect(getDataAtCell(2, 0)).toEqual(999);
  91. done();
  92. }, 200);
  93. });
  94. it('should convert string in format \'XX.XX\' to a float with the same value', (done) => {
  95. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  96. handsontable({
  97. data: arrayOfObjects(),
  98. columns: [
  99. {data: 'id', type: 'numeric'},
  100. {data: 'name'},
  101. {data: 'lastName'}
  102. ],
  103. afterValidate: onAfterValidate
  104. });
  105. selectCell(2, 0);
  106. keyDown('enter');
  107. document.activeElement.value = '99.99';
  108. onAfterValidate.calls.reset();
  109. destroyEditor();
  110. setTimeout(() => {
  111. expect(getDataAtCell(2, 0)).toEqual(parseFloat(99.99));
  112. done();
  113. }, 100);
  114. });
  115. it('should convert string in format \'XX.XX\' to a float when passing float without leading zero', (done) => {
  116. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  117. handsontable({
  118. data: arrayOfObjects(),
  119. columns: [
  120. {data: 'id', type: 'numeric'},
  121. {data: 'name'},
  122. {data: 'lastName'}
  123. ],
  124. afterValidate: onAfterValidate
  125. });
  126. selectCell(2, 0);
  127. keyDown('enter');
  128. document.activeElement.value = '.74';
  129. onAfterValidate.calls.reset();
  130. destroyEditor();
  131. setTimeout(() => {
  132. expect(getDataAtCell(2, 0)).toEqual(parseFloat(0.74));
  133. done();
  134. }, 100);
  135. });
  136. it('should convert string in format \'XX,XX\' (with comma as separator) to a float with the same value if the numeric locale ' +
  137. 'specifies comma as the precision delimiter (language=de)', (done) => {
  138. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  139. handsontable({
  140. data: arrayOfObjects(),
  141. columns: [
  142. {data: 'id', type: 'numeric', language: 'de-DE'},
  143. {data: 'name'},
  144. {data: 'lastName'}
  145. ],
  146. afterValidate: onAfterValidate
  147. });
  148. selectCell(2, 0);
  149. keyDown('enter');
  150. document.activeElement.value = '99,99';
  151. onAfterValidate.calls.reset();
  152. destroyEditor();
  153. setTimeout(() => {
  154. expect(getDataAtCell(2, 0)).toEqual(parseFloat(99.99));
  155. done();
  156. }, 100);
  157. });
  158. it('should display a string in a format \'$X,XXX.XX\' when using language=en, appropriate format in column settings and \'XXXX.XX\' as ' +
  159. 'an input string', (done) => {
  160. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  161. handsontable({
  162. data: arrayOfObjects(),
  163. columns: [
  164. {data: 'id', type: 'numeric', format: '$0,0.00', language: 'en-US'},
  165. {data: 'name'},
  166. {data: 'lastName'}
  167. ],
  168. afterValidate: onAfterValidate
  169. });
  170. selectCell(2, 0);
  171. keyDown('enter');
  172. document.activeElement.value = '2456.22';
  173. onAfterValidate.calls.reset();
  174. destroyEditor();
  175. setTimeout(() => {
  176. expect(getCell(2, 0).innerHTML).toEqual('$2,456.22');
  177. done();
  178. }, 100);
  179. });
  180. it('should display a string in a format \'X.XXX,XX €\' when using language=de, appropriate format in column settings and \'XXXX,XX\' as an ' +
  181. 'input string (that comes from manual input)', (done) => {
  182. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  183. handsontable({
  184. data: arrayOfObjects(),
  185. columns: [
  186. {data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE'},
  187. {data: 'name'},
  188. {data: 'lastName'}
  189. ],
  190. afterValidate: onAfterValidate
  191. });
  192. selectCell(2, 0);
  193. keyDown('enter');
  194. document.activeElement.value = '2456,22';
  195. onAfterValidate.calls.reset();
  196. destroyEditor();
  197. setTimeout(() => {
  198. expect(getCell(2, 0).innerHTML).toEqual('2.456,22 €');
  199. done();
  200. }, 100);
  201. });
  202. it('should display a string in a format \'X.XXX,XX €\' when using language=de, appropriate format in column settings and \'XXXX.XX\' as an ' +
  203. 'input string (that comes from paste)', (done) => {
  204. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  205. handsontable({
  206. data: arrayOfObjects(),
  207. columns: [
  208. {data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE'},
  209. {data: 'name'},
  210. {data: 'lastName'}
  211. ],
  212. afterValidate: onAfterValidate
  213. });
  214. selectCell(2, 0);
  215. keyDown('enter');
  216. document.activeElement.value = '2456.22';
  217. onAfterValidate.calls.reset();
  218. destroyEditor();
  219. setTimeout(() => {
  220. expect(getCell(2, 0).innerHTML).toEqual('2.456,22 €');
  221. done();
  222. }, 100);
  223. });
  224. it('should not validate input values in different formats than \'XX.XX\' and \'XX,XX\'', (done) => {
  225. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  226. handsontable({
  227. data: arrayOfObjects(),
  228. columns: [
  229. {data: 'id', type: 'numeric'},
  230. {data: 'name'},
  231. {data: 'lastName'}
  232. ],
  233. afterValidate: onAfterValidate
  234. });
  235. selectCell(2, 0);
  236. function manuallySetValueTo(val) {
  237. keyDown('enter');
  238. document.activeElement.value = val;
  239. onAfterValidate.calls.reset();
  240. destroyEditor();
  241. }
  242. manuallySetValueTo('22.22');
  243. setTimeout(() => {
  244. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(false); // should validate alright
  245. manuallySetValueTo('2,000,000.22');
  246. }, 100);
  247. setTimeout(() => {
  248. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(true);
  249. manuallySetValueTo('11,11');
  250. }, 200);
  251. setTimeout(() => {
  252. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(false); // should validate alright
  253. manuallySetValueTo('one thounsand');
  254. }, 300);
  255. setTimeout(() => {
  256. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(true);
  257. manuallySetValueTo('99d99');
  258. }, 400);
  259. setTimeout(() => {
  260. expect($(getCell(2, 0)).hasClass('htInvalid')).toBe(true);
  261. done();
  262. }, 500);
  263. });
  264. it('should paste formatted data if source cell has format', (done) => {
  265. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  266. handsontable({
  267. data: arrayOfObjects(),
  268. columns: [
  269. {data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE'},
  270. {data: 'name'},
  271. {data: 'lastName'}
  272. ],
  273. afterValidate: onAfterValidate
  274. });
  275. selectCell(2, 0);
  276. keyDown('enter');
  277. document.activeElement.value = '€123,00';
  278. onAfterValidate.calls.reset();
  279. destroyEditor();
  280. setTimeout(() => {
  281. expect(getCell(2, 0).innerHTML).toEqual('123,00 €');
  282. done();
  283. }, 100);
  284. });
  285. it('should display a string in a format \'X XXX,XX €\' when using language=de, appropriate format in column settings and \'XXXX,XX\' as an ' +
  286. 'input string and ignore not needed zeros at the end', (done) => {
  287. var onAfterValidate = jasmine.createSpy('onAfterValidate');
  288. handsontable({
  289. data: [
  290. {id: 1, name: 'Ted', lastName: 'Right', money: 0},
  291. {id: 2, name: 'Frank', lastName: 'Honest', money: 0},
  292. {id: 3, name: 'Joan', lastName: 'Well', money: 0},
  293. {id: 4, name: 'Sid', lastName: 'Strong', money: 0},
  294. {id: 5, name: 'Jane', lastName: 'Neat', money: 0},
  295. {id: 6, name: 'Chuck', lastName: 'Jackson', money: 0},
  296. {id: 7, name: 'Meg', lastName: 'Jansen', money: 0},
  297. {id: 8, name: 'Rob', lastName: 'Norris', money: 0},
  298. {id: 9, name: 'Sean', lastName: 'O\'Hara', money: 0},
  299. {id: 10, name: 'Eve', lastName: 'Branson', money: 0}
  300. ],
  301. columns: [
  302. {data: 'id', type: 'numeric', format: '0,0.00 $', language: 'de-DE'},
  303. {data: 'name'},
  304. {data: 'lastName'},
  305. {data: 'money', type: 'numeric', format: '$0,0.00', language: 'en-US'}
  306. ],
  307. afterValidate: onAfterValidate
  308. });
  309. selectCell(2, 0);
  310. function manuallySetValueTo(val) {
  311. keyDown('enter');
  312. document.activeElement.value = val;
  313. onAfterValidate.calls.reset();
  314. destroyEditor();
  315. }
  316. manuallySetValueTo('2456,220');
  317. setTimeout(() => {
  318. expect(getCell(2, 0).innerHTML).toEqual('2.456,22 €');
  319. deselectCell();
  320. selectCell(2, 3);
  321. manuallySetValueTo('2456.220');
  322. }, 100);
  323. setTimeout(() => {
  324. expect(getCell(2, 3).innerHTML).toEqual('$2,456.22');
  325. done();
  326. }, 200);
  327. });
  328. it('should mark text as invalid without removing', (done) => {
  329. var hot = handsontable({
  330. data: arrayOfObjects(),
  331. columns: [
  332. {data: 'id', type: 'numeric', format: '0,0.00'},
  333. {data: 'name'},
  334. {data: 'lastName'}
  335. ],
  336. });
  337. hot.setDataAtCell(0, 0, 'abc');
  338. setTimeout(() => {
  339. expect(hot.getDataAtCell(0, 0)).toEqual('abc');
  340. done();
  341. }, 200);
  342. });
  343. it('should not throw error on closing editor when column data is defined as \'length\'', () => {
  344. hot = handsontable({
  345. data: [
  346. {length: 4},
  347. {length: 5},
  348. ],
  349. columns: [
  350. {
  351. data: 'length', type: 'numeric'
  352. },
  353. {},
  354. {}
  355. ]
  356. });
  357. selectCell(1, 0);
  358. keyDown('enter');
  359. document.activeElement.value = '999';
  360. expect(() => {
  361. destroyEditor();
  362. }).not.toThrow();
  363. });
  364. describe('Cell corner is showed properly when changing focused cells #3877', () => {
  365. var isFocusedCellDisplayingCornerTest = function(settings) {
  366. var moveFromRow = settings.moveFromRow;
  367. var moveFromCol = settings.moveFromCol;
  368. var moveToRow = settings.moveToRow;
  369. var moveToCol = settings.moveToCol;
  370. var doneFunc = settings.doneFunc;
  371. var $corner = settings.$container.find('.wtBorder.current.corner');
  372. selectCell(moveFromRow, moveFromCol);
  373. keyDown('enter');
  374. selectCell(moveToRow, moveToCol);
  375. setTimeout(() => {
  376. expect($corner.css('display')).toEqual('block');
  377. doneFunc();
  378. }, 100);
  379. };
  380. it('Moving from numeric editor to text editor', function(done) {
  381. handsontable({
  382. data: [
  383. {id: 1, name: 'Ted', lastName: 'Right', money: 0}
  384. ],
  385. columns: [
  386. {data: 'id'},
  387. {data: 'name'},
  388. {data: 'lastName'},
  389. {data: 'money', type: 'numeric', format: '$0,0.00', language: 'en-US'}
  390. ]
  391. });
  392. isFocusedCellDisplayingCornerTest({
  393. moveFromRow: 0,
  394. moveFromCol: 3,
  395. moveToRow: 0,
  396. moveToCol: 0,
  397. $container: this.$container,
  398. doneFunc: done
  399. });
  400. });
  401. it('Moving from text editor to numeric editor', function(done) {
  402. handsontable({
  403. data: [
  404. {id: 1, name: 'Ted', lastName: 'Right', money: 0}
  405. ],
  406. columns: [
  407. {data: 'id'},
  408. {data: 'name'},
  409. {data: 'lastName'},
  410. {data: 'money', type: 'numeric', format: '$0,0.00', language: 'en-US'}
  411. ]
  412. });
  413. isFocusedCellDisplayingCornerTest({
  414. moveFromRow: 0,
  415. moveFromCol: 1,
  416. moveToRow: 0,
  417. moveToCol: 3,
  418. $container: this.$container,
  419. doneFunc: done
  420. });
  421. });
  422. });
  423. });