Merge pull request #15421 from artfulrobot/queue-safety
[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 },
f570a709
D
227 // Where is this used in the tests?
228 // It seems to be in the format for the activity assignee.
41cf58d3
AF
229 relTypesForm: {
230 values: [
231 {
232 "key": "14_b_a",
233 "value": "Benefits Specialist"
234 },
235 {
236 "key": "14_a_b",
237 "value": "Benefits Specialist is"
238 },
239 {
240 "key": "9_b_a",
241 "value": "Case Coordinator"
242 },
243 {
244 "key": "9_a_b",
245 "value": "Case Coordinator is"
246 },
247 {
248 "key": "2_b_a",
249 "value": "Spouse of"
250 }
251 ]
252 },
4324b8d7 253 caseType: {
416abe87
PH
254 "id": "1",
255 "name": "housing_support",
256 "title": "Housing Support",
257 "description": "Help homeless individuals obtain temporary and long-term housing",
258 "is_active": "1",
259 "is_reserved": "0",
260 "weight": "1",
261 "is_forkable": "1",
262 "is_forked": "",
263 "definition": {
264 "activityTypes": [
265 {"name": "Open Case", "max_instances": "1"}
266 ],
267 "activitySets": [
268 {
c866eb5f 269 "name": "standard_timeline",
416abe87
PH
270 "label": "Standard Timeline",
271 "timeline": "1",
272 "activityTypes": [
273 {
274 "name": "Open Case",
275 "status": "Completed"
276 },
277 {
278 "name": "Medical evaluation",
279 "reference_activity": "Open Case",
280 "reference_offset": "1",
281 "reference_select": "newest"
282 }
283 ]
284 }
285 ],
286 "caseRoles": [
287 {
288 "name": "Homeless Services Coordinator",
289 "creator": "1",
290 "manager": "1"
291 }
292 ]
293 }
ad8d1ce3
RO
294 },
295 defaultAssigneeTypes: {
296 values: [
297 {
298 "id": "1174",
299 "option_group_id": "152",
300 "label": "None",
301 "value": "1",
302 "name": "NONE",
303 "filter": "0",
304 "is_default": "1",
305 "weight": "1",
306 "is_optgroup": "0",
307 "is_reserved": "0",
308 "is_active": "1"
309 },
310 {
311 "id": "1175",
312 "option_group_id": "152",
313 "label": "By relationship to workflow client",
314 "value": "2",
315 "name": "BY_RELATIONSHIP",
316 "filter": "0",
317 "is_default": "0",
318 "weight": "2",
319 "is_optgroup": "0",
320 "is_reserved": "0",
321 "is_active": "1"
322 },
323 {
324 "id": "1176",
325 "option_group_id": "152",
326 "label": "Specific contact",
327 "value": "3",
328 "name": "SPECIFIC_CONTACT",
329 "filter": "0",
330 "is_default": "0",
331 "weight": "3",
332 "is_optgroup": "0",
333 "is_reserved": "0",
334 "is_active": "1"
335 },
336 {
337 "id": "1177",
338 "option_group_id": "152",
339 "label": "User creating the workflow",
340 "value": "4",
341 "name": "USER_CREATING_THE_CASE",
342 "filter": "0",
343 "is_default": "0",
344 "weight": "4",
345 "is_optgroup": "0",
346 "is_reserved": "0",
347 "is_active": "1"
348 }
349 ]
416abe87
PH
350 }
351 };
ad8d1ce3 352 defaultAssigneeDefaultValue = _.find(apiCalls.defaultAssigneeTypes.values, { is_default: '1' });
b109dd8b 353 scope = $rootScope.$new();
416abe87 354 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
b109dd8b 355 });
416abe87
PH
356
357 it('should load activity statuses', function() {
4324b8d7 358 expect(scope.activityStatuses).toEqualData(apiCalls.actStatuses.values);
416abe87
PH
359 });
360
361 it('should load activity types', function() {
4324b8d7 362 expect(scope.activityTypes['ADC referral']).toEqualData(apiCalls.actTypes.values[0]);
416abe87
PH
363 });
364
ad8d1ce3
RO
365 it('should store the default assignee types', function() {
366 expect(scope.defaultAssigneeTypes).toBe(apiCalls.defaultAssigneeTypes.values);
367 });
368
369 it('should store the default assignee types values indexed by name', function() {
370 var defaultAssigneeTypeValues = _.chain(apiCalls.defaultAssigneeTypes.values)
371 .indexBy('name').mapValues('value').value();
372
373 expect(scope.defaultAssigneeTypeValues).toEqual(defaultAssigneeTypeValues);
374 });
375
68098e7b
RO
376 it('should store the default assignee relationship type options', function() {
377 var defaultRelationshipTypeOptions = _.transform(apiCalls.relTypes.values, function(result, relType) {
378 var isBidirectionalRelationship = relType.label_a_b === relType.label_b_a;
379
380 result.push({
381 label: relType.label_b_a,
b79ff943 382 value: relType.id + '_a_b'
68098e7b
RO
383 });
384
385 if (!isBidirectionalRelationship) {
386 result.push({
387 label: relType.label_a_b,
b79ff943 388 value: relType.id + '_b_a'
68098e7b
RO
389 });
390 }
391 }, []);
392
393 expect(scope.defaultRelationshipTypeOptions).toEqual(defaultRelationshipTypeOptions);
394 });
395
416abe87
PH
396 it('addActivitySet should add an activitySet to the case type', function() {
397 scope.addActivitySet('timeline');
398 var activitySets = scope.caseType.definition.activitySets;
399 var newSet = activitySets[activitySets.length - 1];
400 expect(newSet.name).toBe('timeline_1');
401 expect(newSet.timeline).toBe('1');
402 expect(newSet.label).toBe('Timeline');
403 });
404
405 it('addActivitySet handles second timeline correctly', function() {
406 scope.addActivitySet('timeline');
407 scope.addActivitySet('timeline');
408 var activitySets = scope.caseType.definition.activitySets;
409 var newSet = activitySets[activitySets.length - 1];
410 expect(newSet.name).toBe('timeline_2');
411 expect(newSet.timeline).toBe('1');
412 expect(newSet.label).toBe('Timeline #2');
413 });
ad8d1ce3
RO
414
415 describe('when clearing the activity\'s default assignee type values', function() {
416 var activity;
417
418 beforeEach(function() {
419 activity = {
420 default_assignee_relationship: 1,
421 default_assignee_contact: 2
422 };
423
424 scope.clearActivityDefaultAssigneeValues(activity);
425 });
426
427 it('clears the default assignee relationship for the activity', function() {
428 expect(activity.default_assignee_relationship).toBe(null);
429 });
430
431 it('clears the default assignee contact for the activity', function() {
432 expect(activity.default_assignee_contact).toBe(null);
433 });
434 });
435
436 describe('when adding a new activity to a set', function() {
437 var activitySet;
438
439 beforeEach(function() {
440 activitySet = { activityTypes: [] };
441 scope.activityTypes = { comment: { label: 'Add a new comment' } };
442
443 scope.addActivity(activitySet, 'comment');
444 });
445
446 it('adds a new Comment activity to the set', function() {
447 expect(activitySet.activityTypes[0]).toEqual({
448 name: 'comment',
449 label: scope.activityTypes.comment.label,
450 status: 'Scheduled',
451 reference_activity: 'Open Case',
452 reference_offset: '1',
453 reference_select: 'newest',
454 default_assignee_type: defaultAssigneeDefaultValue.value
455 });
456 });
457 });
458
459 describe('when creating a new workflow', function() {
460 beforeEach(inject(function ($controller) {
461 apiCalls.caseType = null;
462
463 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
464 }));
465
466 it('sets default values for the case type title, name, and active status', function() {
467 expect(scope.caseType).toEqual(jasmine.objectContaining({
468 title: '',
469 name: '',
470 is_active: '1'
471 }));
472 });
473
474 it('adds an Open Case activty to the default activty set', function() {
475 expect(scope.caseType.definition.activitySets[0].activityTypes).toEqual([{
476 name: 'Open Case',
477 label: 'Open Case',
478 status: 'Completed',
479 default_assignee_type: defaultAssigneeDefaultValue.value
480 }]);
481 });
482 });
f570a709
D
483
484 describe('when adding a role', function() {
485 beforeEach(inject(function ($controller) {
486 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
487 }));
488
489 it('updates the case roles', function() {
490
491 // This line sort of simulates selecting a relationship type from the
492 // dropdown. It doesn't test that clicking picks the right value to
493 // add, just that if it did then the function that gets called does
494 // the right thing with it.
495 // Note the value returned by the dropdown is "backwards", e.g.
496 // for the client perspective direction the dropdown returns the other
497 // direction, which is also what's stored in the xml.
498 scope.addRole(scope.caseType.definition.caseRoles, 'Case Coordinator');
499
500 expect(scope.caseType.definition.caseRoles).toEqual(
501 [
502 {
503 name: 'Homeless Services Coordinator',
504 creator: '1',
505 manager: '1',
506 displaylabel: 'Homeless Services Coordinator is'
507 },
508 {
509 name: 'Case Coordinator',
510 displaylabel: 'Case Coordinator is'
511 }
512 ]
513 );
514 });
515
516 it('updates case roles if choose non-client-perspective direction', function() {
517 // again, the dropdown returns the opposite direction
518 scope.addRole(scope.caseType.definition.caseRoles, 'Homeless Services Coordinator is');
519 expect(scope.caseType.definition.caseRoles).toEqual(
520 [
521 {
522 name: 'Homeless Services Coordinator',
523 creator: '1',
524 manager: '1',
525 displaylabel: 'Homeless Services Coordinator is'
526 },
527 {
528 name: 'Homeless Services Coordinator is',
529 displaylabel: 'Homeless Services Coordinator'
530 }
531 ]
532 );
533 });
534
535 it("doesn't add the same role twice", function() {
536 // This is in the mock casetype to start, so check if can add twice.
537 scope.addRole(scope.caseType.definition.caseRoles, 'Homeless Services Coordinator');
538 expect(scope.caseType.definition.caseRoles).toEqual(
539 [
540 {
541 name: 'Homeless Services Coordinator',
542 creator: '1',
543 manager: '1',
544 displaylabel: 'Homeless Services Coordinator is'
545 }
546 ]
547 );
548 });
549 });
38ddfacb
D
550
551 describe('when adding a role on-the-fly', function() {
552 beforeEach(inject(function ($controller) {
553 ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
554 }));
555
556 it('updates the case roles for unidirectional', function() {
557 // first simulate the ajax popup to create a new relationship type
558 var newType = {
559 "id": "33",
560 "name_a_b": "Some New Type is",
561 "label_a_b": "Some New Type is",
562 "name_b_a": "Some New Type for",
563 "label_b_a": "Some New Type for",
564 "description": "Some New Type",
565 "contact_type_a": "Individual",
566 "contact_type_b": "Individual",
567 "is_reserved": "0",
568 "is_active": "1"
569 };
570 apiCalls.relTypes.values.push(newType);
571
572 // now let the real code do what it does with the new type
573 scope.addRoleOnTheFly(scope.caseType.definition.caseRoles, newType);
574
575 expect(scope.caseType.definition.caseRoles).toEqual(
576 [
577 {
578 name: 'Homeless Services Coordinator',
579 creator: '1',
580 manager: '1',
581 displaylabel: 'Homeless Services Coordinator is'
582 },
583 {
584 name: 'Some New Type for',
585 displaylabel: 'Some New Type is'
586 }
587 ]
588 );
589
590 expect(scope.relationshipTypeOptions.slice(-2)).toEqual(
591 [
592 {
593 id: 'Some New Type is',
594 text: 'Some New Type for'
595 },
596 {
597 id: 'Some New Type for',
598 text: 'Some New Type is'
599 }
600 ]
601 );
602 });
603
604 it('updates the case roles for bidirectional', function() {
605 // first simulate the ajax popup to create a new relationship type
606 var newType = {
607 "id": "34",
608 "name_a_b": "Friend of",
609 "label_a_b": "Friend of",
610 "name_b_a": "Friend of",
611 "label_b_a": "Friend of",
612 "description": "Friend",
613 "contact_type_a": "Individual",
614 "contact_type_b": "Individual",
615 "is_reserved": "0",
616 "is_active": "1"
617 };
618 apiCalls.relTypes.values.push(newType);
619
620 // now let the real code do what it does with the new type
621 scope.addRoleOnTheFly(scope.caseType.definition.caseRoles, newType);
622
623 expect(scope.caseType.definition.caseRoles).toEqual(
624 [
625 {
626 name: 'Homeless Services Coordinator',
627 creator: '1',
628 manager: '1',
629 displaylabel: 'Homeless Services Coordinator is'
630 },
631 {
632 name: 'Friend of',
633 displaylabel: 'Friend of'
634 }
635 ]
636 );
637
638 expect(scope.relationshipTypeOptions.slice(-1)).toEqual(
639 [
640 {
641 id: 'Friend of',
642 text: 'Friend of'
643 }
644 ]
645 );
646
647 // Check that it did NOT add two entries for this bidirectional type
648 expect(scope.relationshipTypeOptions.slice(-2,-1)).not.toEqual(
649 [
650 {
651 id: 'Friend of',
652 text: 'Friend of'
653 }
654 ]
655 );
656 });
657 });
c0bb8bd4
DB
658 });
659
660 describe('crmAddName', function () {
c0bb8bd4
DB
661 var element;
662
b109dd8b 663 beforeEach(function() {
c0bb8bd4
DB
664 scope = $rootScope.$new();
665 scope.activityTypeOptions = [1, 2, 3];
666 element = '<span crm-add-name crm-options="activityTypeOptions"></span>';
667
668 spyOn(CRM.$.fn, 'crmSelect2').and.callThrough();
416abe87 669
c0bb8bd4
DB
670 element = $compile(element)(scope);
671 scope.$digest();
b109dd8b 672 });
c0bb8bd4
DB
673
674 describe('when initialized', function () {
675 var returnValue;
676
677 beforeEach (function () {
678 var dataFunction = CRM.$.fn.crmSelect2.calls.argsFor(0)[0].data;
679 returnValue = dataFunction();
680 });
681
682 it('updates the UI with updated value of scope variable', function () {
683 expect(returnValue).toEqual({ results: scope.activityTypeOptions });
684 });
685 });
416abe87 686 });
d9aaf033 687
d7a470db
DB
688 describe('crmEditableTabTitle', function () {
689 var element, titleLabel, penIcon, saveButton, cancelButton;
690
691 beforeEach(function() {
692 scope = $rootScope.$new();
693 element = '<div crm-editable-tab-title title="Click to edit">' +
7c369cd7 694 '<span>{{ activitySet.label }}</span>' +
d7a470db
DB
695 '</div>';
696
697 scope.activitySet = { label: 'Title'};
698 element = $compile(element)(scope);
699
700 titleLabel = $(element).find('span');
701 penIcon = $(element).find('i.fa-pencil');
702 saveButton = $(element).find('button[type=button]');
703 cancelButton = $(element).find('button[type=cancel]');
704
705 scope.$digest();
706 });
707
708 describe('when initialized', function () {
709 it('hides the save and cancel button', function () {
710 expect(saveButton.parent().css('display') === 'none').toBe(true);
711 expect(cancelButton.parent().css('display') === 'none').toBe(true);
712 });
713 });
714
715 describe('when clicked on title label', function () {
716 beforeEach(function () {
717 titleLabel.click();
718 });
719
720 it('hides the pen icon', function () {
721 expect(penIcon.css('display') === 'none').toBe(true);
722 });
723
724 it('shows the save button', function () {
725 expect(saveButton.parent().css('display') !== 'none').toBe(true);
726 });
727
728 it('makes the title editable', function () {
729 expect(titleLabel.attr('contenteditable')).toBe('true');
730 });
731 });
732
733 describe('when clicked outside of the editable area', function () {
734 beforeEach(function () {
735 titleLabel.click();
736 titleLabel.text('Updated Title');
737 titleLabel.blur();
738 $timeout.flush();
739 scope.$digest();
740 });
741
742 it('shows the pen icon', function () {
743 expect(penIcon.css('display') !== 'none').toBe(true);
744 });
745
746 it('hides the save and cancel button', function () {
747 expect(saveButton.parent().css('display') === 'none').toBe(true);
748 expect(cancelButton.parent().css('display') === 'none').toBe(true);
749 });
750
751 it('makes the title non editable', function () {
752 expect(titleLabel.attr('contenteditable')).not.toBe('true');
753 });
754
755 it('does not update the title in angular context', function () {
756 expect(scope.activitySet.label).toBe('Title');
757 });
758 });
759
760 describe('when ESCAPE key is pressed while typing', function () {
761 beforeEach(function () {
762 var eventObj = $.Event('keydown');
763 eventObj.key = 'Escape';
764
765 titleLabel.click();
766 titleLabel.text('Updated Title');
767 titleLabel.trigger(eventObj);
768 scope.$digest();
769 });
770
771 it('shows the pen icon', function () {
772 expect(penIcon.css('display') !== 'none').toBe(true);
773 });
774
775 it('hides the save and cancel button', function () {
776 expect(saveButton.parent().css('display') === 'none').toBe(true);
777 expect(cancelButton.parent().css('display') === 'none').toBe(true);
778 });
779
780 it('makes the title non editable', function () {
781 expect(titleLabel.attr('contenteditable')).not.toBe('true');
782 });
783
784 it('does not update the title', function () {
785 expect(scope.activitySet.label).toBe('Title');
786 });
787 });
788
789 describe('when ENTER key is pressed while typing', function () {
790 beforeEach(function () {
791 var eventObj = $.Event('keydown');
792 eventObj.key = 'Enter';
793
794 titleLabel.click();
795 titleLabel.text('Updated Title');
796 titleLabel.trigger(eventObj);
797 scope.$digest();
798 });
799
800 it('shows the pen icon', function () {
801 expect(penIcon.css('display') !== 'none').toBe(true);
802 });
803
804 it('hides the save and cancel button', function () {
805 expect(saveButton.parent().css('display') === 'none').toBe(true);
806 expect(cancelButton.parent().css('display') === 'none').toBe(true);
807 });
808
809 it('makes the title non editable', function () {
810 expect(titleLabel.attr('contenteditable')).not.toBe('true');
811 });
812
813 it('updates the title in angular context', function () {
814 expect(scope.activitySet.label).toBe('Updated Title');
815 });
816 });
817
818 describe('when SAVE button is clicked', function () {
819 beforeEach(function () {
820 titleLabel.click();
821 titleLabel.text('Updated Title');
822 saveButton.click();
823 scope.$digest();
824 });
825
826 it('shows the pen icon', function () {
827 expect(penIcon.css('display') !== 'none').toBe(true);
828 });
829
830 it('hides the save and cancel button', function () {
831 expect(saveButton.parent().css('display') === 'none').toBe(true);
832 expect(cancelButton.parent().css('display') === 'none').toBe(true);
833 });
834
835 it('makes the title non editable', function () {
836 expect(titleLabel.attr('contenteditable')).not.toBe('true');
837 });
838
839 it('updates the title in angular context', function () {
840 expect(scope.activitySet.label).toBe('Updated Title');
841 });
842 });
843
844 describe('when CANCEL button is clicked', function () {
845 beforeEach(function () {
846 titleLabel.click();
847 titleLabel.text('Updated Title');
848 cancelButton.click();
849 scope.$digest();
850 });
851
852 it('shows the pen icon', function () {
853 expect(penIcon.css('display') !== 'none').toBe(true);
854 });
855
856 it('hides the save and cancel button', function () {
857 expect(saveButton.parent().css('display') === 'none').toBe(true);
858 expect(cancelButton.parent().css('display') === 'none').toBe(true);
859 });
860
861 it('makes the title non editable', function () {
862 expect(titleLabel.attr('contenteditable')).not.toBe('true');
863 });
864
865 it('does not update the title in angular context', function () {
866 expect(scope.activitySet.label).toBe('Title');
867 });
868 });
869 });
870
c9817fac
RO
871 describe('CaseTypeListCtrl', function() {
872 var caseTypes, crmApiSpy;
d9aaf033 873
c9817fac 874 beforeEach(function() {
d9aaf033
RO
875 caseTypes = {
876 values: {
877 1: { id: 1 },
878 2: { id: 2 },
879 3: { id: 3 }
880 }
881 };
c9817fac 882 crmApiSpy = jasmine.createSpy('crmApi').and.returnValue($q.resolve());
d9aaf033
RO
883 scope = $rootScope.$new();
884 ctrl = $controller('CaseTypeListCtrl', {
885 $scope: scope,
c9817fac
RO
886 caseTypes: caseTypes,
887 crmApi: crmApiSpy
d9aaf033
RO
888 });
889 });
890
891 it('should store an index of case types', function() {
892 expect(scope.caseTypes).toEqual(caseTypes.values);
893 });
c9817fac
RO
894
895 describe('toggleCaseType', function() {
896 var caseType = { id: _.uniqueId() };
897
898 describe('when the case is active', function() {
899 beforeEach(function() {
900 caseType.is_active = '1';
901
902 scope.toggleCaseType(caseType);
903 });
904
905 it('sets the case type as inactive', function() {
906 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({
907 id: caseType.id,
908 is_active: '0'
909 }), true);
910 });
911 });
912
913 describe('when the case is inactive', function() {
914 beforeEach(function() {
915 caseType.is_active = '0';
916
917 scope.toggleCaseType(caseType);
918 });
919
920 it('sets the case type as active', function() {
921 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({
922 id: caseType.id,
923 is_active: '1'
924 }), true);
925 });
926 });
927 });
2e01cc82
RO
928
929 describe('deleteCaseType', function() {
930 var caseType = { id: _.uniqueId() };
931
932 beforeEach(function() {
933 crmApiSpy.and.returnValue($q.resolve(caseType));
934 scope.caseTypes[caseType.id] = caseType;
935
936 scope.deleteCaseType(caseType);
937 scope.$digest();
938 });
939
940 describe('when the case type can be deleted', function() {
941 it('deletes the case from the api', function() {
942 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'delete', { id: caseType.id }, jasmine.any(Object));
943 });
944
945 it('removes the case type from the list', function() {
946 expect(scope.caseTypes[caseType.id]).toBeUndefined();
947 });
948 });
949
950 describe('when the case type cannot be delted', function() {
951 var error = { error_message: 'Error Message' };
952
953 beforeEach(function() {
954 var errorHandler;
955
956 crmApiSpy.and.returnValue($q.reject(error));
957 scope.caseTypes[caseType.id] = caseType;
958
959 spyOn(CRM, 'alert');
960 scope.deleteCaseType(caseType);
961 scope.$digest();
962
963 errorHandler = crmApiSpy.calls.mostRecent().args[3].error;
964 errorHandler(error);
965 });
966
967 it('displays the error message', function() {
384f015c 968 expect(CRM.alert).toHaveBeenCalledWith(error.error_message, 'Error', 'error');
2e01cc82
RO
969 });
970 });
b4e42693
RO
971
972 describe('revertCaseType', function() {
973 var caseType = {
974 id: _.uniqueId(),
975 definition: {},
976 is_forked: '1'
977 };
978
979 describe('when reverting a case type', function() {
980 beforeEach(function() {
981 scope.revertCaseType(caseType);
982 });
983
984 it('resets the case type information using the api', function() {
985 expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({
986 id: caseType.id,
987 definition: 'null',
988 is_forked: '0'
989 }), true);
990 });
991 });
992 });
2e01cc82 993 });
d9aaf033 994 });
416abe87 995});