blob: 2ec80066252b3332c919bd917b8e92e31549444f [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 Scandolo6a6586e2016-04-14 16:52:13 -070051 describe('when basicly 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 = {
224 columns: [
225 {
226 label: 'Categories',
227 prop: 'categories',
228 type: 'array'
229 }
230 ]
231 }
232 compileElement();
233 });
234 it('should render a comma separated list', () => {
235 let td1 = $(element).find('tbody tr:first-child')[0];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700236 expect($(td1).text().trim()).toEqual('Film, Music');
237 });
238 });
239
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700240 describe('and is object', () => {
241 beforeEach(() => {
242 scope.data = [
243 {
244 attributes: {
245 age: 20,
246 height: 50
247 }
248 }
249 ];
250 scope.config = {
251 columns: [
252 {
253 label: 'Categories',
254 prop: 'attributes',
255 type: 'object'
256 }
257 ]
258 }
259 compileElement();
260 });
261 it('should render a list of key-values', () => {
262 let td = $(element).find('tbody tr:first-child')[0];
Matteo Scandolo7ebd1bf2016-05-06 11:39:56 -0700263 let ageLabel = $(td).find('dl dt')[0];
264 let ageValue = $(td).find('dl dd')[0];
265 let heightLabel = $(td).find('dl dt')[1];
266 let heightValue = $(td).find('dl dd')[1];
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700267 expect($(ageLabel).text().trim()).toEqual('age');
268 expect($(ageValue).text().trim()).toEqual('20');
269 expect($(heightLabel).text().trim()).toEqual('height');
270 expect($(heightValue).text().trim()).toEqual('50');
271 });
272 });
273
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700274 describe('and is custom', () => {
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700275
276 let formatterFn = jasmine.createSpy('formatter').and.returnValue('Formatted Content');
277
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700278 beforeEach(() => {
279 scope.data = [
280 {categories: ['Film', 'Music']}
281 ];
282 scope.config = {
283 columns: [
284 {
285 label: 'Categories',
286 prop: 'categories',
287 type: 'custom',
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700288 formatter: formatterFn
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700289 }
290 ]
291 }
292 compileElement();
293 });
294
295 it('should check for a formatter property', () => {
296 function errorFunctionWrapper(){
297 // setup the parent scope
298 scope = rootScope.$new();
299 scope.config = {
300 columns: [
301 {
302 label: 'Categories',
303 prop: 'categories',
304 type: 'custom'
305 }
306 ]
307 };
308 compileElement();
309 }
310 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
311 });
312
Matteo Scandoloabb75622016-05-06 13:09:19 -0700313 it('should check that the formatter property is a function', () => {
314 function errorFunctionWrapper(){
315 // setup the parent scope
316 scope = rootScope.$new();
317 scope.config = {
318 columns: [
319 {
320 label: 'Categories',
321 prop: 'categories',
322 type: 'custom',
323 formatter: 'formatter'
324 }
325 ]
326 };
327 compileElement();
328 }
329 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
330 });
331
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700332 it('should format data using the formatter property', () => {
333 let td1 = $(element).find('tbody tr:first-child')[0];
334 expect($(td1).text().trim()).toEqual('Formatted Content');
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700335 // the custom formatted should receive the entire object, otherwise is not so custom
336 expect(formatterFn).toHaveBeenCalledWith({categories: ['Film', 'Music']});
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700337 });
338 });
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700339
340 describe('and is icon', () => {
341
342 beforeEach(() => {
343 scope.config = {
344 columns: [
345 {
346 label: 'Label 1',
347 prop: 'label-1',
348 type: 'icon',
349 formatter: item => {
350 switch (item['label-1']){
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700351 case 1:
352 return 'ok';
353 case 2:
354 return 'remove';
355 case 3:
356 return 'plus'
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700357 }
358 }
359 }
360 ]
361 };
362 scope.data = [
363 {
364 'label-1': 1
365 },
366 {
367 'label-1': 2
368 },
369 {
370 'label-1': 3
371 }
372 ];
373 compileElement();
374 });
375
376 it('should render a custom icon', () => {
377 let td1 = $(element).find('tbody tr:first-child td')[0];
378 let td2 = $(element).find('tbody tr:nth-child(2) td')[0];
379 let td3 = $(element).find('tbody tr:last-child td')[0];
380 expect($(td1).find('i')).toHaveClass('glyphicon-ok');
381 expect($(td2).find('i')).toHaveClass('glyphicon-remove');
382 expect($(td3).find('i')).toHaveClass('glyphicon-plus');
383 });
384 });
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700385 });
386
Matteo Scandoloabb75622016-05-06 13:09:19 -0700387 describe('when a link property is provided', () => {
388 beforeEach(() => {
389 scope.data = [
390 {
391 id: 1}
392 ];
393 scope.config = {
394 columns: [
395 {
396 label: 'Id',
397 prop: 'id',
398 link: (item) => {
399 return `/link/${item.id}`;
400 }
401 }
402 ]
403 }
404 compileElement();
405 });
406
407 it('should check that the link property is a function', () => {
408 function errorFunctionWrapper(){
409 // setup the parent scope
410 scope = rootScope.$new();
411 scope.config = {
412 columns: [
413 {
414 label: 'Categories',
415 prop: 'categories',
416 link: 'custom'
417 }
418 ]
419 };
420 compileElement();
421 }
422 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] The link property should be a function.'));
423 });
424
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700425 it('should render a link with the correct url', () => {
Matteo Scandoloabb75622016-05-06 13:09:19 -0700426 let link = $(element).find('tbody tr:first-child td a')[0];
427 expect($(link).attr('href')).toEqual('/link/1');
428 });
429 });
430
Matteo Scandolo6a6586e2016-04-14 16:52:13 -0700431 describe('when actions are passed', () => {
432
433 let cb = jasmine.createSpy('callback')
434
435 beforeEach(() => {
436 isolatedScope.config.actions = [
437 {
438 label: 'delete',
439 icon: 'remove',
440 cb: cb,
441 color: 'red'
442 }
443 ];
444 scope.$digest();
445 });
446
447 it('should have 3 columns', () => {
448 var th = element[0].getElementsByTagName('th');
449 expect(th.length).toEqual(3);
450 expect(isolatedScope.columns.length).toEqual(2);
451 });
452
453 it('when clicking on action should invoke callback', () => {
454 var link = element[0].getElementsByTagName('a')[0];
455 link.click();
456 expect(cb).toHaveBeenCalledWith(scope.data[0]);
457 });
458 });
459
460 describe('when filter is fulltext', () => {
461 beforeEach(() => {
462 isolatedScope.config.filter = 'fulltext';
463 scope.$digest();
464 });
465
466 it('should render a text field', () => {
467 var textField = element[0].getElementsByTagName('input');
468 expect(textField.length).toEqual(1);
469 });
470
471 describe('and a value is enterd', () => {
472 beforeEach(() => {
473 isolatedScope.query = '2.2';
474 scope.$digest();
475 });
476
477 it('should contain 2 rows', function() {
478 var tr = element[0].getElementsByTagName('tr');
479 expect(tr.length).toEqual(2);
480 });
481 });
482 });
483
484 describe('when filter is field', () => {
485 beforeEach(() => {
486 isolatedScope.config.filter = 'field';
487 scope.$digest();
488 });
489
490 it('should render a text field for each column', () => {
491 var textField = element[0].getElementsByTagName('input');
492 expect(textField.length).toEqual(2);
493 });
494
495 describe('and a value is enterd', () => {
496 beforeEach(() => {
497 isolatedScope.query = {'label-1': '2.1'};
498 scope.$digest();
499 });
500
501 it('should contain 3 rows', function() {
502 var tr = element[0].getElementsByTagName('tr');
503 expect(tr.length).toEqual(3);
504 });
505 });
506 });
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700507
508 describe('when order is true', () => {
509 beforeEach(() => {
510 isolatedScope.config.order = true;
511 scope.$digest();
512 });
513
514 it('should render a arrows beside', () => {
515 var arrows = element[0].getElementsByTagName('i');
516 expect(arrows.length).toEqual(4);
517 });
518
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700519 describe('and a default ordering is passed', () => {
520
521 beforeEach(() => {
522 scope.config.order = {
523 field: 'label-1',
524 reverse: true
525 };
526 compileElement();
527 });
528
529 it('should orderBy the default order', () => {
530 var tr = $(element).find('tr');
531 expect($(tr[1]).text()).toContain('Sample 2.2');
532 expect($(tr[2]).text()).toContain('Sample 1.1');
533 });
534 });
535
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700536 describe('and an order is set', () => {
537 beforeEach(() => {
538 isolatedScope.orderBy = 'label-1';
539 isolatedScope.reverse = true;
540 scope.$digest();
541 });
542
543 it('should orderBy', function() {
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700544 // console.log($(element).find('table'));
Matteo Scandoloabb75622016-05-06 13:09:19 -0700545 var tr = $(element).find('tr');
546 expect($(tr[1]).text()).toContain('Sample 2.2');
547 expect($(tr[2]).text()).toContain('Sample 1.1');
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700548 });
549 });
550 });
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -0700551 });
552 });
553 });
554})();
555