1 describe('crmAutosave', function() {
3 function using(name
, values
, func
) {
4 for (var i
= 0, count
= values
.length
; i
< count
; i
++) {
5 if (Object
.prototype.toString
.call(values
[i
]) !== '[object Array]') {
6 values
[i
] = [values
[i
]];
8 func
.apply(this, values
[i
]);
9 jasmine
.currentEnv_
.currentSpec
.description
+= ' (with "' + name
+ '" using ' + values
[i
].join(', ') + ')';
13 beforeEach(function() {
15 module('crmAutosave');
18 describe('Autosave directive', function() {
27 beforeEach(inject(function(_
$compile_
, _
$rootScope_
, _
$interval_
, _
$timeout_
, _
$q_
) {
28 // The injector unwraps the underscores (_) from around the parameter names when matching
29 $compile
= _
$compile_
;
30 $rootScope
= _
$rootScope_
;
31 $interval
= _
$interval_
;
32 $timeout
= _
$timeout_
;
34 $rootScope
.fakeCtrl
= fakeCtrl
= {
37 doSaveWithPromise: function() {
38 var dfr
= _
$q_
.defer();
44 doSaveSlowly: function() {
45 var dfr
= _
$q_
.defer();
46 fakeCtrl
.savingSlowly
= true;
48 fakeCtrl
.savingSlowly
= false;
54 spyOn(fakeCtrl
, 'doSave').and
.callThrough();
55 spyOn(fakeCtrl
, 'doSaveWithPromise').and
.callThrough();
56 spyOn(fakeCtrl
, 'doSaveSlowly').and
.callThrough();
58 $rootScope
.model
= model
= {
64 // Fake wait - advance the interval & timeout
65 // @param int msec Total time to advance the clock
66 // @param int steps Number of times to issue flush()
67 // Higher values provide a more realistic simulation
68 // but can be a bit slower.
69 function wait(msec
, steps
) {
70 if (!steps
) steps
= 4;
71 for (var i
= 0; i
< steps
; i
++) {
72 $interval
.flush(msec
/steps
);
73 $timeout
.flush(msec
/steps
);
77 // TODO: Test: If the save function throws an error, or if its promise returns an error, reset form as dirty.
80 "fakeCtrl.doSave()": 'doSave',
81 "fakeCtrl.doSaveWithPromise()": 'doSaveWithPromise'
83 angular
.forEach(fakeSaves
, function(saveFunc
, saveFuncExpr
) {
84 it('calls ' + saveFuncExpr
+ ' twice over the course of three changes', function() {
85 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
);
88 // check that we load pristine data and don't do any saving
90 expect(element
.find('.fieldA').val()).toBe('alpha');
91 expect(element
.find('.fieldB').val()).toBe('beta');
92 expect($rootScope
.myForm
.$pristine
).toBe(true);
93 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(0);
95 // first round of changes
96 element
.find('.fieldA').val('eh?').trigger('change');
98 element
.find('.fieldB').val('bee').trigger('change');
100 expect(model
.fieldA
).toBe('eh?');
101 expect(model
.fieldB
).toBe('bee');
102 expect($rootScope
.myForm
.$pristine
).toBe(false);
103 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(0);
107 expect($rootScope
.myForm
.$pristine
).toBe(true);
108 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
110 // a little stretch of time with nothing happening
112 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
114 // second round of changes
115 element
.find('.fieldA').val('ah').trigger('change');
116 $rootScope
.$digest();
117 expect(model
.fieldA
).toBe('ah');
120 expect($rootScope
.myForm
.$pristine
).toBe(false);
121 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(1);
123 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(2);
124 expect($rootScope
.myForm
.$pristine
).toBe(true);
126 // a little stretch of time with nothing happening
128 expect(fakeCtrl
[saveFunc
].calls
.count()).toBe(2);
132 it('does not save an invalid form', function() {
133 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
);
134 $rootScope
.$digest();
136 // check that we load pristine data and don't do any saving
138 expect(element
.find('.fieldA').val()).toBe('alpha');
139 expect(element
.find('.fieldB').val()).toBe('beta');
140 expect($rootScope
.myForm
.$pristine
).toBe(true);
141 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
143 // first round of changes - fieldB is invalid
144 element
.find('.fieldA').val('eh?').trigger('change');
145 $rootScope
.$digest();
146 element
.find('.fieldB').val('').trigger('change');
147 $rootScope
.$digest();
148 expect(model
.fieldA
).toBe('eh?');
149 expect(model
.fieldB
).toBeFalsy();
150 expect($rootScope
.myForm
.$pristine
).toBe(false);
151 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
153 // first autosave declines to run
155 expect($rootScope
.myForm
.$pristine
).toBe(false);
156 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
158 // second round of changes
159 element
.find('.fieldB').val('bee').trigger('change');
160 $rootScope
.$digest();
161 expect(model
.fieldB
).toBe('bee');
164 expect($rootScope
.myForm
.$pristine
).toBe(false);
165 expect(fakeCtrl
.doSave
.calls
.count()).toBe(0);
167 expect(fakeCtrl
.doSave
.calls
.count()).toBe(1);
168 expect($rootScope
.myForm
.$pristine
).toBe(true);
170 // a little stretch of time with nothing happening
172 expect(fakeCtrl
.doSave
.calls
.count()).toBe(1);
175 it('defers saving new changes when a save is already pending', function() {
176 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
);
177 $rootScope
.$digest();
179 // check that we load pristine data and don't do any saving
181 expect(element
.find('.fieldA').val()).toBe('alpha');
182 expect(element
.find('.fieldB').val()).toBe('beta');
183 expect($rootScope
.myForm
.$pristine
).toBe(true);
184 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(0);
186 // first round of changes
187 element
.find('.fieldA').val('eh?').trigger('change');
188 $rootScope
.$digest();
189 expect(model
.fieldA
).toBe('eh?');
190 expect($rootScope
.myForm
.$pristine
).toBe(false);
191 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(0);
193 // first autosave starts
195 expect(fakeCtrl
.savingSlowly
).toBe(true);
196 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
198 // second round of changes; doesn't save yet
199 element
.find('.fieldA').val('aleph').trigger('change');
200 $rootScope
.$digest();
201 expect(model
.fieldA
).toBe('aleph');
202 expect(fakeCtrl
.savingSlowly
).toBe(true);
203 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
205 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(1);
207 // second autosave starts and finishes
209 expect(fakeCtrl
.savingSlowly
).toBe(false);
210 expect(fakeCtrl
.doSaveSlowly
.calls
.count()).toBe(2);