blob: 321a476e82af8683e339ad708c29a02c307ade5c [file] [log] [blame]
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -07001/**
2 * © OpenCORD
3 *
4 * Created by teone on 3/24/16.
5 */
6
7(function () {
8 'use strict';
9
Matteo Scandolo8cd182a2016-05-06 09:42:45 -070010 var scope, element, isolatedScope, rootScope, compile;
11 const compileElement = () => {
12
13 if(!scope){
14 scope = rootScope.$new();
15 }
16
17 element = angular.element('<xos-table config="config" data="data"></xos-table>');
18 compile(element)(scope);
19 scope.$digest();
20 isolatedScope = element.isolateScope().vm;
21 }
22
23
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070024 describe('The xos.helper module', function(){
25 describe('The xos-table component', () => {
26
27 beforeEach(module('xos.helpers'));
28
Matteo Scandolo8cd182a2016-05-06 09:42:45 -070029 beforeEach(inject(function ($compile, $rootScope) {
30 compile = $compile;
31 rootScope = $rootScope;
32 }));
33
Matteo Scandolobe136072016-06-03 16:58:43 -070034 it('should throw an error if no config is specified', () => {
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070035 function errorFunctionWrapper(){
Matteo Scandolo8cd182a2016-05-06 09:42:45 -070036 compileElement();
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070037 }
38 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a configuration via the "config" attribute'));
Matteo Scandolobe136072016-06-03 16:58:43 -070039 });
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070040
Matteo Scandolobe136072016-06-03 16:58:43 -070041 it('should throw an error if no config columns are specified', () => {
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070042 function errorFunctionWrapper(){
43 // setup the parent scope
Matteo Scandolobe136072016-06-03 16:58:43 -070044 scope = rootScope.$new();
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070045 scope.config = 'green';
Matteo Scandolo8cd182a2016-05-06 09:42:45 -070046 compileElement();
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070047 }
48 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a columns list in the configuration'));
Matteo Scandolobe136072016-06-03 16:58:43 -070049 });
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070050
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -070051 describe('when basically configured', function() {
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070052
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070053 beforeEach(inject(function ($compile, $rootScope) {
Matteo Scandolo8cd182a2016-05-06 09:42:45 -070054
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070055 scope = $rootScope.$new();
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070056
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070057 scope.config = {
58 columns: [
59 {
60 label: 'Label 1',
61 prop: 'label-1'
62 },
63 {
64 label: 'Label 2',
65 prop: 'label-2'
66 }
67 ]
68 };
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070069
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070070 scope.data = [
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070071 {
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070072 'label-1': 'Sample 1.1',
73 'label-2': 'Sample 1.2'
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070074 },
75 {
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070076 'label-1': 'Sample 2.1',
77 'label-2': 'Sample 2.2'
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070078 }
79 ]
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070080
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070081 element = angular.element('<xos-table config="config" data="data"></xos-table>');
82 $compile(element)(scope);
83 scope.$digest();
84 isolatedScope = element.isolateScope().vm;
85 }));
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070086
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070087 it('should contain 2 columns', function() {
88 var th = element[0].getElementsByTagName('th');
89 expect(th.length).toEqual(2);
90 expect(isolatedScope.columns.length).toEqual(2);
91 });
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -070092
Matteo Scandolo6a6586e2016-04-14 16:52:13 -070093 it('should contain 3 rows', function() {
94 var tr = element[0].getElementsByTagName('tr');
95 expect(tr.length).toEqual(3);
96 });
97
Matteo Scandolo8cd182a2016-05-06 09:42:45 -070098 it('should render labels', () => {
99 let label1 = $(element).find('thead tr th')[0]
100 let label2 = $(element).find('thead tr th')[1]
101 expect($(label1).text().trim()).toEqual('Label 1');
102 expect($(label2).text().trim()).toEqual('Label 2');
103 });
104
Matteo Scandolofb5937d2016-04-15 14:27:54 -0700105 describe('when no data are provided', () => {
106 beforeEach(() => {
107 isolatedScope.data = [];
108 scope.$digest();
109 });
110 it('should render an alert', () => {
111 let alert = element[0].getElementsByClassName('alert');
112 let table = element[0].getElementsByTagName('table');
113 expect(alert.length).toEqual(1);
114 expect(table.length).toEqual(1);
115 });
116 });
117
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700118 describe('when a field type is provided', () => {
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700119 describe('and is boolean', () => {
120 beforeEach(() => {
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700121 scope.config = {
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700122 columns: [
123 {
124 label: 'Label 1',
125 prop: 'label-1',
126 type: 'boolean'
Matteo Scandolodee7c6c2016-06-14 17:26:51 -0700127 },
128 {
129 label: 'Label 2',
130 prop: 'label-2',
131 type: 'boolean'
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700132 }
133 ]
134 };
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700135 scope.data = [
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700136 {
Matteo Scandolodee7c6c2016-06-14 17:26:51 -0700137 'label-1': true,
138 'label-2': 1
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700139 },
140 {
Matteo Scandolodee7c6c2016-06-14 17:26:51 -0700141 'label-1': false,
142 'label-2': 0
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700143 }
144 ];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700145 compileElement();
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700146 });
147
148 it('should render an incon', () => {
149 let td1 = $(element).find('tbody tr:first-child td')[0];
150 let td2 = $(element).find('tbody tr:last-child td')[0];
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700151 expect($(td1).find('i')).toHaveClass('glyphicon-ok');
152 expect($(td2).find('i')).toHaveClass('glyphicon-remove');
153 });
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700154
155 describe('with field filters', () => {
156 beforeEach(() => {
157 scope.config.filter = 'field';
158 compileElement();
159 });
160
161 it('should render a dropdown for filtering', () => {
162 let td1 = $(element).find('table tbody tr td')[0];
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700163 expect(td1).toContainElement('select');
164 expect(td1).not.toContainElement('input');
165 });
Matteo Scandolodee7c6c2016-06-14 17:26:51 -0700166
167 it('should correctly filter results', () => {
168 isolatedScope.query = {
169 'label-1': false
170 };
171 scope.$digest();
172 expect(isolatedScope.query['label-1']).toBeFalsy();
173 var tr = $(element).find('tbody:last-child > tr');
174 var icon = $(tr[0]).find('td i');
175 expect(tr.length).toEqual(1);
176 expect(icon).toHaveClass('glyphicon-remove');
177 });
178
179 it('should correctly filter results if the field is in the form of 0|1', () => {
180 isolatedScope.query = {
181 'label-2': false
182 };
183 scope.$digest();
184 expect(isolatedScope.query['label-1']).toBeFalsy();
185 var tr = $(element).find('tbody:last-child > tr');
186 var icon = $(tr[0]).find('td i');
187 expect(tr.length).toEqual(1);
188 expect(icon).toHaveClass('glyphicon-remove');
189 });
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700190 });
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700191 });
192
193 describe('and is date', () => {
194 beforeEach(() => {
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700195 scope.config = {
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700196 columns: [
197 {
198 label: 'Label 1',
199 prop: 'label-1',
200 type: 'date'
201 }
202 ]
203 };
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700204 scope.data = [
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700205 {
206 'label-1': '2015-02-17T22:06:38.059000Z'
207 }
208 ];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700209 compileElement();
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700210 });
211
212 it('should render an formatted date', () => {
213 let td1 = $(element).find('tbody tr:first-child td')[0];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700214 expect($(td1).text().trim()).toEqual('14:06 Feb 17, 2015');
215 });
216 });
217
218 describe('and is array', () => {
219 beforeEach(() => {
220 scope.data = [
221 {categories: ['Film', 'Music']}
222 ];
223 scope.config = {
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -0700224 filter: 'field',
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700225 columns: [
226 {
227 label: 'Categories',
228 prop: 'categories',
229 type: 'array'
230 }
231 ]
232 }
233 compileElement();
234 });
235 it('should render a comma separated list', () => {
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -0700236 let td1 = $(element).find('tbody:last-child tr:first-child')[0];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700237 expect($(td1).text().trim()).toEqual('Film, Music');
238 });
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -0700239
240 it('should not render the filter field', () => {
241 let filter = $(element).find('tbody tr td')[0];
242 expect($(filter)).not.toContainElement('input');
243 });
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700244 });
245
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700246 describe('and is object', () => {
247 beforeEach(() => {
248 scope.data = [
249 {
250 attributes: {
251 age: 20,
252 height: 50
253 }
254 }
255 ];
256 scope.config = {
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -0700257 filter: 'field',
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700258 columns: [
259 {
260 label: 'Categories',
261 prop: 'attributes',
262 type: 'object'
263 }
264 ]
265 }
266 compileElement();
267 });
268 it('should render a list of key-values', () => {
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -0700269 let td = $(element).find('tbody:last-child tr:first-child')[0];
Matteo Scandolo7ebd1bf2016-05-06 11:39:56 -0700270 let ageLabel = $(td).find('dl dt')[0];
271 let ageValue = $(td).find('dl dd')[0];
272 let heightLabel = $(td).find('dl dt')[1];
273 let heightValue = $(td).find('dl dd')[1];
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700274 expect($(ageLabel).text().trim()).toEqual('age');
275 expect($(ageValue).text().trim()).toEqual('20');
276 expect($(heightLabel).text().trim()).toEqual('height');
277 expect($(heightValue).text().trim()).toEqual('50');
278 });
Matteo Scandolo1cbb96c2016-06-15 13:40:17 -0700279
280 it('should not render the filter field', () => {
281 let filter = $(element).find('tbody tr td')[0];
282 expect($(filter)).not.toContainElement('input');
283 });
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700284 });
285
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700286 describe('and is custom', () => {
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700287
288 let formatterFn = jasmine.createSpy('formatter').and.returnValue('Formatted Content');
289
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700290 beforeEach(() => {
291 scope.data = [
292 {categories: ['Film', 'Music']}
293 ];
294 scope.config = {
295 columns: [
296 {
297 label: 'Categories',
298 prop: 'categories',
299 type: 'custom',
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700300 formatter: formatterFn
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700301 }
302 ]
303 }
304 compileElement();
305 });
306
307 it('should check for a formatter property', () => {
308 function errorFunctionWrapper(){
309 // setup the parent scope
310 scope = rootScope.$new();
311 scope.config = {
312 columns: [
313 {
314 label: 'Categories',
315 prop: 'categories',
316 type: 'custom'
317 }
318 ]
319 };
320 compileElement();
321 }
322 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
323 });
324
Matteo Scandoloabb75622016-05-06 13:09:19 -0700325 it('should check that the formatter property is a function', () => {
326 function errorFunctionWrapper(){
327 // setup the parent scope
328 scope = rootScope.$new();
329 scope.config = {
330 columns: [
331 {
332 label: 'Categories',
333 prop: 'categories',
334 type: 'custom',
335 formatter: 'formatter'
336 }
337 ]
338 };
339 compileElement();
340 }
341 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
342 });
343
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700344 it('should format data using the formatter property', () => {
345 let td1 = $(element).find('tbody tr:first-child')[0];
346 expect($(td1).text().trim()).toEqual('Formatted Content');
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700347 // the custom formatted should receive the entire object, otherwise is not so custom
348 expect(formatterFn).toHaveBeenCalledWith({categories: ['Film', 'Music']});
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700349 });
350 });
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700351
352 describe('and is icon', () => {
353
354 beforeEach(() => {
355 scope.config = {
356 columns: [
357 {
358 label: 'Label 1',
359 prop: 'label-1',
360 type: 'icon',
361 formatter: item => {
362 switch (item['label-1']){
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700363 case 1:
364 return 'ok';
365 case 2:
366 return 'remove';
367 case 3:
368 return 'plus'
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700369 }
370 }
371 }
372 ]
373 };
374 scope.data = [
375 {
376 'label-1': 1
377 },
378 {
379 'label-1': 2
380 },
381 {
382 'label-1': 3
383 }
384 ];
385 compileElement();
386 });
387
388 it('should render a custom icon', () => {
389 let td1 = $(element).find('tbody tr:first-child td')[0];
390 let td2 = $(element).find('tbody tr:nth-child(2) td')[0];
391 let td3 = $(element).find('tbody tr:last-child td')[0];
392 expect($(td1).find('i')).toHaveClass('glyphicon-ok');
393 expect($(td2).find('i')).toHaveClass('glyphicon-remove');
394 expect($(td3).find('i')).toHaveClass('glyphicon-plus');
395 });
396 });
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700397 });
398
Matteo Scandoloabb75622016-05-06 13:09:19 -0700399 describe('when a link property is provided', () => {
400 beforeEach(() => {
401 scope.data = [
402 {
403 id: 1}
404 ];
405 scope.config = {
406 columns: [
407 {
408 label: 'Id',
409 prop: 'id',
410 link: (item) => {
411 return `/link/${item.id}`;
412 }
413 }
414 ]
415 }
416 compileElement();
417 });
418
419 it('should check that the link property is a function', () => {
420 function errorFunctionWrapper(){
421 // setup the parent scope
422 scope = rootScope.$new();
423 scope.config = {
424 columns: [
425 {
426 label: 'Categories',
427 prop: 'categories',
428 link: 'custom'
429 }
430 ]
431 };
432 compileElement();
433 }
434 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] The link property should be a function.'));
435 });
436
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700437 it('should render a link with the correct url', () => {
Matteo Scandoloabb75622016-05-06 13:09:19 -0700438 let link = $(element).find('tbody tr:first-child td a')[0];
439 expect($(link).attr('href')).toEqual('/link/1');
440 });
441 });
442
Matteo Scandolo6a6586e2016-04-14 16:52:13 -0700443 describe('when actions are passed', () => {
444
445 let cb = jasmine.createSpy('callback')
446
447 beforeEach(() => {
448 isolatedScope.config.actions = [
449 {
450 label: 'delete',
451 icon: 'remove',
452 cb: cb,
453 color: 'red'
454 }
455 ];
456 scope.$digest();
457 });
458
459 it('should have 3 columns', () => {
460 var th = element[0].getElementsByTagName('th');
461 expect(th.length).toEqual(3);
462 expect(isolatedScope.columns.length).toEqual(2);
463 });
464
465 it('when clicking on action should invoke callback', () => {
466 var link = element[0].getElementsByTagName('a')[0];
467 link.click();
468 expect(cb).toHaveBeenCalledWith(scope.data[0]);
469 });
470 });
471
472 describe('when filter is fulltext', () => {
473 beforeEach(() => {
474 isolatedScope.config.filter = 'fulltext';
475 scope.$digest();
476 });
477
478 it('should render a text field', () => {
479 var textField = element[0].getElementsByTagName('input');
480 expect(textField.length).toEqual(1);
481 });
482
483 describe('and a value is enterd', () => {
484 beforeEach(() => {
485 isolatedScope.query = '2.2';
486 scope.$digest();
487 });
488
489 it('should contain 2 rows', function() {
490 var tr = element[0].getElementsByTagName('tr');
491 expect(tr.length).toEqual(2);
492 });
493 });
494 });
495
496 describe('when filter is field', () => {
497 beforeEach(() => {
498 isolatedScope.config.filter = 'field';
499 scope.$digest();
500 });
501
502 it('should render a text field for each column', () => {
503 var textField = element[0].getElementsByTagName('input');
504 expect(textField.length).toEqual(2);
505 });
506
507 describe('and a value is enterd', () => {
508 beforeEach(() => {
509 isolatedScope.query = {'label-1': '2.1'};
510 scope.$digest();
511 });
512
513 it('should contain 3 rows', function() {
514 var tr = element[0].getElementsByTagName('tr');
515 expect(tr.length).toEqual(3);
516 });
517 });
518 });
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700519
520 describe('when order is true', () => {
521 beforeEach(() => {
522 isolatedScope.config.order = true;
523 scope.$digest();
524 });
525
526 it('should render a arrows beside', () => {
527 var arrows = element[0].getElementsByTagName('i');
528 expect(arrows.length).toEqual(4);
529 });
530
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700531 describe('and a default ordering is passed', () => {
532
533 beforeEach(() => {
534 scope.config.order = {
535 field: 'label-1',
536 reverse: true
537 };
538 compileElement();
539 });
540
541 it('should orderBy the default order', () => {
542 var tr = $(element).find('tr');
543 expect($(tr[1]).text()).toContain('Sample 2.2');
544 expect($(tr[2]).text()).toContain('Sample 1.1');
545 });
546 });
547
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700548 describe('and an order is set', () => {
549 beforeEach(() => {
550 isolatedScope.orderBy = 'label-1';
551 isolatedScope.reverse = true;
552 scope.$digest();
553 });
554
555 it('should orderBy', function() {
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700556 // console.log($(element).find('table'));
Matteo Scandoloabb75622016-05-06 13:09:19 -0700557 var tr = $(element).find('tr');
558 expect($(tr[1]).text()).toContain('Sample 2.2');
559 expect($(tr[2]).text()).toContain('Sample 1.1');
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700560 });
561 });
562 });
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -0700563 });
564 });
565 });
566})();
567