blob: f87eb960036de09170e488b2e6bf872891f22cee [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 Scandoloa7e64fd2016-04-14 14:59:09 -070034 it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
35 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'));
39 }));
40
41 it('should throw an error if no config columns are specified', inject(($compile, $rootScope) => {
42 function errorFunctionWrapper(){
43 // setup the parent scope
Matteo Scandolo8cd182a2016-05-06 09:42:45 -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'));
49 }));
50
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'
127 }
128 ]
129 };
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700130 scope.data = [
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700131 {
132 'label-1': true
133 },
134 {
135 'label-1': false
136 }
137 ];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700138 compileElement();
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700139 });
140
141 it('should render an incon', () => {
142 let td1 = $(element).find('tbody tr:first-child td')[0];
143 let td2 = $(element).find('tbody tr:last-child td')[0];
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700144 expect($(td1).find('i')).toHaveClass('glyphicon-ok');
145 expect($(td2).find('i')).toHaveClass('glyphicon-remove');
146 });
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700147
148 describe('with field filters', () => {
149 beforeEach(() => {
150 scope.config.filter = 'field';
151 compileElement();
152 });
153
154 it('should render a dropdown for filtering', () => {
155 let td1 = $(element).find('table tbody tr td')[0];
156 console.log(td1);
157 expect(td1).toContainElement('select');
158 expect(td1).not.toContainElement('input');
159 });
160 });
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700161 });
162
163 describe('and is date', () => {
164 beforeEach(() => {
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700165 scope.config = {
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700166 columns: [
167 {
168 label: 'Label 1',
169 prop: 'label-1',
170 type: 'date'
171 }
172 ]
173 };
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700174 scope.data = [
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700175 {
176 'label-1': '2015-02-17T22:06:38.059000Z'
177 }
178 ];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700179 compileElement();
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700180 });
181
182 it('should render an formatted date', () => {
183 let td1 = $(element).find('tbody tr:first-child td')[0];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700184 expect($(td1).text().trim()).toEqual('14:06 Feb 17, 2015');
185 });
186 });
187
188 describe('and is array', () => {
189 beforeEach(() => {
190 scope.data = [
191 {categories: ['Film', 'Music']}
192 ];
193 scope.config = {
194 columns: [
195 {
196 label: 'Categories',
197 prop: 'categories',
198 type: 'array'
199 }
200 ]
201 }
202 compileElement();
203 });
204 it('should render a comma separated list', () => {
205 let td1 = $(element).find('tbody tr:first-child')[0];
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700206 expect($(td1).text().trim()).toEqual('Film, Music');
207 });
208 });
209
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700210 describe('and is object', () => {
211 beforeEach(() => {
212 scope.data = [
213 {
214 attributes: {
215 age: 20,
216 height: 50
217 }
218 }
219 ];
220 scope.config = {
221 columns: [
222 {
223 label: 'Categories',
224 prop: 'attributes',
225 type: 'object'
226 }
227 ]
228 }
229 compileElement();
230 });
231 it('should render a list of key-values', () => {
232 let td = $(element).find('tbody tr:first-child')[0];
Matteo Scandolo7ebd1bf2016-05-06 11:39:56 -0700233 let ageLabel = $(td).find('dl dt')[0];
234 let ageValue = $(td).find('dl dd')[0];
235 let heightLabel = $(td).find('dl dt')[1];
236 let heightValue = $(td).find('dl dd')[1];
Matteo Scandoloe5d74562016-05-06 10:08:34 -0700237 expect($(ageLabel).text().trim()).toEqual('age');
238 expect($(ageValue).text().trim()).toEqual('20');
239 expect($(heightLabel).text().trim()).toEqual('height');
240 expect($(heightValue).text().trim()).toEqual('50');
241 });
242 });
243
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700244 describe('and is custom', () => {
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700245
246 let formatterFn = jasmine.createSpy('formatter').and.returnValue('Formatted Content');
247
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700248 beforeEach(() => {
249 scope.data = [
250 {categories: ['Film', 'Music']}
251 ];
252 scope.config = {
253 columns: [
254 {
255 label: 'Categories',
256 prop: 'categories',
257 type: 'custom',
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700258 formatter: formatterFn
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700259 }
260 ]
261 }
262 compileElement();
263 });
264
265 it('should check for a formatter property', () => {
266 function errorFunctionWrapper(){
267 // setup the parent scope
268 scope = rootScope.$new();
269 scope.config = {
270 columns: [
271 {
272 label: 'Categories',
273 prop: 'categories',
274 type: 'custom'
275 }
276 ]
277 };
278 compileElement();
279 }
280 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
281 });
282
Matteo Scandoloabb75622016-05-06 13:09:19 -0700283 it('should check that the formatter property is a function', () => {
284 function errorFunctionWrapper(){
285 // setup the parent scope
286 scope = rootScope.$new();
287 scope.config = {
288 columns: [
289 {
290 label: 'Categories',
291 prop: 'categories',
292 type: 'custom',
293 formatter: 'formatter'
294 }
295 ]
296 };
297 compileElement();
298 }
299 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
300 });
301
Matteo Scandolo8cd182a2016-05-06 09:42:45 -0700302 it('should format data using the formatter property', () => {
303 let td1 = $(element).find('tbody tr:first-child')[0];
304 expect($(td1).text().trim()).toEqual('Formatted Content');
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700305 // the custom formatted should receive the entire object, otherwise is not so custom
306 expect(formatterFn).toHaveBeenCalledWith({categories: ['Film', 'Music']});
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700307 });
308 });
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700309
310 describe('and is icon', () => {
311
312 beforeEach(() => {
313 scope.config = {
314 columns: [
315 {
316 label: 'Label 1',
317 prop: 'label-1',
318 type: 'icon',
319 formatter: item => {
320 switch (item['label-1']){
Matteo Scandoloa31617e2016-05-18 14:57:56 -0700321 case 1:
322 return 'ok';
323 case 2:
324 return 'remove';
325 case 3:
326 return 'plus'
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700327 }
328 }
329 }
330 ]
331 };
332 scope.data = [
333 {
334 'label-1': 1
335 },
336 {
337 'label-1': 2
338 },
339 {
340 'label-1': 3
341 }
342 ];
343 compileElement();
344 });
345
346 it('should render a custom icon', () => {
347 let td1 = $(element).find('tbody tr:first-child td')[0];
348 let td2 = $(element).find('tbody tr:nth-child(2) td')[0];
349 let td3 = $(element).find('tbody tr:last-child td')[0];
350 expect($(td1).find('i')).toHaveClass('glyphicon-ok');
351 expect($(td2).find('i')).toHaveClass('glyphicon-remove');
352 expect($(td3).find('i')).toHaveClass('glyphicon-plus');
353 });
354 });
Matteo Scandolo250a29c2016-04-27 17:26:21 -0700355 });
356
Matteo Scandoloabb75622016-05-06 13:09:19 -0700357 describe('when a link property is provided', () => {
358 beforeEach(() => {
359 scope.data = [
360 {
361 id: 1}
362 ];
363 scope.config = {
364 columns: [
365 {
366 label: 'Id',
367 prop: 'id',
368 link: (item) => {
369 return `/link/${item.id}`;
370 }
371 }
372 ]
373 }
374 compileElement();
375 });
376
377 it('should check that the link property is a function', () => {
378 function errorFunctionWrapper(){
379 // setup the parent scope
380 scope = rootScope.$new();
381 scope.config = {
382 columns: [
383 {
384 label: 'Categories',
385 prop: 'categories',
386 link: 'custom'
387 }
388 ]
389 };
390 compileElement();
391 }
392 expect(errorFunctionWrapper).toThrow(new Error('[xosTable] The link property should be a function.'));
393 });
394
Matteo Scandolob4fdd0a2016-05-09 15:27:47 -0700395 it('should render a link with the correct url', () => {
Matteo Scandoloabb75622016-05-06 13:09:19 -0700396 let link = $(element).find('tbody tr:first-child td a')[0];
397 expect($(link).attr('href')).toEqual('/link/1');
398 });
399 });
400
Matteo Scandolo6a6586e2016-04-14 16:52:13 -0700401 describe('when actions are passed', () => {
402
403 let cb = jasmine.createSpy('callback')
404
405 beforeEach(() => {
406 isolatedScope.config.actions = [
407 {
408 label: 'delete',
409 icon: 'remove',
410 cb: cb,
411 color: 'red'
412 }
413 ];
414 scope.$digest();
415 });
416
417 it('should have 3 columns', () => {
418 var th = element[0].getElementsByTagName('th');
419 expect(th.length).toEqual(3);
420 expect(isolatedScope.columns.length).toEqual(2);
421 });
422
423 it('when clicking on action should invoke callback', () => {
424 var link = element[0].getElementsByTagName('a')[0];
425 link.click();
426 expect(cb).toHaveBeenCalledWith(scope.data[0]);
427 });
428 });
429
430 describe('when filter is fulltext', () => {
431 beforeEach(() => {
432 isolatedScope.config.filter = 'fulltext';
433 scope.$digest();
434 });
435
436 it('should render a text field', () => {
437 var textField = element[0].getElementsByTagName('input');
438 expect(textField.length).toEqual(1);
439 });
440
441 describe('and a value is enterd', () => {
442 beforeEach(() => {
443 isolatedScope.query = '2.2';
444 scope.$digest();
445 });
446
447 it('should contain 2 rows', function() {
448 var tr = element[0].getElementsByTagName('tr');
449 expect(tr.length).toEqual(2);
450 });
451 });
452 });
453
454 describe('when filter is field', () => {
455 beforeEach(() => {
456 isolatedScope.config.filter = 'field';
457 scope.$digest();
458 });
459
460 it('should render a text field for each column', () => {
461 var textField = element[0].getElementsByTagName('input');
462 expect(textField.length).toEqual(2);
463 });
464
465 describe('and a value is enterd', () => {
466 beforeEach(() => {
467 isolatedScope.query = {'label-1': '2.1'};
468 scope.$digest();
469 });
470
471 it('should contain 3 rows', function() {
472 var tr = element[0].getElementsByTagName('tr');
473 expect(tr.length).toEqual(3);
474 });
475 });
476 });
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700477
478 describe('when order is true', () => {
479 beforeEach(() => {
480 isolatedScope.config.order = true;
481 scope.$digest();
482 });
483
484 it('should render a arrows beside', () => {
485 var arrows = element[0].getElementsByTagName('i');
486 expect(arrows.length).toEqual(4);
487 });
488
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700489 describe('and a default ordering is passed', () => {
490
491 beforeEach(() => {
492 scope.config.order = {
493 field: 'label-1',
494 reverse: true
495 };
496 compileElement();
497 });
498
499 it('should orderBy the default order', () => {
500 var tr = $(element).find('tr');
501 expect($(tr[1]).text()).toContain('Sample 2.2');
502 expect($(tr[2]).text()).toContain('Sample 1.1');
503 });
504 });
505
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700506 describe('and an order is set', () => {
507 beforeEach(() => {
508 isolatedScope.orderBy = 'label-1';
509 isolatedScope.reverse = true;
510 scope.$digest();
511 });
512
513 it('should orderBy', function() {
Matteo Scandoloea6ef002016-05-13 10:12:09 -0700514 // console.log($(element).find('table'));
Matteo Scandoloabb75622016-05-06 13:09:19 -0700515 var tr = $(element).find('tr');
516 expect($(tr[1]).text()).toContain('Sample 2.2');
517 expect($(tr[2]).text()).toContain('Sample 1.1');
Matteo Scandolof32a2e92016-04-14 17:19:08 -0700518 });
519 });
520 });
Matteo Scandoloa7e64fd2016-04-14 14:59:09 -0700521 });
522 });
523 });
524})();
525