3 describe('crmAutosave', function() {
5 beforeEach(function() {
10 describe('Autosave directive', function() {
19 beforeEach(inject(function(_
$compile_
, _
$rootScope_
, _
$interval_
, _
$timeout_
, _
$q_
) {
20 // The injector unwraps the underscores (_) from around the parameter names when matching
21 $compile
= _
$compile_
;
22 $rootScope
= _
$rootScope_
;
23 $interval
= _
$interval_
;
24 $timeout
= _
$timeout_
;
26 $rootScope
.fakeCtrl
= fakeCtrl
= {
29 doSaveWithPromise: function() {
30 var dfr
= _
$q_
.defer();
36 doSaveSlowly: function() {
37 var dfr
= _
$q_
.defer();
38 fakeCtrl
.savingSlowly
= true;
40 fakeCtrl
.savingSlowly
= false;
46 spyOn(fakeCtrl
, 'doSave').and
.callThrough();
47 spyOn(fakeCtrl
, 'doSaveWithPromise').and
.callThrough();
48 spyOn(fakeCtrl
, 'doSaveSlowly').and
.callThrough();
50 $rootScope
.model
= model
= {
56 // Fake wait - advance the interval & timeout
57 // @param int msec Total time to advance the clock
58 // @param int steps Number of times to issue flush()
59 // Higher values provide a more realistic simulation
60 // but can be a bit slower.
61 function wait(msec
, steps
) {
62 if (!steps
) steps
= 4;
63 for (var i
= 0; i
< steps
; i
++) {
64 $interval
.flush(msec
/steps
);
65 $timeout
.flush(msec
/steps
);
69 // TODO: Test: If the save function throws an error, or if its promise returns an error, reset form as dirty.
72 "fakeCtrl.doSave()": 'doSave',
73 "fakeCtrl.doSaveWithPromise()": 'doSaveWithPromise'
75 angular
.forEach(fakeSaves
, function(saveFunc
, saveFuncExpr
) {
76 it('calls ' + saveFuncExpr
+ ' twice over the course of three changes', function() {
77 element
= $compile('<form name="myForm" crm-autosave="' + saveFuncExpr
+ '" crm-autosave-model="model" crm-autosave-interval="{poll: 25, save: 50}"><input class="fieldA" ng-model="model.fieldA"><input class="fieldB" ng-model="model.fieldB"></form>')($rootScope
);
80 // check that we load pristine data and don't do any saving
82 expect(element
.find('.fieldA').val()).toBe('alpha');
83 expect(element
.find('.fieldB').val()).toBe('beta');
84 expect($rootScope
.myForm
.$pristine
).toBe(true);
85 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(0);
87 // first round of changes
88 element
.find('.fieldA').val('eh?').trigger('change');
90 element
.find('.fieldB').val('bee').trigger('change');
92 expect(model
.fieldA
).toBe('eh?');
93 expect(model
.fieldB
).toBe('bee');
94 expect($rootScope
.myForm
.$pristine
).toBe(false);
95 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(0);
99 expect($rootScope
.myForm
.$pristine
).toBe(true);
100 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
102 // a little stretch of time with nothing happening
104 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
106 // second round of changes
107 element
.find('.fieldA').val('ah').trigger('change');
108 $rootScope
.$digest();
109 expect(model
.fieldA
).toBe('ah');
112 expect($rootScope
.myForm
.$pristine
).toBe(false);
113 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
115 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(2);
116 expect($rootScope
.myForm
.$pristine
).toBe(true);
118 // a little stretch of time with nothing happening
120 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(2);
124 it('does not save an invalid form', function() {
125 element
= $compile('<form name="myForm" crm-autosave="fakeCtrl.doSave()" crm-autosave-model="model" crm-autosave-interval="{poll: 25, save: 50}"><input class="fieldA" ng-model="model.fieldA"><input class="fieldB" required ng-model="model.fieldB"></form>')($rootScope
);
126 $rootScope
.$digest();
128 // check that we load pristine data and don't do any saving
130 expect(element
.find('.fieldA').val()).toBe('alpha');
131 expect(element
.find('.fieldB').val()).toBe('beta');
132 expect($rootScope
.myForm
.$pristine
).toBe(true);
133 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
135 // first round of changes - fieldB is invalid
136 element
.find('.fieldA').val('eh?').trigger('change');
137 $rootScope
.$digest();
138 element
.find('.fieldB').val('').trigger('change');
139 $rootScope
.$digest();
140 expect(model
.fieldA
).toBe('eh?');
141 expect(model
.fieldB
).toBeFalsy();
142 expect($rootScope
.myForm
.$pristine
).toBe(false);
143 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
145 // first autosave declines to run
147 expect($rootScope
.myForm
.$pristine
).toBe(false);
148 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
150 // second round of changes
151 element
.find('.fieldB').val('bee').trigger('change');
152 $rootScope
.$digest();
153 expect(model
.fieldB
).toBe('bee');
156 expect($rootScope
.myForm
.$pristine
).toBe(false);
157 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
159 expect(fakeCtrl
.doSave
.calls
.count()).toBe(1);
160 expect($rootScope
.myForm
.$pristine
).toBe(true);
162 // a little stretch of time with nothing happening
164 expect(fakeCtrl
.doSave
.calls
.count()).toBe(1);
167 it('defers saving new changes when a save is already pending', function() {
168 element
= $compile('<form name="myForm" crm-autosave="fakeCtrl.doSaveSlowly()" crm-autosave-model="model" crm-autosave-interval="{poll: 25, save: 50}"><input class="fieldA" ng-model="model.fieldA"><input class="fieldB" ng-model="model.fieldB"></form>')($rootScope
);
169 $rootScope
.$digest();
171 // check that we load pristine data and don't do any saving
173 expect(element
.find('.fieldA').val()).toBe('alpha');
174 expect(element
.find('.fieldB').val()).toBe('beta');
175 expect($rootScope
.myForm
.$pristine
).toBe(true);
176 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(0);
178 // first round of changes
179 element
.find('.fieldA').val('eh?').trigger('change');
180 $rootScope
.$digest();
181 expect(model
.fieldA
).toBe('eh?');
182 expect($rootScope
.myForm
.$pristine
).toBe(false);
183 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(0);
185 // first autosave starts
187 expect(fakeCtrl
.savingSlowly
).toBe(true);
188 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
190 // second round of changes; doesn't save yet
191 element
.find('.fieldA').val('aleph').trigger('change');
192 $rootScope
.$digest();
193 expect(model
.fieldA
).toBe('aleph');
194 expect(fakeCtrl
.savingSlowly
).toBe(true);
195 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
197 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
199 // second autosave starts and finishes
201 expect(fakeCtrl
.savingSlowly
).toBe(false);
202 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(2);