PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/test/jasmine/spec/Core_loadDataSpec.js

https://gitlab.com/e0/handsontable
JavaScript | 629 lines | 507 code | 108 blank | 14 comment | 36 complexity | c6fa620e3befe2b77962705611b51839 MD5 | raw file
  1. describe('Core_loadData', function () {
  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 arrayOfArrays = function () {
  13. return [
  14. ["", "Kia", "Nissan", "Toyota", "Honda"],
  15. ["2008", 10, 11, 12, 13],
  16. ["2009", 20, 11, 14, 13],
  17. ["2010", 30, 15, 12, 13]
  18. ];
  19. };
  20. var arrayOfObjects = function () {
  21. return [
  22. {id: 1, name: "Ted", lastName: "Right"},
  23. {id: 2, name: "Frank", lastName: "Honest"},
  24. {id: 3, name: "Joan", lastName: "Well"},
  25. {id: 4, name: "Sid", lastName: "Strong"},
  26. {id: 5, name: "Jane", lastName: "Neat"},
  27. {id: 6, name: "Chuck", lastName: "Jackson"},
  28. {id: 7, name: "Meg", lastName: "Jansen"},
  29. {id: 8, name: "Rob", lastName: "Norris"},
  30. {id: 9, name: "Sean", lastName: "O'Hara"},
  31. {id: 10, name: "Eve", lastName: "Branson"}
  32. ];
  33. };
  34. var arrayOfNestedObjects = function () {
  35. return [
  36. {
  37. id: 1,
  38. name: {
  39. first: "Ted",
  40. last: "Right"
  41. },
  42. 'full.street': 'Street I',
  43. },
  44. {
  45. id: 2,
  46. name: {
  47. first: "Frank",
  48. last: "Honest"
  49. },
  50. 'full.street': 'Street II',
  51. },
  52. {
  53. id: 3,
  54. name: {
  55. first: "Joan",
  56. last: "Well"
  57. },
  58. 'full.street': 'Street III',
  59. }
  60. ]
  61. };
  62. var htmlData = [
  63. ['<b>H&M</b>']
  64. ];
  65. it('should allow array of arrays', function () {
  66. handsontable();
  67. loadData(arrayOfArrays());
  68. expect(getDataAtCell(0, 2)).toEqual("Nissan");
  69. });
  70. it('should allow array of objects', function () {
  71. handsontable({
  72. columns: [
  73. {data: "id"},
  74. {data: "lastName"},
  75. {data: "name"}
  76. ]
  77. });
  78. loadData(arrayOfObjects());
  79. expect(getDataAtCell(0, 2)).toEqual("Ted");
  80. });
  81. it('should allow array of objects when columns as a function', function () {
  82. handsontable({
  83. columns: function(column) {
  84. var colMeta = {};
  85. if (column === 0) {
  86. colMeta.data = 'id';
  87. } else if (column === 1) {
  88. colMeta.data = 'lastName';
  89. } else if (column === 2) {
  90. colMeta.data = 'name';
  91. } else {
  92. colMeta = null;
  93. }
  94. return colMeta;
  95. }
  96. });
  97. loadData(arrayOfObjects());
  98. expect(getDataAtCell(0, 2)).toEqual("Ted");
  99. });
  100. it('should allow array of nested objects', function () {
  101. handsontable({
  102. data: arrayOfNestedObjects(),
  103. colHeaders: true,
  104. columns: [
  105. {data: "id"},
  106. {data: "name.last"},
  107. {data: "name.first"},
  108. {data: "full.street"},
  109. ]
  110. });
  111. expect(getDataAtCell(0, 2)).toEqual("Ted");
  112. expect(getDataAtCell(1, 3)).toEqual("Street II");
  113. expect(getDataAtRowProp(2, 'full.street')).toEqual("Street III");
  114. });
  115. it('should allow array of nested objects when columns as a function', function () {
  116. handsontable({
  117. data: arrayOfNestedObjects(),
  118. colHeaders: true,
  119. columns: function(column) {
  120. var colMeta = {};
  121. if (column === 0) {
  122. colMeta.data = 'id';
  123. } else if (column === 1) {
  124. colMeta.data = 'name.last';
  125. } else if (column === 2) {
  126. colMeta.data = 'name.first';
  127. } else if (column === 3) {
  128. colMeta.data = 'full.street';
  129. } else {
  130. colMeta = null;
  131. }
  132. return colMeta;
  133. }
  134. });
  135. expect(getDataAtCell(0, 2)).toEqual("Ted");
  136. expect(getDataAtCell(1, 3)).toEqual("Street II");
  137. expect(getDataAtRowProp(2, 'full.street')).toEqual("Street III");
  138. });
  139. it('should figure out default column names for array of nested objects', function () {
  140. handsontable({
  141. data: arrayOfNestedObjects(),
  142. colHeaders: true
  143. });
  144. expect(getDataAtCell(0, 2)).toEqual("Right");
  145. });
  146. it('should trigger onChange callback when loaded array of arrays', function () {
  147. var called = false;
  148. handsontable({
  149. afterChange: function (changes, source) {
  150. if (source === 'loadData') {
  151. called = true;
  152. }
  153. }
  154. });
  155. loadData(arrayOfArrays());
  156. expect(called).toEqual(true);
  157. });
  158. it('should trigger onChange callback when loaded array of objects', function () {
  159. var called = false;
  160. handsontable({
  161. afterChange: function (changes, source) {
  162. if (source === 'loadData') {
  163. called = true;
  164. }
  165. }
  166. });
  167. loadData(arrayOfObjects());
  168. expect(called).toEqual(true);
  169. });
  170. it('should trigger onChange callback when loaded array of nested objects', function () {
  171. var called = false;
  172. handsontable({
  173. afterChange: function (changes, source) {
  174. if (source === 'loadData') {
  175. called = true;
  176. }
  177. }
  178. });
  179. loadData(arrayOfNestedObjects());
  180. expect(called).toEqual(true);
  181. });
  182. it('should create new rows for array of arrays (and respect minRows)', function () {
  183. handsontable({
  184. minRows: 20, //minRows should be respected
  185. data: arrayOfArrays()
  186. });
  187. expect(countRows()).toEqual(20); //TODO why this must be checked after render?
  188. });
  189. it('should create new rows for array of nested objects (and respect minRows)', function () {
  190. handsontable({
  191. minRows: 20, //minRows should be respected
  192. data: arrayOfNestedObjects()
  193. });
  194. expect(countRows()).toEqual(20); //TODO why this must be checked after render?
  195. });
  196. it('HTML special chars should be escaped by default', function () {
  197. handsontable();
  198. loadData(htmlData);
  199. expect(getCell(0, 0).innerHTML).toEqual('&lt;b&gt;H&amp;M&lt;/b&gt;');
  200. });
  201. it('should create as many rows as needed by array of objects', function () {
  202. handsontable({
  203. minRows: 6,
  204. data: arrayOfObjects()
  205. });
  206. expect(getCell(9, 1).innerHTML).toEqual('Eve');
  207. });
  208. //https://github.com/handsontable/handsontable/pull/233
  209. it('should not invoke the cells callback multiple times with the same row/col (without overlays)', function () {
  210. var cellsSpy = jasmine.createSpy('cellsSpy');
  211. handsontable({
  212. data: arrayOfNestedObjects(),
  213. colWidths: [90, 90, 90, 90],
  214. rowHeights: [23, 23, 23, 23],
  215. cells: cellsSpy
  216. });
  217. //
  218. expect(cellsSpy.calls.length).toEqual(43);
  219. });
  220. it('should not invoke the cells callback multiple times with the same row/col (with overlays)', function () {
  221. var cellsSpy = jasmine.createSpy('cellsSpy');
  222. handsontable({
  223. data: arrayOfNestedObjects(),
  224. colHeaders: true,
  225. rowHeaders: true,
  226. colWidths: [90, 90, 90, 90],
  227. rowHeights: [90, 90, 90, 90],
  228. cells: cellsSpy
  229. });
  230. expect(cellsSpy.calls.length).toEqual(56);
  231. });
  232. it('should remove grid rows if new data source has less of them', function () {
  233. var data1 = [
  234. ["a"],
  235. ["b"],
  236. ["c"],
  237. ["d"],
  238. ["e"],
  239. ["f"],
  240. ["g"],
  241. ["h"]
  242. ];
  243. var data2 = [
  244. ["a"],
  245. ["b"],
  246. ["c"],
  247. ["d"],
  248. ["e"]
  249. ];
  250. handsontable({
  251. data: data1,
  252. rowHeaders: true,
  253. colHeaders: true
  254. });
  255. selectCell(7, 0);
  256. loadData(data2);
  257. expect(countRows()).toBe(data2.length);
  258. expect(getSelected()).toEqual([4, 0, 4, 0]);
  259. });
  260. it('should remove grid rows if new data source has less of them (with minSpareRows)', function () {
  261. var data1 = [
  262. ["a"],
  263. ["b"],
  264. ["c"],
  265. ["d"],
  266. ["e"],
  267. ["f"],
  268. ["g"],
  269. ["h"]
  270. ];
  271. var data2 = [
  272. ["a"],
  273. ["b"],
  274. ["c"],
  275. ["d"],
  276. ["e"]
  277. ];
  278. handsontable({
  279. data: data1,
  280. minSpareCols: 1,
  281. minSpareRows: 1,
  282. rowHeaders: true,
  283. colHeaders: true
  284. });
  285. selectCell(8, 0);
  286. loadData(data2);
  287. expect(countRows()).toBe(6); //+1 because of minSpareRows
  288. expect(getSelected()).toEqual([5, 0, 5, 0]);
  289. });
  290. it('loading empty data should remove all rows', function () {
  291. var data1 = [
  292. ["a"],
  293. ["b"],
  294. ["c"],
  295. ["d"],
  296. ["e"],
  297. ["f"],
  298. ["g"],
  299. ["h"]
  300. ];
  301. var data2 = [];
  302. handsontable({
  303. data: data1,
  304. rowHeaders: true,
  305. colHeaders: true
  306. });
  307. selectCell(7, 0);
  308. loadData(data2);
  309. expect(countRows()).toBe(0);
  310. expect(getSelected()).toEqual(null);
  311. });
  312. it('should only have as many columns as in settings', function () {
  313. var data1 = arrayOfArrays();
  314. handsontable({
  315. data: data1,
  316. columns: [
  317. { data: 1 },
  318. { data: 3 }
  319. ]
  320. });
  321. expect(countCols()).toBe(2);
  322. });
  323. it('should only have as many columns as in settings when columns is a function', function () {
  324. var data1 = arrayOfArrays();
  325. handsontable({
  326. data: data1,
  327. columns: function(column) {
  328. var colMeta = {
  329. data: column
  330. };
  331. if ([1, 3].indexOf(column) < 0) {
  332. colMeta = null
  333. }
  334. return colMeta;
  335. }
  336. });
  337. expect(countCols()).toBe(2);
  338. });
  339. it('should throw error when trying to load a string (constructor)', function () {
  340. var errors = 0;
  341. try {
  342. handsontable({
  343. data: "string"
  344. });
  345. }
  346. catch (e) {
  347. errors++;
  348. }
  349. expect(errors).toBe(1);
  350. });
  351. it('should throw error when trying to load a string (loadData)', function () {
  352. var errors = 0;
  353. try {
  354. handsontable();
  355. loadData("string");
  356. }
  357. catch (e) {
  358. errors++;
  359. }
  360. expect(errors).toBe(1);
  361. });
  362. it('should load Backbone Collection as data source', function () {
  363. // code borrowed from demo/backbone.js
  364. var CarModel = Backbone.Model.extend({});
  365. var CarCollection = Backbone.Collection.extend({
  366. model: CarModel,
  367. // Backbone.Collection doesn't support `splice`, yet! Easy to add.
  368. splice: hacked_splice
  369. });
  370. var cars = new CarCollection();
  371. cars.add([
  372. {make: "Dodge", model: "Ram", year: 2012, weight: 6811},
  373. {make: "Toyota", model: "Camry", year: 2012, weight: 3190},
  374. {make: "Smart", model: "Fortwo", year: 2012, weight: 1808}
  375. ]);
  376. handsontable({
  377. data: cars,
  378. columns: [
  379. attr("make"),
  380. attr("model"),
  381. attr("year")
  382. ]
  383. });
  384. // use the "good" Collection methods to emulate Array.splice
  385. function hacked_splice(index, howMany /* model1, ... modelN */) {
  386. var args = _.toArray(arguments).slice(2).concat({at: index}),
  387. removed = this.models.slice(index, index + howMany);
  388. this.remove(removed).add.apply(this, args);
  389. return removed;
  390. }
  391. // normally, you'd get these from the server with .fetch()
  392. function attr(attr) {
  393. // this lets us remember `attr` for when when it is get/set
  394. return {data: function (car, value) {
  395. if (_.isUndefined(value)) {
  396. return car.get(attr);
  397. }
  398. car.set(attr, value);
  399. }};
  400. }
  401. expect(countRows()).toBe(3);
  402. });
  403. it('should load Backbone Collection as data source when columns is a function', function () {
  404. // code borrowed from demo/backbone.js
  405. var CarModel = Backbone.Model.extend({});
  406. var CarCollection = Backbone.Collection.extend({
  407. model: CarModel,
  408. // Backbone.Collection doesn't support `splice`, yet! Easy to add.
  409. splice: hacked_splice
  410. });
  411. var cars = new CarCollection();
  412. cars.add([
  413. {make: "Dodge", model: "Ram", year: 2012, weight: 6811},
  414. {make: "Toyota", model: "Camry", year: 2012, weight: 3190},
  415. {make: "Smart", model: "Fortwo", year: 2012, weight: 1808}
  416. ]);
  417. handsontable({
  418. data: cars,
  419. columns: function(column) {
  420. var colMeta = null;
  421. if (column === 0) {
  422. colMeta = attr("make");
  423. } else if (column === 1) {
  424. colMeta = attr("model");
  425. } else if (column === 2) {
  426. colMeta = attr("year");
  427. }
  428. return colMeta;
  429. }
  430. });
  431. // use the "good" Collection methods to emulate Array.splice
  432. function hacked_splice(index, howMany /* model1, ... modelN */) {
  433. var args = _.toArray(arguments).slice(2).concat({at: index}),
  434. removed = this.models.slice(index, index + howMany);
  435. this.remove(removed).add.apply(this, args);
  436. return removed;
  437. }
  438. // normally, you'd get these from the server with .fetch()
  439. function attr(attr) {
  440. // this lets us remember `attr` for when when it is get/set
  441. return {data: function (car, value) {
  442. if (_.isUndefined(value)) {
  443. return car.get(attr);
  444. }
  445. car.set(attr, value);
  446. }};
  447. }
  448. expect(countRows()).toBe(3);
  449. });
  450. it('should clear cell properties after loadData', function () {
  451. handsontable();
  452. loadData(arrayOfArrays());
  453. getCellMeta(0, 0).foo = 'bar';
  454. expect(getCellMeta(0, 0).foo).toEqual("bar");
  455. loadData(arrayOfArrays());
  456. expect(getCellMeta(0, 0).foo).toBeUndefined();
  457. });
  458. it('should clear cell properties after loadData, but before rendering new data', function () {
  459. handsontable();
  460. loadData(arrayOfArrays());
  461. getCellMeta(0, 0).valid = false;
  462. render();
  463. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(true);
  464. loadData(arrayOfArrays());
  465. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').hasClass('htInvalid')).toEqual(false);
  466. });
  467. // https://github.com/handsontable/handsontable/issues/1700
  468. // can't edit anything after starting editing cell with no nested object
  469. it('should correct behave with cell with no nested object data source corresponding to column mapping', function () {
  470. var objectData = [
  471. {id: 1, user: {name: {first: "Ted", last: "Right"}}},
  472. {id: 2, user: {name: {}}},
  473. {id: 3}
  474. ];
  475. handsontable({
  476. data: objectData,
  477. columns: [
  478. {data: 'id'},
  479. {data: 'user.name.first'},
  480. {data: 'user.name.last'}
  481. ]
  482. });
  483. mouseDoubleClick(getCell(1, 1));
  484. document.activeElement.value = 'Harry';
  485. deselectCell();
  486. expect(objectData[1].user.name.first).toEqual('Harry');
  487. mouseDoubleClick(getCell(2, 1));
  488. document.activeElement.value = 'Barry';
  489. deselectCell();
  490. expect(objectData[2].user.name.first).toEqual('Barry');
  491. });
  492. it('should correct behave with cell with no nested object data source corresponding to column mapping when columns is a function', function () {
  493. var objectData = [
  494. {id: 1, user: {name: {first: "Ted", last: "Right"}}},
  495. {id: 2, user: {name: {}}},
  496. {id: 3}
  497. ];
  498. handsontable({
  499. data: objectData,
  500. columns: function(column) {
  501. var colMeta = null;
  502. if (column === 0) {
  503. colMeta = {data: 'id'}
  504. } else if (column === 1) {
  505. colMeta = {data: 'user.name.first'};
  506. } else if (column === 2) {
  507. colMeta = {data: 'user.name.last'};
  508. }
  509. return colMeta;
  510. }
  511. });
  512. mouseDoubleClick(getCell(1, 1));
  513. document.activeElement.value = 'Harry';
  514. deselectCell();
  515. expect(objectData[1].user.name.first).toEqual('Harry');
  516. mouseDoubleClick(getCell(2, 1));
  517. document.activeElement.value = 'Barry';
  518. deselectCell();
  519. expect(objectData[2].user.name.first).toEqual('Barry');
  520. });
  521. });