Merge pull request #15541 from ixiam/dev_issue#1324
[civicrm-core.git] / tests / karma / unit / crmCaseTypeSpec.js
CommitLineData
384f015c 1/* global $, _, CRM:true */
416abe87
PH
2'use strict';
3
4describe('crmCaseType', function() {
b109dd8b
RO
5 var $controller;
6 var $compile;
7 var $httpBackend;
c9817fac 8 var $q;
b109dd8b 9 var $rootScope;
d7a470db 10 var $timeout;
b109dd8b
RO
11 var apiCalls;
12 var ctrl;
13 var compile;
ad8d1ce3 14 var defaultAssigneeDefaultValue;
b109dd8b 15 var scope;
416abe87
PH
16
17 beforeEach(function() {
18 CRM.resourceUrls = {
19 'civicrm': ''
20 };
416abe87 21 module('crmCaseType');
09a09949
PH
22 module('crmJsonComparator');
23 inject(function(crmJsonComparator) {
24 crmJsonComparator.register(jasmine);
416abe87
PH
25 });
26 });
27
d7a470db 28 beforeEach(inject(function(_$controller_, _$compile_, _$httpBackend_, _$q_, _$rootScope_, _$timeout_) {
b109dd8b
RO
29 $controller = _$controller_;
30 $compile = _$compile_;
31 $httpBackend = _$httpBackend_;
c9817fac 32 $q = _$q_;
b109dd8b 33 $rootScope = _$rootScope_;
d7a470db 34 $timeout = _$timeout_;
b109dd8b 35 }));
416abe87 36
b109dd8b
RO
37 describe('CaseTypeCtrl', function() {
38 beforeEach(function () {
416abe87 39 apiCalls = {
4324b8d7
CW
40 actStatuses: {
41 values: [
42 {
416abe87
PH
43 "id": "272",
44 "option_group_id": "25",
45 "label": "Scheduled",
46 "value": "1",
47 "name": "Scheduled",
48 "filter": "0",
49 "is_default": "1",
50 "weight": "1",
51 "is_optgroup": "0",
52 "is_reserved": "1",
53 "is_active": "1"
54 },
4324b8d7 55 {
416abe87
PH
56 "id": "273",
57 "option_group_id": "25",
58 "label": "Completed",
59 "value": "2",
60 "name": "Completed",
61 "filter": "0",
62 "weight": "2",
63 "is_optgroup": "0",
64 "is_reserved": "1",
65 "is_active": "1"
66 }
4324b8d7 67 ]
416abe87 68 },
4324b8d7
CW
69 caseStatuses: {
70 values: [
71 {
72 "id": "290",
73 "option_group_id": "28",
74 "label": "Ongoing",
75 "value": "1",
76 "name": "Open",
77 "grouping": "Opened",
78 "filter": "0",
79 "is_default": "1",
80 "weight": "1",
81 "is_optgroup": "0",
82 "is_reserved": "1",
83 "is_active": "1"
84 },
85 {
86 "id": "291",
87 "option_group_id": "28",
88 "label": "Resolved",
89 "value": "2",
90 "name": "Closed",
91 "grouping": "Closed",
92 "filter": "0",
93 "weight": "2",
94 "is_optgroup": "0",
95 "is_reserved": "1",
96 "is_active": "1"
97 }
98 ]
99 },
100 actTypes: {
101 values: [
102 {
416abe87
PH
103 "id": "784",
104 "option_group_id": "2",
105 "label": "ADC referral",
c866eb5f 106 "value": "62",
416abe87
PH
107 "name": "ADC referral",
108 "filter": "0",
109 "is_default": "0",
110 "weight": "64",
111 "is_optgroup": "0",
112 "is_reserved": "0",
113 "is_active": "1",
114 "component_id": "7"
115 },
4324b8d7 116 {
416abe87
PH
117 "id": "32",
118 "option_group_id": "2",
119 "label": "Add Client To Case",
120 "value": "27",
121 "name": "Add Client To Case",
122 "filter": "0",
123 "is_default": "0",
124 "weight": "26",
125 "description": "",
126 "is_optgroup": "0",
127 "is_reserved": "1",
128 "is_active": "1",
129 "component_id": "7"
ba1ac52d
AH
130 },
131 {
132 "id": "18",
133 "option_group_id": "2",
134 "label": "Open Case",
135 "value": "13",
136 "name": "Open Case",
137 "filter": "0",
138 "is_default": "0",
139 "weight": "13",
140 "is_optgroup": "0",
141 "is_reserved": "1",
142 "is_active": "1",
143 "component_id": "7",
144 "icon": "fa-folder-open-o"
145 },
146 {
147 "id": "857",
148 "option_group_id": "2",
149 "label": "Medical evaluation",
150 "value": "55",
151 "name": "Medical evaluation",
152 "filter": "0",
153 "is_default": "0",
154 "weight": "56",
155 "is_optgroup": "0",
156 "is_reserved": "0",
157 "is_active": "1",
158 "component_id": "7"
159 },
4324b8d7 160 ]
416abe87 161 },
4324b8d7
CW
162 relTypes: {
163 values: [
164 {
416abe87
PH
165 "id": "14",
166 "name_a_b": "Benefits Specialist is",
167 "label_a_b": "Benefits Specialist is",
168 "name_b_a": "Benefits Specialist",
169 "label_b_a": "Benefits Specialist",
170 "description": "Benefits Specialist",
171 "contact_type_a": "Individual",
172 "contact_type_b": "Individual",
173 "is_reserved": "0",
174 "is_active": "1"
175 },
4324b8d7 176 {
416abe87
PH
177 "id": "9",
178 "name_a_b": "Case Coordinator is",
179 "label_a_b": "Case Coordinator is",
180 "name_b_a": "Case Coordinator",
181 "label_b_a": "Case Coordinator",
182 "description": "Case Coordinator",
183 "contact_type_a": "Individual",
184 "contact_type_b": "Individual",
185 "is_reserved": "0",
186 "is_active": "1"
68098e7b 187 },
f570a709
D
188 {
189 "id": "10",
190 "name_a_b": "Homeless Services Coordinator is",
191 "label_a_b": "Homeless Services Coordinator is",
192 "name_b_a": "Homeless Services Coordinator",
193 "label_b_a": "Homeless Services Coordinator",
194 "description": "Homeless Services Coordinator",
195 "contact_type_a": "Individual",
196 "contact_type_b": "Individual",
197 "is_reserved": "0",
198 "is_active": "1"
199 },
68098e7b
RO
200 {
201 "id": "2",
202 "name_a_b": "Spouse of",
203 "label_a_b": "Spouse of",
204 "name_b_a": "Spouse of",
205 "label_b_a": "Spouse of",
206 "description": "Spousal relationship.",
207 "contact_type_a": "Individual",
208 "contact_type_b": "Individual",
209 "is_reserved": "0",
210 "is_active": "1"
f570a709
D
211 },
212 // include one where name is different from label
213 {
214 "id": "27",
215 "name_a_b": "GA123ab",
216 "label_a_b": "Guardian Angel is",
217 "name_b_a": "GA123ba",
218 "label_b_a": "Guardian Angel for",
219 "description": "Guardian Angel.",
220 "contact_type_a": "Individual",
221 "contact_type_b": "Individual",
222 "is_reserved": "0",
223 "is_active": "1"
416abe87 224 }
4324b8d7 225 ]
416abe87 226 },
4324b8d7 227 caseType: {
416abe87
PH
228 "id": "1",
229 "name": "housing_support",
230 "title": "Housing Support",
231 "description": "Help homeless individuals obtain temporary and long-term housing",
232 "is_active": "1",
233 "is_reserved": "0",
234 "weight": "1",
235 "is_forkable": "1",
236 "is_forked": "",
237 "definition": {
238 "activityTypes": [
239 {"name": "Open Case", "max_instances": "1"}
240 ],
241 "activitySets": [
242 {
c866eb5f 243 "name": "standard_timeline",
416abe87
PH
244 "label": "Standard Timeline",
245 "timeline": "1",
246 "activityTypes": [
247 {
248 "name": "Open Case",
249 "status": "Completed"
250 },
251 {
252 "name": "Medical evaluation",
253 "reference_activity": "Open Case",
254 "reference_offset": "1",
255 "reference_select": "newest"
256 }
257 ]
258 }
259 ],
260 "caseRoles": [
261 {
262 "name": "Homeless Services Coordinator",
263 "creator": "1",
264 "manager": "1"
265 }
266 ]
267 }
ad8d1ce3
RO
268 },
269 defaultAssigneeTypes: {
270 values: [
271 {
272 "id": "1174",
273 "option_group_id": "152",
274 "label": "None",
275 "value": "1",
276 "name": "NONE",
277 "filter": "0",
278 "is_default": "1",
279 "weight": "1",
280 "is_optgroup": "0",
281 "is_reserved": "0",
282 "is_active": "1"
283 },
284 {
285 "id": "1175",
286 "option_group_id": "152",
287 "label": "By relationship to workflow client",
288 "value": "2",
289 "name": "BY_RELATIONSHIP",
290 "filter": "0",
291 "is_default": "0",
292 "weight": "2",
293 "is_optgroup": "0",
294 "is_reserved": "0",
295 "is_active": "1"
296 },
297 {
298 "id": "1176",
299 "option_group_id": "152",
300 "label": "Specific contact",
301 "value": "3",
302 "name": "SPECIFIC_CONTACT",
303 "filter": "0",
304 "is_default": "0",
305 "weight": "3",
306 "is_optgroup": "0",
307 "is_reserved": "0",
308 "is_active": "1"
309 },
310 {
311 "id": "1177",
312 "option_group_id": "152",
313 "label": "User creating the workflow",
314 "value": "4",
315 "name": "USER_CREATING_THE_CASE",
316 "filter": "0",
317 "is_default": "0",
318 "weight": "4",
319 "is_optgroup": "0",
320 "is_reserved": "0",
321 "is_active": "1"
322 }
323 ]
416abe87
PH
324 }
325 };
ad8d1ce3 326 defaultAssigneeDefaultValue = _.find(apiCalls.defaultAssigneeTypes.values, { is_default: '1' });
b109dd8b 327 scope = $rootScope.$new();
416abe87 328 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
b109dd8b 329 });
416abe87
PH
330
331 it('should load activity statuses', function() {
4324b8d7 332 expect(scope.activityStatuses).toEqualData(apiCalls.actStatuses.values);
416abe87
PH
333 });
334
335 it('should load activity types', function() {
4324b8d7 336 expect(scope.activityTypes['ADC referral']).toEqualData(apiCalls.actTypes.values[0]);
416abe87
PH
337 });
338
ad8d1ce3
RO
339 it('should store the default assignee types', function() {
340 expect(scope.defaultAssigneeTypes).toBe(apiCalls.defaultAssigneeTypes.values);
341 });
342
343 it('should store the default assignee types values indexed by name', function() {
344 var defaultAssigneeTypeValues = _.chain(apiCalls.defaultAssigneeTypes.values)
345 .indexBy('name').mapValues('value').value();
346
347 expect(scope.defaultAssigneeTypeValues).toEqual(defaultAssigneeTypeValues);
348 });
349
2058bf54
D
350 it('should compute the relationship type options', function() {
351 var expectedRelationshipTypeOptions = [
352 {
353 "id": "14_a_b",
354 "text": "Benefits Specialist",
355 "xmlName": "Benefits Specialist is"
356 },
357 {
358 "id": "14_b_a",
359 "text": "Benefits Specialist is",
360 "xmlName": "Benefits Specialist"
361 },
362 {
363 "id": "9_a_b",
364 "text": "Case Coordinator",
365 "xmlName": "Case Coordinator is"
366 },
367 {
368 "id": "9_b_a",
369 "text": "Case Coordinator is",
370 "xmlName": "Case Coordinator"
371 },
372 {
373 "id": "10_a_b",
374 "text": "Homeless Services Coordinator",
375 "xmlName": "Homeless Services Coordinator is"
376 },
377 {
378 "id": "10_b_a",
379 "text": "Homeless Services Coordinator is",
380 "xmlName": "Homeless Services Coordinator"
381 },
382 // Bidirectional, so should only have the one direction in the list
383 {
384 "id": "2_a_b",
385 "text": "Spouse of",
386 "xmlName": "Spouse of"
387 },
388 // include one where name is different from label
389 {
390 "id": "27_a_b",
391 "text": "Guardian Angel for",
392 "xmlName": "GA123ab",
393 },
394 {
395 "id": "27_b_a",
396 "text": "Guardian Angel is",
397 "xmlName": "GA123ba",
68098e7b 398 }
2058bf54 399 ];
68098e7b 400
2058bf54 401 expect(scope.relationshipTypeOptions).toEqual(expectedRelationshipTypeOptions);
68098e7b
RO
402 });
403
416abe87
PH
404 it('addActivitySet should add an activitySet to the case type', function() {
405 scope.addActivitySet('timeline');
406 var activitySets = scope.caseType.definition.activitySets;
407 var newSet = activitySets[activitySets.length - 1];
408 expect(newSet.name).toBe('timeline_1');
409 expect(newSet.timeline).toBe('1');
410 expect(newSet.label).toBe('Timeline');
411 });
412
413 it('addActivitySet handles second timeline correctly', function() {
414 scope.addActivitySet('timeline');
415 scope.addActivitySet('timeline');
416 var activitySets = scope.caseType.definition.activitySets;
417 var newSet = activitySets[activitySets.length - 1];
418 expect(newSet.name).toBe('timeline_2');
419 expect(newSet.timeline).toBe('1');
420 expect(newSet.label).toBe('Timeline #2');
421 });
ad8d1ce3
RO
422
423 describe('when clearing the activity\'s default assignee type values', function() {
424 var activity;
425
426 beforeEach(function() {
427 activity = {
428 default_assignee_relationship: 1,
429 default_assignee_contact: 2
430 };
431
432 scope.clearActivityDefaultAssigneeValues(activity);
433 });
434
435 it('clears the default assignee relationship for the activity', function() {
436 expect(activity.default_assignee_relationship).toBe(null);
437 });
438
439 it('clears the default assignee contact for the activity', function() {
440 expect(activity.default_assignee_contact).toBe(null);
441 });
442 });
443
444 describe('when adding a new activity to a set', function() {
445 var activitySet;
446
447 beforeEach(function() {
448 activitySet = { activityTypes: [] };
449 scope.activityTypes = { comment: { label: 'Add a new comment' } };
450
451 scope.addActivity(activitySet, 'comment');
452 });
453
454 it('adds a new Comment activity to the set', function() {
455 expect(activitySet.activityTypes[0]).toEqual({
456 name: 'comment',
457 label: scope.activityTypes.comment.label,
458 status: 'Scheduled',
459 reference_activity: 'Open Case',
460 reference_offset: '1',
461 reference_select: 'newest',
462 default_assignee_type: defaultAssigneeDefaultValue.value
463 });
464 });
465 });
466
467 describe('when creating a new workflow', function() {
468 beforeEach(inject(function ($controller) {
469 apiCalls.caseType = null;
470
471 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
472 }));
473
474 it('sets default values for the case type title, name, and active status', function() {
475 expect(scope.caseType).toEqual(jasmine.objectContaining({
476 title: '',
477 name: '',
478 is_active: '1'
479 }));
480 });
481
482 it('adds an Open Case activty to the default activty set', function() {
483 expect(scope.caseType.definition.activitySets[0].activityTypes).toEqual([{
484 name: 'Open Case',
485 label: 'Open Case',
486 status: 'Completed',
487 default_assignee_type: defaultAssigneeDefaultValue.value
488 }]);
489 });
490 });
f570a709
D
491
492 describe('when adding a role', function() {
493 beforeEach(inject(function ($controller) {
494 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
495 }));
496
497 it('updates the case roles', function() {
498
499 // This line sort of simulates selecting a relationship type from the
500 // dropdown. It doesn't test that clicking picks the right value to
501 // add, just that if it did then the function that gets called does
502 // the right thing with it.
2058bf54
D
503 // Note the value returned by the dropdown is "backwards" to match
504 // historically what has been stored in the xml as name, e.g.
f570a709 505 // for the client perspective direction the dropdown returns the other
2058bf54
D
506 // direction.
507 // So 9_b_a is "Case Coordinator", which means that they actually
508 // selected "Case Coordinator is".
509 scope.addRole(scope.caseType.definition.caseRoles, '9_b_a');
f570a709
D
510
511 expect(scope.caseType.definition.caseRoles).toEqual(
512 [
513 {
514 name: 'Homeless Services Coordinator',
515 creator: '1',
516 manager: '1',
671a5fef 517 displayLabel: 'Homeless Services Coordinator is'
f570a709
D
518 },
519 {
520 name: 'Case Coordinator',
671a5fef 521 displayLabel: 'Case Coordinator is'
f570a709
D
522 }
523 ]
524 );
525 });
526
2058bf54
D
527 it('updates case roles when name and label are different', function() {
528 scope.addRole(scope.caseType.definition.caseRoles, '27_b_a');
529 expect(scope.caseType.definition.caseRoles).toEqual(
530 [
531 {
532 name: 'Homeless Services Coordinator',
533 creator: '1',
534 manager: '1',
535 displayLabel: 'Homeless Services Coordinator is'
536 },
537 {
538 name: 'GA123ba',
539 displayLabel: 'Guardian Angel is'
540 }
541 ]
542 );
543 });
544
f570a709
D
545 it('updates case roles if choose non-client-perspective direction', function() {
546 // again, the dropdown returns the opposite direction
2058bf54 547 scope.addRole(scope.caseType.definition.caseRoles, '10_a_b');
f570a709
D
548 expect(scope.caseType.definition.caseRoles).toEqual(
549 [
550 {
551 name: 'Homeless Services Coordinator',
552 creator: '1',
553 manager: '1',
671a5fef 554 displayLabel: 'Homeless Services Coordinator is'
f570a709
D
555 },
556 {
557 name: 'Homeless Services Coordinator is',
671a5fef 558 displayLabel: 'Homeless Services Coordinator'
f570a709
D
559 }
560 ]
561 );
562 });
563
2058bf54
D
564 it('updates case roles non-client-perspective direction name/label different', function() {
565 scope.addRole(scope.caseType.definition.caseRoles, '27_a_b');
566 expect(scope.caseType.definition.caseRoles).toEqual(
567 [
568 {
569 name: 'Homeless Services Coordinator',
570 creator: '1',
571 manager: '1',
572 displayLabel: 'Homeless Services Coordinator is'
573 },
574 {
575 name: 'GA123ab',
576 displayLabel: 'Guardian Angel for'
577 }
578 ]
579 );
580 });
581
f570a709
D
582 it("doesn't add the same role twice", function() {
583 // This is in the mock casetype to start, so check if can add twice.
2058bf54
D
584 scope.addRole(scope.caseType.definition.caseRoles, '10_b_a');
585 expect(scope.caseType.definition.caseRoles).toEqual(
586 [
587 {
588 name: 'Homeless Services Coordinator',
589 creator: '1',
590 manager: '1',
591 displayLabel: 'Homeless Services Coordinator is'
592 }
593 ]
594 );
595
596 // Try with name and label different. We already tested one time in
597 // another test so just go straight to twice.
598 scope.addRole(scope.caseType.definition.caseRoles, '27_b_a');
599 scope.addRole(scope.caseType.definition.caseRoles, '27_b_a');
f570a709
D
600 expect(scope.caseType.definition.caseRoles).toEqual(
601 [
602 {
603 name: 'Homeless Services Coordinator',
604 creator: '1',
605 manager: '1',
671a5fef 606 displayLabel: 'Homeless Services Coordinator is'
2058bf54
D
607 },
608 {
609 name: 'GA123ba',
610 displayLabel: 'Guardian Angel is'
f570a709
D
611 }
612 ]
613 );
614 });
615 });
38ddfacb
D
616
617 describe('when adding a role on-the-fly', function() {
618 beforeEach(inject(function ($controller) {
619 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
620 }));
621
622 it('updates the case roles for unidirectional', function() {
623 // first simulate the ajax popup to create a new relationship type
624 var newType = {
625 "id": "33",
626 "name_a_b": "Some New Type is",
627 "label_a_b": "Some New Type is",
628 "name_b_a": "Some New Type for",
629 "label_b_a": "Some New Type for",
630 "description": "Some New Type",
631 "contact_type_a": "Individual",
632 "contact_type_b": "Individual",
633 "is_reserved": "0",
634 "is_active": "1"
635 };
38ddfacb
D
636
637 // now let the real code do what it does with the new type
638 scope.addRoleOnTheFly(scope.caseType.definition.caseRoles, newType);
639
640 expect(scope.caseType.definition.caseRoles).toEqual(
641 [
642 {
643 name: 'Homeless Services Coordinator',
644 creator: '1',
645 manager: '1',
671a5fef 646 displayLabel: 'Homeless Services Coordinator is'
38ddfacb
D
647 },
648 {
649 name: 'Some New Type for',
671a5fef 650 displayLabel: 'Some New Type is'
38ddfacb
D
651 }
652 ]
653 );
654
655 expect(scope.relationshipTypeOptions.slice(-2)).toEqual(
656 [
657 {
2058bf54
D
658 xmlName: 'Some New Type is',
659 id: '33_a_b',
38ddfacb
D
660 text: 'Some New Type for'
661 },
662 {
2058bf54
D
663 xmlName: 'Some New Type for',
664 id: '33_b_a',
38ddfacb
D
665 text: 'Some New Type is'
666 }
667 ]
668 );
669 });
670
671 it('updates the case roles for bidirectional', function() {
672 // first simulate the ajax popup to create a new relationship type
673 var newType = {
674 "id": "34",
675 "name_a_b": "Friend of",
676 "label_a_b": "Friend of",
677 "name_b_a": "Friend of",
678 "label_b_a": "Friend of",
679 "description": "Friend",
680 "contact_type_a": "Individual",
681 "contact_type_b": "Individual",
682 "is_reserved": "0",
683 "is_active": "1"
684 };
38ddfacb
D
685
686 // now let the real code do what it does with the new type
687 scope.addRoleOnTheFly(scope.caseType.definition.caseRoles, newType);
688
689 expect(scope.caseType.definition.caseRoles).toEqual(
690 [
691 {
692 name: 'Homeless Services Coordinator',
693 creator: '1',
694 manager: '1',
671a5fef 695 displayLabel: 'Homeless Services Coordinator is'
38ddfacb
D
696 },
697 {
698 name: 'Friend of',
671a5fef 699 displayLabel: 'Friend of'
38ddfacb
D
700 }
701 ]
702 );
703
704 expect(scope.relationshipTypeOptions.slice(-1)).toEqual(
705 [
706 {
2058bf54
D
707 xmlName: 'Friend of',
708 id: '34_a_b',
38ddfacb
D
709 text: 'Friend of'
710 }
711 ]
712 );
713
714 // Check that it did NOT add two entries for this bidirectional type
715 expect(scope.relationshipTypeOptions.slice(-2,-1)).not.toEqual(
716 [
717 {
2058bf54
D
718 xmlName: 'Friend of',
719 id: '34_b_a',
38ddfacb
D
720 text: 'Friend of'
721 }
722 ]
723 );
724 });
725 });
c0bb8bd4
DB
726 });
727
728 describe('crmAddName', function () {
c0bb8bd4
DB
729 var element;
730
b109dd8b 731 beforeEach(function() {
c0bb8bd4
DB
732 scope = $rootScope.$new();
733 scope.activityTypeOptions = [1, 2, 3];
734 element = '<span crm-add-name crm-options="activityTypeOptions"></span>';
735
736 spyOn(CRM.$.fn, 'crmSelect2').and.callThrough();
416abe87 737
c0bb8bd4
DB
738 element = $compile(element)(scope);
739 scope.$digest();
b109dd8b 740 });
c0bb8bd4
DB
741
742 describe('when initialized', function () {
743 var returnValue;
744
745 beforeEach (function () {
746 var dataFunction = CRM.$.fn.crmSelect2.calls.argsFor(0)[0].data;
747 returnValue = dataFunction();
748 });
749
750 it('updates the UI with updated value of scope variable', function () {
751 expect(returnValue).toEqual({ results: scope.activityTypeOptions });
752 });
753 });
416abe87 754 });
d9aaf033 755
d7a470db
DB
756 describe('crmEditableTabTitle', function () {
757 var element, titleLabel, penIcon, saveButton, cancelButton;
758
759 beforeEach(function() {
760 scope = $rootScope.$new();
761 element = '<div crm-editable-tab-title title="Click to edit">' +
7c369cd7 762 '<span>{{ activitySet.label }}</span>' +
d7a470db
DB
763 '</div>';
764
765 scope.activitySet = { label: 'Title'};
766 element = $compile(element)(scope);
767
768 titleLabel = $(element).find('span');
769 penIcon = $(element).find('i.fa-pencil');
770 saveButton = $(element).find('button[type=button]');
771 cancelButton = $(element).find('button[type=cancel]');
772
773 scope.$digest();
774 });
775
776 describe('when initialized', function () {
777 it('hides the save and cancel button', function () {
778 expect(saveButton.parent().css('display') === 'none').toBe(true);
779 expect(cancelButton.parent().css('display') === 'none').toBe(true);
780 });
781 });
782
783 describe('when clicked on title label', function () {
784 beforeEach(function () {
785 titleLabel.click();
786 });
787
788 it('hides the pen icon', function () {
789 expect(penIcon.css('display') === 'none').toBe(true);
790 });
791
792 it('shows the save button', function () {
793 expect(saveButton.parent().css('display') !== 'none').toBe(true);
794 });
795
796 it('makes the title editable', function () {
797 expect(titleLabel.attr('contenteditable')).toBe('true');
798 });
799 });
800
801 describe('when clicked outside of the editable area', function () {
802 beforeEach(function () {
803 titleLabel.click();
804 titleLabel.text('Updated Title');
805 titleLabel.blur();
806 $timeout.flush();
807 scope.$digest();
808 });
809
810 it('shows the pen icon', function () {
811 expect(penIcon.css('display') !== 'none').toBe(true);
812 });
813
814 it('hides the save and cancel button', function () {
815 expect(saveButton.parent().css('display') === 'none').toBe(true);
816 expect(cancelButton.parent().css('display') === 'none').toBe(true);
817 });
818
819 it('makes the title non editable', function () {
820 expect(titleLabel.attr('contenteditable')).not.toBe('true');
821 });
822
823 it('does not update the title in angular context', function () {
824 expect(scope.activitySet.label).toBe('Title');
825 });
826 });
827
828 describe('when ESCAPE key is pressed while typing', function () {
829 beforeEach(function () {
830 var eventObj = $.Event('keydown');
831 eventObj.key = 'Escape';
832
833 titleLabel.click();
834 titleLabel.text('Updated Title');
835 titleLabel.trigger(eventObj);
836 scope.$digest();
837 });
838
839 it('shows the pen icon', function () {
840 expect(penIcon.css('display') !== 'none').toBe(true);
841 });
842
843 it('hides the save and cancel button', function () {
844 expect(saveButton.parent().css('display') === 'none').toBe(true);
845 expect(cancelButton.parent().css('display') === 'none').toBe(true);
846 });
847
848 it('makes the title non editable', function () {
849 expect(titleLabel.attr('contenteditable')).not.toBe('true');
850 });
851
852 it('does not update the title', function () {
853 expect(scope.activitySet.label).toBe('Title');
854 });
855 });
856
857 describe('when ENTER key is pressed while typing', function () {
858 beforeEach(function () {
859 var eventObj = $.Event('keydown');
860 eventObj.key = 'Enter';
861
862 titleLabel.click();
863 titleLabel.text('Updated Title');
864 titleLabel.trigger(eventObj);
865 scope.$digest();
866 });
867
868 it('shows the pen icon', function () {
869 expect(penIcon.css('display') !== 'none').toBe(true);
870 });
871
872 it('hides the save and cancel button', function () {
873 expect(saveButton.parent().css('display') === 'none').toBe(true);
874 expect(cancelButton.parent().css('display') === 'none').toBe(true);
875 });
876
877 it('makes the title non editable', function () {
878 expect(titleLabel.attr('contenteditable')).not.toBe('true');
879 });
880
881 it('updates the title in angular context', function () {
882 expect(scope.activitySet.label).toBe('Updated Title');
883 });
884 });
885
886 describe('when SAVE button is clicked', function () {
887 beforeEach(function () {
888 titleLabel.click();
889 titleLabel.text('Updated Title');
890 saveButton.click();
891 scope.$digest();
892 });
893
894 it('shows the pen icon', function () {
895 expect(penIcon.css('display') !== 'none').toBe(true);
896 });
897
898 it('hides the save and cancel button', function () {
899 expect(saveButton.parent().css('display') === 'none').toBe(true);
900 expect(cancelButton.parent().css('display') === 'none').toBe(true);
901 });
902
903 it('makes the title non editable', function () {
904 expect(titleLabel.attr('contenteditable')).not.toBe('true');
905 });
906
907 it('updates the title in angular context', function () {
908 expect(scope.activitySet.label).toBe('Updated Title');
909 });
910 });
911
912 describe('when CANCEL button is clicked', function () {
913 beforeEach(function () {
914 titleLabel.click();
915 titleLabel.text('Updated Title');
916 cancelButton.click();
917 scope.$digest();
918 });
919
920 it('shows the pen icon', function () {
921 expect(penIcon.css('display') !== 'none').toBe(true);
922 });
923
924 it('hides the save and cancel button', function () {
925 expect(saveButton.parent().css('display') === 'none').toBe(true);
926 expect(cancelButton.parent().css('display') === 'none').toBe(true);
927 });
928
929 it('makes the title non editable', function () {
930 expect(titleLabel.attr('contenteditable')).not.toBe('true');
931 });
932
933 it('does not update the title in angular context', function () {
934 expect(scope.activitySet.label).toBe('Title');
935 });
936 });
937 });
938
c9817fac
RO
939 describe('CaseTypeListCtrl', function() {
940 var caseTypes, crmApiSpy;
d9aaf033 941
c9817fac 942 beforeEach(function() {
d9aaf033
RO
943 caseTypes = {
944 values: {
945 1: { id: 1 },
946 2: { id: 2 },
947 3: { id: 3 }
948 }
949 };
c9817fac 950 crmApiSpy = jasmine.createSpy('crmApi').and.returnValue($q.resolve());
d9aaf033
RO
951 scope = $rootScope.$new();
952 ctrl = $controller('CaseTypeListCtrl', {
953 $scope: scope,
c9817fac
RO
954 caseTypes: caseTypes,
955 crmApi: crmApiSpy
d9aaf033
RO
956 });
957 });
958
959 it('should store an index of case types', function() {
960 expect(scope.caseTypes).toEqual(caseTypes.values);
961 });
c9817fac
RO
962
963 describe('toggleCaseType', function() {
964 var caseType = { id: _.uniqueId() };
965
966 describe('when the case is active', function() {
967 beforeEach(function() {
968 caseType.is_active = '1';
969
970 scope.toggleCaseType(caseType);
971 });
972
973 it('sets the case type as inactive', function() {
974 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({
975 id: caseType.id,
976 is_active: '0'
977 }), true);
978 });
979 });
980
981 describe('when the case is inactive', function() {
982 beforeEach(function() {
983 caseType.is_active = '0';
984
985 scope.toggleCaseType(caseType);
986 });
987
988 it('sets the case type as active', function() {
989 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({
990 id: caseType.id,
991 is_active: '1'
992 }), true);
993 });
994 });
995 });
2e01cc82
RO
996
997 describe('deleteCaseType', function() {
998 var caseType = { id: _.uniqueId() };
999
1000 beforeEach(function() {
1001 crmApiSpy.and.returnValue($q.resolve(caseType));
1002 scope.caseTypes[caseType.id] = caseType;
1003
1004 scope.deleteCaseType(caseType);
1005 scope.$digest();
1006 });
1007
1008 describe('when the case type can be deleted', function() {
1009 it('deletes the case from the api', function() {
1010 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'delete', { id: caseType.id }, jasmine.any(Object));
1011 });
1012
1013 it('removes the case type from the list', function() {
1014 expect(scope.caseTypes[caseType.id]).toBeUndefined();
1015 });
1016 });
1017
1018 describe('when the case type cannot be delted', function() {
1019 var error = { error_message: 'Error Message' };
1020
1021 beforeEach(function() {
1022 var errorHandler;
1023
1024 crmApiSpy.and.returnValue($q.reject(error));
1025 scope.caseTypes[caseType.id] = caseType;
1026
1027 spyOn(CRM, 'alert');
1028 scope.deleteCaseType(caseType);
1029 scope.$digest();
1030
1031 errorHandler = crmApiSpy.calls.mostRecent().args[3].error;
1032 errorHandler(error);
1033 });
1034
1035 it('displays the error message', function() {
384f015c 1036 expect(CRM.alert).toHaveBeenCalledWith(error.error_message, 'Error', 'error');
2e01cc82
RO
1037 });
1038 });
b4e42693
RO
1039
1040 describe('revertCaseType', function() {
1041 var caseType = {
1042 id: _.uniqueId(),
1043 definition: {},
1044 is_forked: '1'
1045 };
1046
1047 describe('when reverting a case type', function() {
1048 beforeEach(function() {
1049 scope.revertCaseType(caseType);
1050 });
1051
1052 it('resets the case type information using the api', function() {
1053 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({
1054 id: caseType.id,
1055 definition: 'null',
1056 is_forked: '0'
1057 }), true);
1058 });
1059 });
1060 });
2e01cc82 1061 });
d9aaf033 1062 });
416abe87 1063});