Commit | Line | Data |
---|---|---|
384f015c | 1 | /* global $, _, CRM:true */ |
416abe87 PH |
2 | 'use strict'; |
3 | ||
4 | describe('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; | |
14 | var scope; | |
416abe87 PH |
15 | |
16 | beforeEach(function() { | |
17 | CRM.resourceUrls = { | |
18 | 'civicrm': '' | |
19 | }; | |
4324b8d7 | 20 | // CRM_Case_XMLProcessor::REL_TYPE_CNAME |
416abe87 PH |
21 | CRM.crmCaseType = { |
22 | 'REL_TYPE_CNAME': 'label_b_a' | |
23 | }; | |
24 | module('crmCaseType'); | |
09a09949 PH |
25 | module('crmJsonComparator'); |
26 | inject(function(crmJsonComparator) { | |
27 | crmJsonComparator.register(jasmine); | |
416abe87 PH |
28 | }); |
29 | }); | |
30 | ||
d7a470db | 31 | beforeEach(inject(function(_$controller_, _$compile_, _$httpBackend_, _$q_, _$rootScope_, _$timeout_) { |
b109dd8b RO |
32 | $controller = _$controller_; |
33 | $compile = _$compile_; | |
34 | $httpBackend = _$httpBackend_; | |
c9817fac | 35 | $q = _$q_; |
b109dd8b | 36 | $rootScope = _$rootScope_; |
d7a470db | 37 | $timeout = _$timeout_; |
b109dd8b | 38 | })); |
416abe87 | 39 | |
b109dd8b RO |
40 | describe('CaseTypeCtrl', function() { |
41 | beforeEach(function () { | |
416abe87 | 42 | apiCalls = { |
4324b8d7 CW |
43 | actStatuses: { |
44 | values: [ | |
45 | { | |
416abe87 PH |
46 | "id": "272", |
47 | "option_group_id": "25", | |
48 | "label": "Scheduled", | |
49 | "value": "1", | |
50 | "name": "Scheduled", | |
51 | "filter": "0", | |
52 | "is_default": "1", | |
53 | "weight": "1", | |
54 | "is_optgroup": "0", | |
55 | "is_reserved": "1", | |
56 | "is_active": "1" | |
57 | }, | |
4324b8d7 | 58 | { |
416abe87 PH |
59 | "id": "273", |
60 | "option_group_id": "25", | |
61 | "label": "Completed", | |
62 | "value": "2", | |
63 | "name": "Completed", | |
64 | "filter": "0", | |
65 | "weight": "2", | |
66 | "is_optgroup": "0", | |
67 | "is_reserved": "1", | |
68 | "is_active": "1" | |
69 | } | |
4324b8d7 | 70 | ] |
416abe87 | 71 | }, |
4324b8d7 CW |
72 | caseStatuses: { |
73 | values: [ | |
74 | { | |
75 | "id": "290", | |
76 | "option_group_id": "28", | |
77 | "label": "Ongoing", | |
78 | "value": "1", | |
79 | "name": "Open", | |
80 | "grouping": "Opened", | |
81 | "filter": "0", | |
82 | "is_default": "1", | |
83 | "weight": "1", | |
84 | "is_optgroup": "0", | |
85 | "is_reserved": "1", | |
86 | "is_active": "1" | |
87 | }, | |
88 | { | |
89 | "id": "291", | |
90 | "option_group_id": "28", | |
91 | "label": "Resolved", | |
92 | "value": "2", | |
93 | "name": "Closed", | |
94 | "grouping": "Closed", | |
95 | "filter": "0", | |
96 | "weight": "2", | |
97 | "is_optgroup": "0", | |
98 | "is_reserved": "1", | |
99 | "is_active": "1" | |
100 | } | |
101 | ] | |
102 | }, | |
103 | actTypes: { | |
104 | values: [ | |
105 | { | |
416abe87 PH |
106 | "id": "784", |
107 | "option_group_id": "2", | |
108 | "label": "ADC referral", | |
c866eb5f | 109 | "value": "62", |
416abe87 PH |
110 | "name": "ADC referral", |
111 | "filter": "0", | |
112 | "is_default": "0", | |
113 | "weight": "64", | |
114 | "is_optgroup": "0", | |
115 | "is_reserved": "0", | |
116 | "is_active": "1", | |
117 | "component_id": "7" | |
118 | }, | |
4324b8d7 | 119 | { |
416abe87 PH |
120 | "id": "32", |
121 | "option_group_id": "2", | |
122 | "label": "Add Client To Case", | |
123 | "value": "27", | |
124 | "name": "Add Client To Case", | |
125 | "filter": "0", | |
126 | "is_default": "0", | |
127 | "weight": "26", | |
128 | "description": "", | |
129 | "is_optgroup": "0", | |
130 | "is_reserved": "1", | |
131 | "is_active": "1", | |
132 | "component_id": "7" | |
ba1ac52d AH |
133 | }, |
134 | { | |
135 | "id": "18", | |
136 | "option_group_id": "2", | |
137 | "label": "Open Case", | |
138 | "value": "13", | |
139 | "name": "Open Case", | |
140 | "filter": "0", | |
141 | "is_default": "0", | |
142 | "weight": "13", | |
143 | "is_optgroup": "0", | |
144 | "is_reserved": "1", | |
145 | "is_active": "1", | |
146 | "component_id": "7", | |
147 | "icon": "fa-folder-open-o" | |
148 | }, | |
149 | { | |
150 | "id": "857", | |
151 | "option_group_id": "2", | |
152 | "label": "Medical evaluation", | |
153 | "value": "55", | |
154 | "name": "Medical evaluation", | |
155 | "filter": "0", | |
156 | "is_default": "0", | |
157 | "weight": "56", | |
158 | "is_optgroup": "0", | |
159 | "is_reserved": "0", | |
160 | "is_active": "1", | |
161 | "component_id": "7" | |
162 | }, | |
4324b8d7 | 163 | ] |
416abe87 | 164 | }, |
4324b8d7 CW |
165 | relTypes: { |
166 | values: [ | |
167 | { | |
416abe87 PH |
168 | "id": "14", |
169 | "name_a_b": "Benefits Specialist is", | |
170 | "label_a_b": "Benefits Specialist is", | |
171 | "name_b_a": "Benefits Specialist", | |
172 | "label_b_a": "Benefits Specialist", | |
173 | "description": "Benefits Specialist", | |
174 | "contact_type_a": "Individual", | |
175 | "contact_type_b": "Individual", | |
176 | "is_reserved": "0", | |
177 | "is_active": "1" | |
178 | }, | |
4324b8d7 | 179 | { |
416abe87 PH |
180 | "id": "9", |
181 | "name_a_b": "Case Coordinator is", | |
182 | "label_a_b": "Case Coordinator is", | |
183 | "name_b_a": "Case Coordinator", | |
184 | "label_b_a": "Case Coordinator", | |
185 | "description": "Case Coordinator", | |
186 | "contact_type_a": "Individual", | |
187 | "contact_type_b": "Individual", | |
188 | "is_reserved": "0", | |
189 | "is_active": "1" | |
190 | } | |
4324b8d7 | 191 | ] |
416abe87 | 192 | }, |
4324b8d7 | 193 | caseType: { |
416abe87 PH |
194 | "id": "1", |
195 | "name": "housing_support", | |
196 | "title": "Housing Support", | |
197 | "description": "Help homeless individuals obtain temporary and long-term housing", | |
198 | "is_active": "1", | |
199 | "is_reserved": "0", | |
200 | "weight": "1", | |
201 | "is_forkable": "1", | |
202 | "is_forked": "", | |
203 | "definition": { | |
204 | "activityTypes": [ | |
205 | {"name": "Open Case", "max_instances": "1"} | |
206 | ], | |
207 | "activitySets": [ | |
208 | { | |
c866eb5f | 209 | "name": "standard_timeline", |
416abe87 PH |
210 | "label": "Standard Timeline", |
211 | "timeline": "1", | |
212 | "activityTypes": [ | |
213 | { | |
214 | "name": "Open Case", | |
215 | "status": "Completed" | |
216 | }, | |
217 | { | |
218 | "name": "Medical evaluation", | |
219 | "reference_activity": "Open Case", | |
220 | "reference_offset": "1", | |
221 | "reference_select": "newest" | |
222 | } | |
223 | ] | |
224 | } | |
225 | ], | |
226 | "caseRoles": [ | |
227 | { | |
228 | "name": "Homeless Services Coordinator", | |
229 | "creator": "1", | |
230 | "manager": "1" | |
231 | } | |
232 | ] | |
233 | } | |
234 | } | |
235 | }; | |
b109dd8b | 236 | scope = $rootScope.$new(); |
416abe87 | 237 | ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls}); |
b109dd8b | 238 | }); |
416abe87 PH |
239 | |
240 | it('should load activity statuses', function() { | |
4324b8d7 | 241 | expect(scope.activityStatuses).toEqualData(apiCalls.actStatuses.values); |
416abe87 PH |
242 | }); |
243 | ||
244 | it('should load activity types', function() { | |
4324b8d7 | 245 | expect(scope.activityTypes['ADC referral']).toEqualData(apiCalls.actTypes.values[0]); |
416abe87 PH |
246 | }); |
247 | ||
248 | it('addActivitySet should add an activitySet to the case type', function() { | |
249 | scope.addActivitySet('timeline'); | |
250 | var activitySets = scope.caseType.definition.activitySets; | |
251 | var newSet = activitySets[activitySets.length - 1]; | |
252 | expect(newSet.name).toBe('timeline_1'); | |
253 | expect(newSet.timeline).toBe('1'); | |
254 | expect(newSet.label).toBe('Timeline'); | |
255 | }); | |
256 | ||
257 | it('addActivitySet handles second timeline correctly', function() { | |
258 | scope.addActivitySet('timeline'); | |
259 | scope.addActivitySet('timeline'); | |
260 | var activitySets = scope.caseType.definition.activitySets; | |
261 | var newSet = activitySets[activitySets.length - 1]; | |
262 | expect(newSet.name).toBe('timeline_2'); | |
263 | expect(newSet.timeline).toBe('1'); | |
264 | expect(newSet.label).toBe('Timeline #2'); | |
265 | }); | |
c0bb8bd4 DB |
266 | }); |
267 | ||
268 | describe('crmAddName', function () { | |
c0bb8bd4 DB |
269 | var element; |
270 | ||
b109dd8b | 271 | beforeEach(function() { |
c0bb8bd4 DB |
272 | scope = $rootScope.$new(); |
273 | scope.activityTypeOptions = [1, 2, 3]; | |
274 | element = '<span crm-add-name crm-options="activityTypeOptions"></span>'; | |
275 | ||
276 | spyOn(CRM.$.fn, 'crmSelect2').and.callThrough(); | |
416abe87 | 277 | |
c0bb8bd4 DB |
278 | element = $compile(element)(scope); |
279 | scope.$digest(); | |
b109dd8b | 280 | }); |
c0bb8bd4 DB |
281 | |
282 | describe('when initialized', function () { | |
283 | var returnValue; | |
284 | ||
285 | beforeEach (function () { | |
286 | var dataFunction = CRM.$.fn.crmSelect2.calls.argsFor(0)[0].data; | |
287 | returnValue = dataFunction(); | |
288 | }); | |
289 | ||
290 | it('updates the UI with updated value of scope variable', function () { | |
291 | expect(returnValue).toEqual({ results: scope.activityTypeOptions }); | |
292 | }); | |
293 | }); | |
416abe87 | 294 | }); |
d9aaf033 | 295 | |
d7a470db DB |
296 | describe('crmEditableTabTitle', function () { |
297 | var element, titleLabel, penIcon, saveButton, cancelButton; | |
298 | ||
299 | beforeEach(function() { | |
300 | scope = $rootScope.$new(); | |
301 | element = '<div crm-editable-tab-title title="Click to edit">' + | |
7c369cd7 | 302 | '<span>{{ activitySet.label }}</span>' + |
d7a470db DB |
303 | '</div>'; |
304 | ||
305 | scope.activitySet = { label: 'Title'}; | |
306 | element = $compile(element)(scope); | |
307 | ||
308 | titleLabel = $(element).find('span'); | |
309 | penIcon = $(element).find('i.fa-pencil'); | |
310 | saveButton = $(element).find('button[type=button]'); | |
311 | cancelButton = $(element).find('button[type=cancel]'); | |
312 | ||
313 | scope.$digest(); | |
314 | }); | |
315 | ||
316 | describe('when initialized', function () { | |
317 | it('hides the save and cancel button', function () { | |
318 | expect(saveButton.parent().css('display') === 'none').toBe(true); | |
319 | expect(cancelButton.parent().css('display') === 'none').toBe(true); | |
320 | }); | |
321 | }); | |
322 | ||
323 | describe('when clicked on title label', function () { | |
324 | beforeEach(function () { | |
325 | titleLabel.click(); | |
326 | }); | |
327 | ||
328 | it('hides the pen icon', function () { | |
329 | expect(penIcon.css('display') === 'none').toBe(true); | |
330 | }); | |
331 | ||
332 | it('shows the save button', function () { | |
333 | expect(saveButton.parent().css('display') !== 'none').toBe(true); | |
334 | }); | |
335 | ||
336 | it('makes the title editable', function () { | |
337 | expect(titleLabel.attr('contenteditable')).toBe('true'); | |
338 | }); | |
339 | }); | |
340 | ||
341 | describe('when clicked outside of the editable area', function () { | |
342 | beforeEach(function () { | |
343 | titleLabel.click(); | |
344 | titleLabel.text('Updated Title'); | |
345 | titleLabel.blur(); | |
346 | $timeout.flush(); | |
347 | scope.$digest(); | |
348 | }); | |
349 | ||
350 | it('shows the pen icon', function () { | |
351 | expect(penIcon.css('display') !== 'none').toBe(true); | |
352 | }); | |
353 | ||
354 | it('hides the save and cancel button', function () { | |
355 | expect(saveButton.parent().css('display') === 'none').toBe(true); | |
356 | expect(cancelButton.parent().css('display') === 'none').toBe(true); | |
357 | }); | |
358 | ||
359 | it('makes the title non editable', function () { | |
360 | expect(titleLabel.attr('contenteditable')).not.toBe('true'); | |
361 | }); | |
362 | ||
363 | it('does not update the title in angular context', function () { | |
364 | expect(scope.activitySet.label).toBe('Title'); | |
365 | }); | |
366 | }); | |
367 | ||
368 | describe('when ESCAPE key is pressed while typing', function () { | |
369 | beforeEach(function () { | |
370 | var eventObj = $.Event('keydown'); | |
371 | eventObj.key = 'Escape'; | |
372 | ||
373 | titleLabel.click(); | |
374 | titleLabel.text('Updated Title'); | |
375 | titleLabel.trigger(eventObj); | |
376 | scope.$digest(); | |
377 | }); | |
378 | ||
379 | it('shows the pen icon', function () { | |
380 | expect(penIcon.css('display') !== 'none').toBe(true); | |
381 | }); | |
382 | ||
383 | it('hides the save and cancel button', function () { | |
384 | expect(saveButton.parent().css('display') === 'none').toBe(true); | |
385 | expect(cancelButton.parent().css('display') === 'none').toBe(true); | |
386 | }); | |
387 | ||
388 | it('makes the title non editable', function () { | |
389 | expect(titleLabel.attr('contenteditable')).not.toBe('true'); | |
390 | }); | |
391 | ||
392 | it('does not update the title', function () { | |
393 | expect(scope.activitySet.label).toBe('Title'); | |
394 | }); | |
395 | }); | |
396 | ||
397 | describe('when ENTER key is pressed while typing', function () { | |
398 | beforeEach(function () { | |
399 | var eventObj = $.Event('keydown'); | |
400 | eventObj.key = 'Enter'; | |
401 | ||
402 | titleLabel.click(); | |
403 | titleLabel.text('Updated Title'); | |
404 | titleLabel.trigger(eventObj); | |
405 | scope.$digest(); | |
406 | }); | |
407 | ||
408 | it('shows the pen icon', function () { | |
409 | expect(penIcon.css('display') !== 'none').toBe(true); | |
410 | }); | |
411 | ||
412 | it('hides the save and cancel button', function () { | |
413 | expect(saveButton.parent().css('display') === 'none').toBe(true); | |
414 | expect(cancelButton.parent().css('display') === 'none').toBe(true); | |
415 | }); | |
416 | ||
417 | it('makes the title non editable', function () { | |
418 | expect(titleLabel.attr('contenteditable')).not.toBe('true'); | |
419 | }); | |
420 | ||
421 | it('updates the title in angular context', function () { | |
422 | expect(scope.activitySet.label).toBe('Updated Title'); | |
423 | }); | |
424 | }); | |
425 | ||
426 | describe('when SAVE button is clicked', function () { | |
427 | beforeEach(function () { | |
428 | titleLabel.click(); | |
429 | titleLabel.text('Updated Title'); | |
430 | saveButton.click(); | |
431 | scope.$digest(); | |
432 | }); | |
433 | ||
434 | it('shows the pen icon', function () { | |
435 | expect(penIcon.css('display') !== 'none').toBe(true); | |
436 | }); | |
437 | ||
438 | it('hides the save and cancel button', function () { | |
439 | expect(saveButton.parent().css('display') === 'none').toBe(true); | |
440 | expect(cancelButton.parent().css('display') === 'none').toBe(true); | |
441 | }); | |
442 | ||
443 | it('makes the title non editable', function () { | |
444 | expect(titleLabel.attr('contenteditable')).not.toBe('true'); | |
445 | }); | |
446 | ||
447 | it('updates the title in angular context', function () { | |
448 | expect(scope.activitySet.label).toBe('Updated Title'); | |
449 | }); | |
450 | }); | |
451 | ||
452 | describe('when CANCEL button is clicked', function () { | |
453 | beforeEach(function () { | |
454 | titleLabel.click(); | |
455 | titleLabel.text('Updated Title'); | |
456 | cancelButton.click(); | |
457 | scope.$digest(); | |
458 | }); | |
459 | ||
460 | it('shows the pen icon', function () { | |
461 | expect(penIcon.css('display') !== 'none').toBe(true); | |
462 | }); | |
463 | ||
464 | it('hides the save and cancel button', function () { | |
465 | expect(saveButton.parent().css('display') === 'none').toBe(true); | |
466 | expect(cancelButton.parent().css('display') === 'none').toBe(true); | |
467 | }); | |
468 | ||
469 | it('makes the title non editable', function () { | |
470 | expect(titleLabel.attr('contenteditable')).not.toBe('true'); | |
471 | }); | |
472 | ||
473 | it('does not update the title in angular context', function () { | |
474 | expect(scope.activitySet.label).toBe('Title'); | |
475 | }); | |
476 | }); | |
477 | }); | |
478 | ||
c9817fac RO |
479 | describe('CaseTypeListCtrl', function() { |
480 | var caseTypes, crmApiSpy; | |
d9aaf033 | 481 | |
c9817fac | 482 | beforeEach(function() { |
d9aaf033 RO |
483 | caseTypes = { |
484 | values: { | |
485 | 1: { id: 1 }, | |
486 | 2: { id: 2 }, | |
487 | 3: { id: 3 } | |
488 | } | |
489 | }; | |
c9817fac | 490 | crmApiSpy = jasmine.createSpy('crmApi').and.returnValue($q.resolve()); |
d9aaf033 RO |
491 | scope = $rootScope.$new(); |
492 | ctrl = $controller('CaseTypeListCtrl', { | |
493 | $scope: scope, | |
c9817fac RO |
494 | caseTypes: caseTypes, |
495 | crmApi: crmApiSpy | |
d9aaf033 RO |
496 | }); |
497 | }); | |
498 | ||
499 | it('should store an index of case types', function() { | |
500 | expect(scope.caseTypes).toEqual(caseTypes.values); | |
501 | }); | |
c9817fac RO |
502 | |
503 | describe('toggleCaseType', function() { | |
504 | var caseType = { id: _.uniqueId() }; | |
505 | ||
506 | describe('when the case is active', function() { | |
507 | beforeEach(function() { | |
508 | caseType.is_active = '1'; | |
509 | ||
510 | scope.toggleCaseType(caseType); | |
511 | }); | |
512 | ||
513 | it('sets the case type as inactive', function() { | |
514 | expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({ | |
515 | id: caseType.id, | |
516 | is_active: '0' | |
517 | }), true); | |
518 | }); | |
519 | }); | |
520 | ||
521 | describe('when the case is inactive', function() { | |
522 | beforeEach(function() { | |
523 | caseType.is_active = '0'; | |
524 | ||
525 | scope.toggleCaseType(caseType); | |
526 | }); | |
527 | ||
528 | it('sets the case type as active', function() { | |
529 | expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({ | |
530 | id: caseType.id, | |
531 | is_active: '1' | |
532 | }), true); | |
533 | }); | |
534 | }); | |
535 | }); | |
2e01cc82 RO |
536 | |
537 | describe('deleteCaseType', function() { | |
538 | var caseType = { id: _.uniqueId() }; | |
539 | ||
540 | beforeEach(function() { | |
541 | crmApiSpy.and.returnValue($q.resolve(caseType)); | |
542 | scope.caseTypes[caseType.id] = caseType; | |
543 | ||
544 | scope.deleteCaseType(caseType); | |
545 | scope.$digest(); | |
546 | }); | |
547 | ||
548 | describe('when the case type can be deleted', function() { | |
549 | it('deletes the case from the api', function() { | |
550 | expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'delete', { id: caseType.id }, jasmine.any(Object)); | |
551 | }); | |
552 | ||
553 | it('removes the case type from the list', function() { | |
554 | expect(scope.caseTypes[caseType.id]).toBeUndefined(); | |
555 | }); | |
556 | }); | |
557 | ||
558 | describe('when the case type cannot be delted', function() { | |
559 | var error = { error_message: 'Error Message' }; | |
560 | ||
561 | beforeEach(function() { | |
562 | var errorHandler; | |
563 | ||
564 | crmApiSpy.and.returnValue($q.reject(error)); | |
565 | scope.caseTypes[caseType.id] = caseType; | |
566 | ||
567 | spyOn(CRM, 'alert'); | |
568 | scope.deleteCaseType(caseType); | |
569 | scope.$digest(); | |
570 | ||
571 | errorHandler = crmApiSpy.calls.mostRecent().args[3].error; | |
572 | errorHandler(error); | |
573 | }); | |
574 | ||
575 | it('displays the error message', function() { | |
384f015c | 576 | expect(CRM.alert).toHaveBeenCalledWith(error.error_message, 'Error', 'error'); |
2e01cc82 RO |
577 | }); |
578 | }); | |
b4e42693 RO |
579 | |
580 | describe('revertCaseType', function() { | |
581 | var caseType = { | |
582 | id: _.uniqueId(), | |
583 | definition: {}, | |
584 | is_forked: '1' | |
585 | }; | |
586 | ||
587 | describe('when reverting a case type', function() { | |
588 | beforeEach(function() { | |
589 | scope.revertCaseType(caseType); | |
590 | }); | |
591 | ||
592 | it('resets the case type information using the api', function() { | |
593 | expect(crmApiSpy).toHaveBeenCalledWith('CaseType', 'create', jasmine.objectContaining({ | |
594 | id: caseType.id, | |
595 | definition: 'null', | |
596 | is_forked: '0' | |
597 | }), true); | |
598 | }); | |
599 | }); | |
600 | }); | |
2e01cc82 | 601 | }); |
d9aaf033 | 602 | }); |
416abe87 | 603 | }); |