1 /* global $, _, CRM:true */
4 describe('crmCaseType', function() {
14 var defaultAssigneeDefaultValue
;
17 beforeEach(function() {
21 // CRM_Case_XMLProcessor::REL_TYPE_CNAME
23 'REL_TYPE_CNAME': 'label_b_a'
25 module('crmCaseType');
26 module('crmJsonComparator');
27 inject(function(crmJsonComparator
) {
28 crmJsonComparator
.register(jasmine
);
32 beforeEach(inject(function(_
$controller_
, _
$compile_
, _
$httpBackend_
, _
$q_
, _
$rootScope_
, _
$timeout_
) {
33 $controller
= _
$controller_
;
34 $compile
= _
$compile_
;
35 $httpBackend
= _
$httpBackend_
;
37 $rootScope
= _
$rootScope_
;
38 $timeout
= _
$timeout_
;
41 describe('CaseTypeCtrl', function() {
42 beforeEach(function () {
48 "option_group_id": "25",
61 "option_group_id": "25",
77 "option_group_id": "28",
91 "option_group_id": "28",
108 "option_group_id": "2",
109 "label": "ADC referral",
111 "name": "ADC referral",
122 "option_group_id": "2",
123 "label": "Add Client To Case",
125 "name": "Add Client To Case",
137 "option_group_id": "2",
138 "label": "Open Case",
148 "icon": "fa-folder-open-o"
152 "option_group_id": "2",
153 "label": "Medical evaluation",
155 "name": "Medical evaluation",
170 "name_a_b": "Benefits Specialist is",
171 "label_a_b": "Benefits Specialist is",
172 "name_b_a": "Benefits Specialist",
173 "label_b_a": "Benefits Specialist",
174 "description": "Benefits Specialist",
175 "contact_type_a": "Individual",
176 "contact_type_b": "Individual",
182 "name_a_b": "Case Coordinator is",
183 "label_a_b": "Case Coordinator is",
184 "name_b_a": "Case Coordinator",
185 "label_b_a": "Case Coordinator",
186 "description": "Case Coordinator",
187 "contact_type_a": "Individual",
188 "contact_type_b": "Individual",
194 "name_a_b": "Spouse of",
195 "label_a_b": "Spouse of",
196 "name_b_a": "Spouse of",
197 "label_b_a": "Spouse of",
198 "description": "Spousal relationship.",
199 "contact_type_a": "Individual",
200 "contact_type_b": "Individual",
208 "name": "housing_support",
209 "title": "Housing Support",
210 "description": "Help homeless individuals obtain temporary and long-term housing",
218 {"name": "Open Case", "max_instances": "1"}
222 "name": "standard_timeline",
223 "label": "Standard Timeline",
228 "status": "Completed"
231 "name": "Medical evaluation",
232 "reference_activity": "Open Case",
233 "reference_offset": "1",
234 "reference_select": "newest"
241 "name": "Homeless Services Coordinator",
248 defaultAssigneeTypes
: {
252 "option_group_id": "152",
265 "option_group_id": "152",
266 "label": "By relationship to workflow client",
268 "name": "BY_RELATIONSHIP",
278 "option_group_id": "152",
279 "label": "Specific contact",
281 "name": "SPECIFIC_CONTACT",
291 "option_group_id": "152",
292 "label": "User creating the workflow",
294 "name": "USER_CREATING_THE_CASE",
305 defaultAssigneeDefaultValue
= _
.find(apiCalls
.defaultAssigneeTypes
.values
, { is_default
: '1' });
306 scope
= $rootScope
.$new();
307 ctrl
= $controller('CaseTypeCtrl', {$scope
: scope
, apiCalls
: apiCalls
});
310 it('should load activity statuses', function() {
311 expect(scope
.activityStatuses
).toEqualData(apiCalls
.actStatuses
.values
);
314 it('should load activity types', function() {
315 expect(scope
.activityTypes
['ADC referral']).toEqualData(apiCalls
.actTypes
.values
[0]);
318 it('should store the default assignee types', function() {
319 expect(scope
.defaultAssigneeTypes
).toBe(apiCalls
.defaultAssigneeTypes
.values
);
322 it('should store the default assignee types values indexed by name', function() {
323 var defaultAssigneeTypeValues
= _
.chain(apiCalls
.defaultAssigneeTypes
.values
)
324 .indexBy('name').mapValues('value').value();
326 expect(scope
.defaultAssigneeTypeValues
).toEqual(defaultAssigneeTypeValues
);
329 it('should store the default assignee relationship type options', function() {
330 var defaultRelationshipTypeOptions
= _
.transform(apiCalls
.relTypes
.values
, function(result
, relType
) {
331 var isBidirectionalRelationship
= relType
.label_a_b
=== relType
.label_b_a
;
334 label
: relType
.label_b_a
,
335 value
: relType
.id
+ '_b_a'
338 if (!isBidirectionalRelationship
) {
340 label
: relType
.label_a_b
,
341 value
: relType
.id
+ '_a_b'
346 expect(scope
.defaultRelationshipTypeOptions
).toEqual(defaultRelationshipTypeOptions
);
349 it('addActivitySet should add an activitySet to the case type', function() {
350 scope
.addActivitySet('timeline');
351 var activitySets
= scope
.caseType
.definition
.activitySets
;
352 var newSet
= activitySets
[activitySets
.length
- 1];
353 expect(newSet
.name
).toBe('timeline_1');
354 expect(newSet
.timeline
).toBe('1');
355 expect(newSet
.label
).toBe('Timeline');
358 it('addActivitySet handles second timeline correctly', function() {
359 scope
.addActivitySet('timeline');
360 scope
.addActivitySet('timeline');
361 var activitySets
= scope
.caseType
.definition
.activitySets
;
362 var newSet
= activitySets
[activitySets
.length
- 1];
363 expect(newSet
.name
).toBe('timeline_2');
364 expect(newSet
.timeline
).toBe('1');
365 expect(newSet
.label
).toBe('Timeline #2');
368 describe('when clearing the activity\'s default assignee type values', function() {
371 beforeEach(function() {
373 default_assignee_relationship
: 1,
374 default_assignee_contact
: 2
377 scope
.clearActivityDefaultAssigneeValues(activity
);
380 it('clears the default assignee relationship for the activity', function() {
381 expect(activity
.default_assignee_relationship
).toBe(null);
384 it('clears the default assignee contact for the activity', function() {
385 expect(activity
.default_assignee_contact
).toBe(null);
389 describe('when adding a new activity to a set', function() {
392 beforeEach(function() {
393 activitySet
= { activityTypes
: [] };
394 scope
.activityTypes
= { comment
: { label
: 'Add a new comment' } };
396 scope
.addActivity(activitySet
, 'comment');
399 it('adds a new Comment activity to the set', function() {
400 expect(activitySet
.activityTypes
[0]).toEqual({
402 label
: scope
.activityTypes
.comment
.label
,
404 reference_activity
: 'Open Case',
405 reference_offset
: '1',
406 reference_select
: 'newest',
407 default_assignee_type
: defaultAssigneeDefaultValue
.value
412 describe('when creating a new workflow', function() {
413 beforeEach(inject(function ($controller
) {
414 apiCalls
.caseType
= null;
416 ctrl
= $controller('CaseTypeCtrl', {$scope
: scope
, apiCalls
: apiCalls
});
419 it('sets default values for the case type title, name, and active status', function() {
420 expect(scope
.caseType
).toEqual(jasmine
.objectContaining({
427 it('adds an Open Case activty to the default activty set', function() {
428 expect(scope
.caseType
.definition
.activitySets
[0].activityTypes
).toEqual([{
432 default_assignee_type
: defaultAssigneeDefaultValue
.value
438 describe('crmAddName', function () {
441 beforeEach(function() {
442 scope
= $rootScope
.$new();
443 scope
.activityTypeOptions
= [1, 2, 3];
444 element
= '<span crm-add-name crm-options="activityTypeOptions"></span>';
446 spyOn(CRM
.$.fn
, 'crmSelect2').and
.callThrough();
448 element
= $compile(element
)(scope
);
452 describe('when initialized', function () {
455 beforeEach (function () {
456 var dataFunction
= CRM
.$.fn
.crmSelect2
.calls
.argsFor(0)[0].data
;
457 returnValue
= dataFunction();
460 it('updates the UI with updated value of scope variable', function () {
461 expect(returnValue
).toEqual({ results
: scope
.activityTypeOptions
});
466 describe('crmEditableTabTitle', function () {
467 var element
, titleLabel
, penIcon
, saveButton
, cancelButton
;
469 beforeEach(function() {
470 scope
= $rootScope
.$new();
471 element
= '<div crm-editable-tab-title title="Click to edit">' +
472 '<span>{{ activitySet.label }}</span>' +
475 scope
.activitySet
= { label
: 'Title'};
476 element
= $compile(element
)(scope
);
478 titleLabel
= $(element
).find('span');
479 penIcon
= $(element
).find('i.fa-pencil');
480 saveButton
= $(element
).find('button[type=button]');
481 cancelButton
= $(element
).find('button[type=cancel]');
486 describe('when initialized', function () {
487 it('hides the save and cancel button', function () {
488 expect(saveButton
.parent().css('display') === 'none').toBe(true);
489 expect(cancelButton
.parent().css('display') === 'none').toBe(true);
493 describe('when clicked on title label', function () {
494 beforeEach(function () {
498 it('hides the pen icon', function () {
499 expect(penIcon
.css('display') === 'none').toBe(true);
502 it('shows the save button', function () {
503 expect(saveButton
.parent().css('display') !== 'none').toBe(true);
506 it('makes the title editable', function () {
507 expect(titleLabel
.attr('contenteditable')).toBe('true');
511 describe('when clicked outside of the editable area', function () {
512 beforeEach(function () {
514 titleLabel
.text('Updated Title');
520 it('shows the pen icon', function () {
521 expect(penIcon
.css('display') !== 'none').toBe(true);
524 it('hides the save and cancel button', function () {
525 expect(saveButton
.parent().css('display') === 'none').toBe(true);
526 expect(cancelButton
.parent().css('display') === 'none').toBe(true);
529 it('makes the title non editable', function () {
530 expect(titleLabel
.attr('contenteditable')).not
.toBe('true');
533 it('does not update the title in angular context', function () {
534 expect(scope
.activitySet
.label
).toBe('Title');
538 describe('when ESCAPE key is pressed while typing', function () {
539 beforeEach(function () {
540 var eventObj
= $.Event('keydown');
541 eventObj
.key
= 'Escape';
544 titleLabel
.text('Updated Title');
545 titleLabel
.trigger(eventObj
);
549 it('shows the pen icon', function () {
550 expect(penIcon
.css('display') !== 'none').toBe(true);
553 it('hides the save and cancel button', function () {
554 expect(saveButton
.parent().css('display') === 'none').toBe(true);
555 expect(cancelButton
.parent().css('display') === 'none').toBe(true);
558 it('makes the title non editable', function () {
559 expect(titleLabel
.attr('contenteditable')).not
.toBe('true');
562 it('does not update the title', function () {
563 expect(scope
.activitySet
.label
).toBe('Title');
567 describe('when ENTER key is pressed while typing', function () {
568 beforeEach(function () {
569 var eventObj
= $.Event('keydown');
570 eventObj
.key
= 'Enter';
573 titleLabel
.text('Updated Title');
574 titleLabel
.trigger(eventObj
);
578 it('shows the pen icon', function () {
579 expect(penIcon
.css('display') !== 'none').toBe(true);
582 it('hides the save and cancel button', function () {
583 expect(saveButton
.parent().css('display') === 'none').toBe(true);
584 expect(cancelButton
.parent().css('display') === 'none').toBe(true);
587 it('makes the title non editable', function () {
588 expect(titleLabel
.attr('contenteditable')).not
.toBe('true');
591 it('updates the title in angular context', function () {
592 expect(scope
.activitySet
.label
).toBe('Updated Title');
596 describe('when SAVE button is clicked', function () {
597 beforeEach(function () {
599 titleLabel
.text('Updated Title');
604 it('shows the pen icon', function () {
605 expect(penIcon
.css('display') !== 'none').toBe(true);
608 it('hides the save and cancel button', function () {
609 expect(saveButton
.parent().css('display') === 'none').toBe(true);
610 expect(cancelButton
.parent().css('display') === 'none').toBe(true);
613 it('makes the title non editable', function () {
614 expect(titleLabel
.attr('contenteditable')).not
.toBe('true');
617 it('updates the title in angular context', function () {
618 expect(scope
.activitySet
.label
).toBe('Updated Title');
622 describe('when CANCEL button is clicked', function () {
623 beforeEach(function () {
625 titleLabel
.text('Updated Title');
626 cancelButton
.click();
630 it('shows the pen icon', function () {
631 expect(penIcon
.css('display') !== 'none').toBe(true);
634 it('hides the save and cancel button', function () {
635 expect(saveButton
.parent().css('display') === 'none').toBe(true);
636 expect(cancelButton
.parent().css('display') === 'none').toBe(true);
639 it('makes the title non editable', function () {
640 expect(titleLabel
.attr('contenteditable')).not
.toBe('true');
643 it('does not update the title in angular context', function () {
644 expect(scope
.activitySet
.label
).toBe('Title');
649 describe('CaseTypeListCtrl', function() {
650 var caseTypes
, crmApiSpy
;
652 beforeEach(function() {
660 crmApiSpy
= jasmine
.createSpy('crmApi').and
.returnValue($q
.resolve());
661 scope
= $rootScope
.$new();
662 ctrl
= $controller('CaseTypeListCtrl', {
664 caseTypes
: caseTypes
,
669 it('should store an index of case types', function() {
670 expect(scope
.caseTypes
).toEqual(caseTypes
.values
);
673 describe('toggleCaseType', function() {
674 var caseType
= { id
: _
.uniqueId() };
676 describe('when the case is active', function() {
677 beforeEach(function() {
678 caseType
.is_active
= '1';
680 scope
.toggleCaseType(caseType
);
683 it('sets the case type as inactive', function() {
684 expect(crmApiSpy
).toHaveBeenCalledWith('CaseType', 'create', jasmine
.objectContaining({
691 describe('when the case is inactive', function() {
692 beforeEach(function() {
693 caseType
.is_active
= '0';
695 scope
.toggleCaseType(caseType
);
698 it('sets the case type as active', function() {
699 expect(crmApiSpy
).toHaveBeenCalledWith('CaseType', 'create', jasmine
.objectContaining({
707 describe('deleteCaseType', function() {
708 var caseType
= { id
: _
.uniqueId() };
710 beforeEach(function() {
711 crmApiSpy
.and
.returnValue($q
.resolve(caseType
));
712 scope
.caseTypes
[caseType
.id
] = caseType
;
714 scope
.deleteCaseType(caseType
);
718 describe('when the case type can be deleted', function() {
719 it('deletes the case from the api', function() {
720 expect(crmApiSpy
).toHaveBeenCalledWith('CaseType', 'delete', { id
: caseType
.id
}, jasmine
.any(Object
));
723 it('removes the case type from the list', function() {
724 expect(scope
.caseTypes
[caseType
.id
]).toBeUndefined();
728 describe('when the case type cannot be delted', function() {
729 var error
= { error_message
: 'Error Message' };
731 beforeEach(function() {
734 crmApiSpy
.and
.returnValue($q
.reject(error
));
735 scope
.caseTypes
[caseType
.id
] = caseType
;
738 scope
.deleteCaseType(caseType
);
741 errorHandler
= crmApiSpy
.calls
.mostRecent().args
[3].error
;
745 it('displays the error message', function() {
746 expect(CRM
.alert
).toHaveBeenCalledWith(error
.error_message
, 'Error', 'error');
750 describe('revertCaseType', function() {
757 describe('when reverting a case type', function() {
758 beforeEach(function() {
759 scope
.revertCaseType(caseType
);
762 it('resets the case type information using the api', function() {
763 expect(crmApiSpy
).toHaveBeenCalledWith('CaseType', 'create', jasmine
.objectContaining({