3 describe('crmAutosave', function() {
5 beforeEach(function() {
10 describe('Autosave directive', function() {
20 beforeEach(inject(function(_
$compile_
, _
$rootScope_
, _
$interval_
, _
$timeout_
, _
$q_
, _CrmAutosaveCtrl_
) {
21 // The injector unwraps the underscores (_) from around the parameter names when matching
22 $compile
= _
$compile_
;
23 $rootScope
= _
$rootScope_
;
24 $interval
= _
$interval_
;
25 $timeout
= _
$timeout_
;
26 CrmAutosaveCtrl
= _CrmAutosaveCtrl_
;
28 $rootScope
.fakeCtrl
= fakeCtrl
= {
31 doSaveWithPromise: function() {
32 var dfr
= _
$q_
.defer();
38 doSaveSlowly: function() {
39 var dfr
= _
$q_
.defer();
40 fakeCtrl
.savingSlowly
= true;
42 fakeCtrl
.savingSlowly
= false;
48 spyOn(fakeCtrl
, 'doSave').and
.callThrough();
49 spyOn(fakeCtrl
, 'doSaveWithPromise').and
.callThrough();
50 spyOn(fakeCtrl
, 'doSaveSlowly').and
.callThrough();
52 $rootScope
.model
= model
= {
58 // Fake wait - advance the interval & timeout
59 // @param int msec Total time to advance the clock
60 // @param int steps Number of times to issue flush()
61 // Higher values provide a more realistic simulation
62 // but can be a bit slower.
63 function wait(msec
, steps
) {
64 if (!steps
) steps
= 4;
65 for (var i
= 0; i
< steps
; i
++) {
66 $interval
.flush(msec
/steps
);
67 $timeout
.flush(msec
/steps
);
71 // TODO: Test: If the save function throws an error, or if its promise returns an error, reset form as dirty.
74 "fakeCtrl.doSave()": 'doSave',
75 "fakeCtrl.doSaveWithPromise()": 'doSaveWithPromise'
77 angular
.forEach(fakeSaves
, function(saveFunc
, saveFuncExpr
) {
78 it('calls ' + saveFuncExpr
+ ' twice over the course of three changes', function() {
79 var myAutosave
= $rootScope
.myAutosave
= new CrmAutosaveCtrl({
80 save
: fakeCtrl
[saveFunc
],
81 model: function(){ return model
; },
82 interval
: {poll
: 25, save
: 50},
83 form: function(){ return $rootScope
.myForm
; }
86 $rootScope
.$on('$destroy', myAutosave
.stop
);
87 element
= $compile('<form name="myForm"><input class="fieldA" ng-model="model.fieldA"><input class="fieldB" ng-model="model.fieldB"></form>')($rootScope
);
90 // check that we load pristine data and don't do any saving
92 expect(element
.find('.fieldA').val()).toBe('alpha');
93 expect(element
.find('.fieldB').val()).toBe('beta');
94 expect($rootScope
.myForm
.$pristine
).toBe(true);
95 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(0);
97 // first round of changes
98 element
.find('.fieldA').val('eh?').trigger('change');
100 element
.find('.fieldB').val('bee').trigger('change');
101 $rootScope
.$digest();
102 expect(model
.fieldA
).toBe('eh?');
103 expect(model
.fieldB
).toBe('bee');
104 expect($rootScope
.myForm
.$pristine
).toBe(false);
105 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(0);
109 expect($rootScope
.myForm
.$pristine
).toBe(true);
110 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
112 // a little stretch of time with nothing happening
114 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
116 // second round of changes
117 element
.find('.fieldA').val('ah').trigger('change');
118 $rootScope
.$digest();
119 expect(model
.fieldA
).toBe('ah');
122 expect($rootScope
.myForm
.$pristine
).toBe(false);
123 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
125 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(2);
126 expect($rootScope
.myForm
.$pristine
).toBe(true);
128 // a little stretch of time with nothing happening
130 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(2);
134 it('does not save an invalid form', function() {
135 var myAutosave
= $rootScope
.myAutosave
= new CrmAutosaveCtrl({
136 save
: fakeCtrl
.doSave
,
137 model: function(){ return model
; },
138 interval
: {poll
: 25, save
: 50},
139 form: function(){ return $rootScope
.myForm
; }
142 $rootScope
.$on('$destroy', myAutosave
.stop
);
143 element
= $compile('<form name="myForm"><input class="fieldA" ng-model="model.fieldA"><input class="fieldB" required ng-model="model.fieldB"></form>')($rootScope
);
144 $rootScope
.$digest();
146 // check that we load pristine data and don't do any saving
148 expect(element
.find('.fieldA').val()).toBe('alpha');
149 expect(element
.find('.fieldB').val()).toBe('beta');
150 expect($rootScope
.myForm
.$pristine
).toBe(true);
151 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
153 // first round of changes - fieldB is invalid
154 element
.find('.fieldA').val('eh?').trigger('change');
155 $rootScope
.$digest();
156 element
.find('.fieldB').val('').trigger('change');
157 $rootScope
.$digest();
158 expect(model
.fieldA
).toBe('eh?');
159 expect(model
.fieldB
).toBeFalsy();
160 expect($rootScope
.myForm
.$pristine
).toBe(false);
161 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
163 // first autosave declines to run
165 expect($rootScope
.myForm
.$pristine
).toBe(false);
166 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
168 // second round of changes
169 element
.find('.fieldB').val('bee').trigger('change');
170 $rootScope
.$digest();
171 expect(model
.fieldB
).toBe('bee');
174 expect($rootScope
.myForm
.$pristine
).toBe(false);
175 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
177 expect(fakeCtrl
.doSave
.calls
.count()).toBe(1);
178 expect($rootScope
.myForm
.$pristine
).toBe(true);
180 // a little stretch of time with nothing happening
182 expect(fakeCtrl
.doSave
.calls
.count()).toBe(1);
185 it('defers saving new changes when a save is already pending', function() {
186 var myAutosave
= $rootScope
.myAutosave
= new CrmAutosaveCtrl({
187 save
: fakeCtrl
.doSaveSlowly
,
188 model: function(){ return model
; },
189 interval
: {poll
: 25, save
: 50},
190 form: function(){ return $rootScope
.myForm
; }
193 $rootScope
.$on('$destroy', myAutosave
.stop
);
194 element
= $compile('<form name="myForm"><input class="fieldA" ng-model="model.fieldA"><input class="fieldB" ng-model="model.fieldB"></form>')($rootScope
);
195 $rootScope
.$digest();
197 // check that we load pristine data and don't do any saving
199 expect(element
.find('.fieldA').val()).toBe('alpha');
200 expect(element
.find('.fieldB').val()).toBe('beta');
201 expect($rootScope
.myForm
.$pristine
).toBe(true);
202 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(0);
204 // first round of changes
205 element
.find('.fieldA').val('eh?').trigger('change');
206 $rootScope
.$digest();
207 expect(model
.fieldA
).toBe('eh?');
208 expect($rootScope
.myForm
.$pristine
).toBe(false);
209 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(0);
211 // first autosave starts
213 expect(fakeCtrl
.savingSlowly
).toBe(true);
214 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
216 // second round of changes; doesn't save yet
217 element
.find('.fieldA').val('aleph').trigger('change');
218 $rootScope
.$digest();
219 expect(model
.fieldA
).toBe('aleph');
220 expect(fakeCtrl
.savingSlowly
).toBe(true);
221 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
223 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
225 // second autosave starts and finishes
227 expect(fakeCtrl
.savingSlowly
).toBe(false);
228 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(2);