Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: third_party/pkg/angular/test/directive/ng_model_spec.dart

Issue 256553002: Revert "Update all Angular libs (run update_all.sh)." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 library ng_model_spec; 1 library ng_model_spec;
2 2
3 import '../_specs.dart'; 3 import '../_specs.dart';
4 import 'dart:html' as dom; 4 import 'dart:html' as dom;
5 5
6 //-----------------------------------------------------------------------------
7 // Utility functions
8
9 /* This function simulates typing the given text into the input field. The
10 * text will be added wherever the insertion point happens to be. This method
11 * has as side-effect to set the focus on the input (without setting the
12 * focus, the text dispatch may not work).
13 */
14 void simulateTypingText(InputElement input, String text) {
15 input..focus()..dispatchEvent(new TextEvent('textInput', data: text));
16 }
17
18 bool simulateTypingTextWithConfirmation(InputElement input, String text,
19 { bool shouldWorkForChrome : true }) {
20 bool result;
21 String val = input.value;
22 try {
23 simulateTypingText(input, text);
24 result = input.value == val + text;
25 } catch (e) {
26 result = false;
27 }
28 if (!result && shouldWorkForChrome) expect(isBrowser('Chrome')).toBeFalsy();
29 return result;
30 }
31
32 bool isBrowser(String pattern) => dom.window.navigator.userAgent.indexOf(pattern ) > 0;
33
34 //-----------------------------------------------------------------------------
35
36 void main() { 6 void main() {
37 describe('ng-model', () { 7 describe('ng-model', () {
38 TestBed _; 8 TestBed _;
39 9
40 beforeEachModule((Module module) { 10 beforeEach(module((Module module) {
41 module 11 module..type(ControllerWithNoLove);
42 ..type(ControllerWithNoLove) 12 }));
43 ..type(MyCustomInputValidator)
44 ..type(CountingValidator);
45 });
46 13
47 beforeEach((TestBed tb) => _ = tb); 14 beforeEach(inject((TestBed tb) => _ = tb));
48 15
49 describe('type="text" like', () { 16 describe('type="text" like', () {
50 it('should update input value from model', () { 17 it('should update input value from model', inject(() {
51 _.compile('<input type="text" ng-model="model">'); 18 _.compile('<input type="text" ng-model="model">');
52 _.rootScope.apply(); 19 _.rootScope.apply();
53 20
54 expect((_.rootElement as dom.InputElement).value).toEqual(''); 21 expect((_.rootElement as dom.InputElement).value).toEqual('');
55 22
56 _.rootScope.apply('model = "misko"'); 23 _.rootScope.apply('model = "misko"');
57 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); 24 expect((_.rootElement as dom.InputElement).value).toEqual('misko');
58 }); 25 }));
59 26
60 it('should render null as the empty string', () { 27 it('should render null as the empty string', inject(() {
61 _.compile('<input type="text" ng-model="model">'); 28 _.compile('<input type="text" ng-model="model">');
62 _.rootScope.apply(); 29 _.rootScope.apply();
63 30
64 expect((_.rootElement as dom.InputElement).value).toEqual(''); 31 expect((_.rootElement as dom.InputElement).value).toEqual('');
65 32
66 _.rootScope.apply('model = null'); 33 _.rootScope.apply('model = null');
67 expect((_.rootElement as dom.InputElement).value).toEqual(''); 34 expect((_.rootElement as dom.InputElement).value).toEqual('');
68 }); 35 }));
69 36
70 it('should update model from the input value', () { 37 it('should update model from the input value', inject(() {
71 _.compile('<input type="text" ng-model="model" probe="p">'); 38 _.compile('<input type="text" ng-model="model" probe="p">');
72 Probe probe = _.rootScope.context['p']; 39 Probe probe = _.rootScope.context['p'];
73 var ngModel = probe.directive(NgModel); 40 var ngModel = probe.directive(NgModel);
74 InputElement inputElement = probe.element; 41 InputElement inputElement = probe.element;
75 42
76 inputElement.value = 'abc'; 43 inputElement.value = 'abc';
77 _.triggerEvent(inputElement, 'change'); 44 _.triggerEvent(inputElement, 'change');
78 expect(_.rootScope.context['model']).toEqual('abc'); 45 expect(_.rootScope.context['model']).toEqual('abc');
79 46
80 inputElement.value = 'def'; 47 inputElement.value = 'def';
81 var input = probe.directive(InputTextLike); 48 var input = probe.directive(InputTextLikeDirective);
82 input.processValue(); 49 input.processValue();
83 expect(_.rootScope.context['model']).toEqual('def'); 50 expect(_.rootScope.context['model']).toEqual('def');
84 }); 51 }));
85 52
86 it('should write to input only if the value is different', 53 it('should update model from the input value for type=number', inject(() {
87 (Injector i, Animate animate) {
88
89 var scope = _.rootScope;
90 var element = new dom.InputElement();
91 var ngElement = new NgElement(element, scope, animate);
92
93 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement());
94 nodeAttrs['ng-model'] = 'model';
95 var model = new NgModel(scope, ngElement, i.createChild([new Module()]),
96 nodeAttrs, new Animate());
97 dom.querySelector('body').append(element);
98 var input = new InputTextLike(element, model, scope);
99
100 element
101 ..value = 'abc'
102 ..selectionStart = 1
103 ..selectionEnd = 2;
104
105 scope.apply(() {
106 scope.context['model'] = 'abc';
107 });
108
109 expect(element.value).toEqual('abc');
110 // No update. selectionStart/End is unchanged.
111 expect(element.selectionStart).toEqual(1);
112 expect(element.selectionEnd).toEqual(2);
113
114 scope.apply(() {
115 scope.context['model'] = 'xyz';
116 });
117
118 // Value updated. selectionStart/End changed.
119 expect(element.value).toEqual('xyz');
120 expect(element.selectionStart).toEqual(3);
121 expect(element.selectionEnd).toEqual(3);
122 });
123
124 it('should only render the input value upon the next digest', (Scope scope ) {
125 _.compile('<input type="text" ng-model="model" probe="p">');
126 Probe probe = _.rootScope.context['p'];
127 var ngModel = probe.directive(NgModel);
128 InputElement inputElement = probe.element;
129
130 ngModel.render('xyz');
131 scope.context['model'] = 'xyz';
132
133 expect(inputElement.value).not.toEqual('xyz');
134
135 scope.apply();
136
137 expect(inputElement.value).toEqual('xyz');
138 });
139 });
140
141 describe('type="number" or type="range"', () {
142
143 it('should update model from the input value for type=number', () {
144 _.compile('<input type="number" ng-model="model" probe="p">'); 54 _.compile('<input type="number" ng-model="model" probe="p">');
145 Probe probe = _.rootScope.context['p']; 55 Probe probe = _.rootScope.context['p'];
146 var ngModel = probe.directive(NgModel); 56 var ngModel = probe.directive(NgModel);
147 InputElement inputElement = probe.element; 57 InputElement inputElement = probe.element;
148 58
149 inputElement.value = '12'; 59 inputElement.value = '12';
150 _.triggerEvent(inputElement, 'change'); 60 _.triggerEvent(inputElement, 'change');
151 expect(_.rootScope.context['model']).toEqual(12); 61 expect(_.rootScope.context['model']).toEqual(12);
152 62
153 inputElement.value = '14'; 63 inputElement.value = '14';
154 var input = probe.directive(InputNumberLike); 64 var input = probe.directive(InputNumberLikeDirective);
155 input.processValue(); 65 input.processValue();
156 expect(_.rootScope.context['model']).toEqual(14); 66 expect(_.rootScope.context['model']).toEqual(14);
157 }); 67 }));
158 68
159 it('should update input type=number to blank when model is null', () { 69 it('should update input type=number to blank when model is null', inject(( ) {
160 _.compile('<input type="number" ng-model="model" probe="p">'); 70 _.compile('<input type="number" ng-model="model" probe="p">');
161 Probe probe = _.rootScope.context['p']; 71 Probe probe = _.rootScope.context['p'];
162 var ngModel = probe.directive(NgModel); 72 var ngModel = probe.directive(NgModel);
163 InputElement inputElement = probe.element; 73 InputElement inputElement = probe.element;
164 74
165 inputElement.value = '12'; 75 inputElement.value = '12';
166 _.triggerEvent(inputElement, 'change'); 76 _.triggerEvent(inputElement, 'change');
167 expect(_.rootScope.context['model']).toEqual(12); 77 expect(_.rootScope.context['model']).toEqual(12);
168 78
169 _.rootScope.context['model'] = null; 79 _.rootScope.context['model'] = null;
170 _.rootScope.apply(); 80 _.rootScope.apply();
171 expect(inputElement.value).toEqual(''); 81 expect(inputElement.value).toEqual('');
172 }); 82 }));
173 83
174 it('should be invalid when the input value results in a NaN value', () { 84 it('should write to input only if value is different', inject((Injector i, AstParser parser) {
175 _.compile('<input type="number" ng-model="model" probe="p">'); 85 var scope = _.rootScope;
176 Probe probe = _.rootScope.context['p']; 86 var element = new dom.InputElement();
177 var ngModel = probe.directive(NgModel); 87 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement());
178 InputElement inputElement = probe.element; 88 nodeAttrs['ng-model'] = 'model';
89 var model = new NgModel(scope, element, i.createChild([new Module()]), n ew NgNullForm(), parser, nodeAttrs);
90 dom.querySelector('body').append(element);
91 var input = new InputTextLikeDirective(element, model, scope);
179 92
180 inputElement.value = 'aa'; 93 element
181 _.triggerEvent(inputElement, 'change'); 94 ..value = 'abc'
182 expect(_.rootScope.context['model'].isNaN).toBe(true); 95 ..selectionStart = 1
183 expect(ngModel.valid).toBe(false); 96 ..selectionEnd = 2;
184 });
185 97
186 it('should leave input unchanged when text does not represent a valid numb er', (Injector i) { 98 model.render('abc');
99
100 expect(element.value).toEqual('abc');
101 // No update. selectionStart/End is unchanged.
102 expect(element.selectionStart).toEqual(1);
103 expect(element.selectionEnd).toEqual(2);
104
105 model.render('xyz');
106
107 // Value updated. selectionStart/End changed.
108 expect(element.value).toEqual('xyz');
109 expect(element.selectionStart).toEqual(3);
110 expect(element.selectionEnd).toEqual(3);
111 }));
112 });
113
114 /* This function simulates typing the given text into the input
115 * field. The text will be added wherever the insertion point
116 * happens to be. This method has as side-effect to set the
117 * focus on the input (without setting the focus the text
118 * dispatch may not work).
119 */
120 void simulateTypingText(InputElement input, String text) {
121 input..focus()..dispatchEvent(new TextEvent('textInput', data: text));
122 }
123
124 describe('type="number" like', () {
125
126 it('should leave input unchanged when text does not represent a valid numb er', inject((Injector i) {
187 var modelFieldName = 'modelForNumFromInvalid1'; 127 var modelFieldName = 'modelForNumFromInvalid1';
188 var element = _.compile('<input type="number" ng-model="$modelFieldName" >'); 128 var element = _.compile('<input type="number" ng-model="$modelFieldName" >');
189 dom.querySelector('body').append(element); 129 dom.querySelector('body').append(element);
190 130
191 if (!simulateTypingTextWithConfirmation(element, '1')) return; // skip t est.
192 element.value = ''; // reset input
193
194 // This test will progressively enter the text '1e1' 131 // This test will progressively enter the text '1e1'
195 // '1' is a valid number. 132 // '1' is a valid number.
196 // '1e' is not a valid number. 133 // '1e' is not a valid number.
197 // '1e1' is again a valid number (with an exponent) 134 // '1e1' is again a valid number (with an exponent)
198 135
199 simulateTypingText(element, '1'); 136 simulateTypingText(element, '1');
200 _.triggerEvent(element, 'change'); 137 _.triggerEvent(element, 'change');
201 expect(element.value).toEqual('1'); 138 expect(element.value).toEqual('1');
202 expect(_.rootScope.context[modelFieldName]).toEqual(1); 139 expect(_.rootScope.context[modelFieldName]).toEqual(1);
203 140
204 simulateTypingText(element, 'e'); 141 simulateTypingText(element, 'e');
205 // Because the text is not a valid number, the element value is empty. 142 // Because the text is not a valid number, the element value is empty.
206 expect(element.value).toEqual(''); 143 expect(element.value).toEqual('');
207 // When the input is invalid, the model is [double.NAN]: 144 // When the input is invalid, the model is [double.NAN]:
208 _.triggerEvent(element, 'change'); 145 _.triggerEvent(element, 'change');
209 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy(); 146 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy();
210 147
211 simulateTypingText(element, '1'); 148 simulateTypingText(element, '1');
212 _.triggerEvent(element, 'change'); 149 _.triggerEvent(element, 'change');
213 expect(element.value).toEqual('1e1'); 150 expect(element.value).toEqual('1e1');
214 expect(_.rootScope.context[modelFieldName]).toEqual(10); 151 expect(_.rootScope.context[modelFieldName]).toEqual(10);
215 }); 152 }));
216 153
217 it('should not reformat user input to equivalent numeric representation', (Injector i) { 154 it('should not reformat user input to equivalent numeric representation', inject((Injector i) {
218 var modelFieldName = 'modelForNumFromInvalid2'; 155 var modelFieldName = 'modelForNumFromInvalid2';
219 var element = _.compile('<input type="number" ng-model="$modelFieldName" >'); 156 var element = _.compile('<input type="number" ng-model="$modelFieldName" >');
220 dom.querySelector('body').append(element); 157 dom.querySelector('body').append(element);
221 158
222 if (!simulateTypingTextWithConfirmation(element, '1')) return; // skip t est.
223 element.value = ''; // reset input
224
225 simulateTypingText(element, '1e-1'); 159 simulateTypingText(element, '1e-1');
226 expect(element.value).toEqual('1e-1'); 160 expect(element.value).toEqual('1e-1');
227 expect(_.rootScope.context[modelFieldName]).toEqual(0.1); 161 expect(_.rootScope.context[modelFieldName]).toEqual(0.1);
228 }); 162 }));
229 163
230 it('should update input value from model', () { 164 it('should update input value from model', inject(() {
231 _.compile('<input type="number" ng-model="model">'); 165 _.compile('<input type="number" ng-model="model">');
232 _.rootScope.apply(); 166 _.rootScope.apply();
233 167
234 _.rootScope.apply('model = 42'); 168 _.rootScope.apply('model = 42');
235 expect((_.rootElement as dom.InputElement).value).toEqual('42'); 169 expect((_.rootElement as dom.InputElement).value).toEqual('42');
236 }); 170 }));
237 171
238 it('should update input value from model for range inputs', () { 172 it('should update input value from model for range inputs', inject(() {
239 _.compile('<input type="range" ng-model="model">'); 173 _.compile('<input type="range" ng-model="model">');
240 _.rootScope.apply(); 174 _.rootScope.apply();
241 175
242 _.rootScope.apply('model = 42'); 176 _.rootScope.apply('model = 42');
243 expect((_.rootElement as dom.InputElement).value).toEqual('42'); 177 expect((_.rootElement as dom.InputElement).value).toEqual('42');
244 }); 178 }));
245 179
246 it('should update model from the input value', () { 180 it('should update model from the input value', inject(() {
247 _.compile('<input type="number" ng-model="model" probe="p">'); 181 _.compile('<input type="number" ng-model="model" probe="p">');
248 Probe probe = _.rootScope.context['p']; 182 Probe probe = _.rootScope.context['p'];
249 var ngModel = probe.directive(NgModel); 183 var ngModel = probe.directive(NgModel);
250 InputElement inputElement = probe.element; 184 InputElement inputElement = probe.element;
251 185
252 inputElement.value = '42'; 186 inputElement.value = '42';
253 _.triggerEvent(inputElement, 'change'); 187 _.triggerEvent(inputElement, 'change');
254 expect(_.rootScope.context['model']).toEqual(42); 188 expect(_.rootScope.context['model']).toEqual(42);
255 189
256 inputElement.value = '43'; 190 inputElement.value = '43';
257 var input = probe.directive(InputNumberLike); 191 var input = probe.directive(InputNumberLikeDirective);
258 input.processValue(); 192 input.processValue();
259 expect(_.rootScope.context['model']).toEqual(43); 193 expect(_.rootScope.context['model']).toEqual(43);
260 }); 194 }));
261 195
262 it('should update model to NaN from a blank input value', () { 196 it('should update model to NaN from a blank input value', inject(() {
263 _.compile('<input type="number" ng-model="model" probe="p">'); 197 _.compile('<input type="number" ng-model="model" probe="p">');
264 Probe probe = _.rootScope.context['p']; 198 Probe probe = _.rootScope.context['p'];
265 var ngModel = probe.directive(NgModel); 199 var ngModel = probe.directive(NgModel);
266 InputElement inputElement = probe.element; 200 InputElement inputElement = probe.element;
267 201
268 inputElement.value = ''; 202 inputElement.value = '';
269 _.triggerEvent(inputElement, 'change'); 203 _.triggerEvent(inputElement, 'change');
270 expect(_.rootScope.context['model'].isNaN).toBeTruthy(); 204 expect(_.rootScope.context['model'].isNaN).toBeTruthy();
271 }); 205 }));
272 206
273 it('should update model from the input value for range inputs', () { 207 it('should update model from the input value for range inputs', inject(() {
274 _.compile('<input type="range" ng-model="model" probe="p">'); 208 _.compile('<input type="range" ng-model="model" probe="p">');
275 Probe probe = _.rootScope.context['p']; 209 Probe probe = _.rootScope.context['p'];
276 var ngModel = probe.directive(NgModel); 210 var ngModel = probe.directive(NgModel);
277 InputElement inputElement = probe.element; 211 InputElement inputElement = probe.element;
278 212
279 inputElement.value = '42'; 213 inputElement.value = '42';
280 _.triggerEvent(inputElement, 'change'); 214 _.triggerEvent(inputElement, 'change');
281 expect(_.rootScope.context['model']).toEqual(42); 215 expect(_.rootScope.context['model']).toEqual(42);
282 216
283 inputElement.value = '43'; 217 inputElement.value = '43';
284 var input = probe.directive(InputNumberLike); 218 var input = probe.directive(InputNumberLikeDirective);
285 input.processValue(); 219 input.processValue();
286 expect(_.rootScope.context['model']).toEqual(43); 220 expect(_.rootScope.context['model']).toEqual(43);
287 }); 221 }));
288 222
289 it('should update model to a native default value from a blank range input value', () { 223 it('should update model to a native default value from a blank range input value', inject(() {
290 _.compile('<input type="range" ng-model="model" probe="p">'); 224 _.compile('<input type="range" ng-model="model" probe="p">');
291 Probe probe = _.rootScope.context['p']; 225 Probe probe = _.rootScope.context['p'];
292 var ngModel = probe.directive(NgModel); 226 var ngModel = probe.directive(NgModel);
293 InputElement inputElement = probe.element; 227 InputElement inputElement = probe.element;
294 228
295 inputElement.value = ''; 229 inputElement.value = '';
296 _.triggerEvent(inputElement, 'change'); 230 _.triggerEvent(inputElement, 'change');
297 expect(_.rootScope.context['model']).toBeDefined(); 231 expect(_.rootScope.context['model']).toBeDefined();
298 }); 232 }));
299 233
300 it('should render null as blank', () { 234 it('should render null as blank', inject(() {
301 _.compile('<input type="number" ng-model="model">'); 235 _.compile('<input type="number" ng-model="model">');
302 _.rootScope.apply(); 236 _.rootScope.apply();
303 237
304 _.rootScope.apply('model = null'); 238 _.rootScope.apply('model = null');
305 expect((_.rootElement as dom.InputElement).value).toEqual(''); 239 expect((_.rootElement as dom.InputElement).value).toEqual('');
306 }); 240 }));
307
308 it('should only render the input value upon the next digest', (Scope scope ) {
309 _.compile('<input type="number" ng-model="model" probe="p">');
310 Probe probe = _.rootScope.context['p'];
311 var ngModel = probe.directive(NgModel);
312 InputElement inputElement = probe.element;
313
314 ngModel.render(123);
315 scope.context['model'] = 123;
316
317 expect(inputElement.value).not.toEqual('123');
318
319 scope.apply();
320
321 expect(inputElement.value).toEqual('123');
322 });
323 241
324 }); 242 });
325 243
326 describe('type="password"', () { 244 describe('type="password"', () {
327 it('should update input value from model', () { 245 it('should update input value from model', inject(() {
328 _.compile('<input type="password" ng-model="model">'); 246 _.compile('<input type="password" ng-model="model">');
329 _.rootScope.apply(); 247 _.rootScope.apply();
330 248
331 expect((_.rootElement as dom.InputElement).value).toEqual(''); 249 expect((_.rootElement as dom.InputElement).value).toEqual('');
332 250
333 _.rootScope.apply('model = "misko"'); 251 _.rootScope.apply('model = "misko"');
334 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); 252 expect((_.rootElement as dom.InputElement).value).toEqual('misko');
335 }); 253 }));
336 254
337 it('should render null as the empty string', () { 255 it('should render null as the empty string', inject(() {
338 _.compile('<input type="password" ng-model="model">'); 256 _.compile('<input type="password" ng-model="model">');
339 _.rootScope.apply(); 257 _.rootScope.apply();
340 258
341 expect((_.rootElement as dom.InputElement).value).toEqual(''); 259 expect((_.rootElement as dom.InputElement).value).toEqual('');
342 260
343 _.rootScope.apply('model = null'); 261 _.rootScope.apply('model = null');
344 expect((_.rootElement as dom.InputElement).value).toEqual(''); 262 expect((_.rootElement as dom.InputElement).value).toEqual('');
345 }); 263 }));
346 264
347 it('should update model from the input value', () { 265 it('should update model from the input value', inject(() {
348 _.compile('<input type="password" ng-model="model" probe="p">'); 266 _.compile('<input type="password" ng-model="model" probe="p">');
349 Probe probe = _.rootScope.context['p']; 267 Probe probe = _.rootScope.context['p'];
350 var ngModel = probe.directive(NgModel); 268 var ngModel = probe.directive(NgModel);
351 InputElement inputElement = probe.element; 269 InputElement inputElement = probe.element;
352 270
353 inputElement.value = 'abc'; 271 inputElement.value = 'abc';
354 _.triggerEvent(inputElement, 'change'); 272 _.triggerEvent(inputElement, 'change');
355 expect(_.rootScope.context['model']).toEqual('abc'); 273 expect(_.rootScope.context['model']).toEqual('abc');
356 274
357 inputElement.value = 'def'; 275 inputElement.value = 'def';
358 var input = probe.directive(InputTextLike); 276 var input = probe.directive(InputTextLikeDirective);
359 input.processValue(); 277 input.processValue();
360 expect(_.rootScope.context['model']).toEqual('def'); 278 expect(_.rootScope.context['model']).toEqual('def');
361 279
362 }); 280 }));
363 281
364 it('should write to input only if value is different', 282 it('should write to input only if value is different', inject((Injector i, AstParser parser) {
365 (Injector i, Animate animate) {
366
367 var scope = _.rootScope; 283 var scope = _.rootScope;
368 var element = new dom.InputElement(); 284 var element = new dom.InputElement();
369 var ngElement = new NgElement(element, scope, animate);
370
371 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); 285 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement());
372 nodeAttrs['ng-model'] = 'model'; 286 nodeAttrs['ng-model'] = 'model';
373 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), 287 var model = new NgModel(scope, element, i.createChild([new Module()]), n ew NgNullForm(), parser, nodeAttrs);
374 nodeAttrs, new Animate());
375 dom.querySelector('body').append(element); 288 dom.querySelector('body').append(element);
376 var input = new InputTextLike(element, model, scope); 289 var input = new InputTextLikeDirective(element, model, scope);
377 290
378 element 291 element
379 ..value = 'abc' 292 ..value = 'abc'
380 ..selectionStart = 1 293 ..selectionStart = 1
381 ..selectionEnd = 2; 294 ..selectionEnd = 2;
382 295
383 scope.apply(() { 296 model.render('abc');
384 scope.context['model'] = 'abc';
385 });
386 297
387 expect(element.value).toEqual('abc'); 298 expect(element.value).toEqual('abc');
388 expect(element.selectionStart).toEqual(1); 299 expect(element.selectionStart).toEqual(1);
389 expect(element.selectionEnd).toEqual(2); 300 expect(element.selectionEnd).toEqual(2);
390 301
391 scope.apply(() { 302 model.render('xyz');
392 scope.context['model'] = 'xyz';
393 });
394 303
395 expect(element.value).toEqual('xyz'); 304 expect(element.value).toEqual('xyz');
396 expect(element.selectionStart).toEqual(3); 305 expect(element.selectionStart).toEqual(3);
397 expect(element.selectionEnd).toEqual(3); 306 expect(element.selectionEnd).toEqual(3);
398 }); 307 }));
399
400 it('should only render the input value upon the next digest', (Scope scope ) {
401 _.compile('<input type="password" ng-model="model" probe="p">');
402 Probe probe = _.rootScope.context['p'];
403 var ngModel = probe.directive(NgModel);
404 InputElement inputElement = probe.element;
405
406 ngModel.render('xyz');
407 scope.context['model'] = 'xyz';
408
409 expect(inputElement.value).not.toEqual('xyz');
410
411 scope.apply();
412
413 expect(inputElement.value).toEqual('xyz');
414 });
415 }); 308 });
416 309
417 describe('type="search"', () { 310 describe('type="search"', () {
418 it('should update input value from model', () { 311 it('should update input value from model', inject(() {
419 _.compile('<input type="search" ng-model="model">'); 312 _.compile('<input type="search" ng-model="model">');
420 _.rootScope.apply(); 313 _.rootScope.apply();
421 314
422 expect((_.rootElement as dom.InputElement).value).toEqual(''); 315 expect((_.rootElement as dom.InputElement).value).toEqual('');
423 316
424 _.rootScope.apply('model = "misko"'); 317 _.rootScope.apply('model = "misko"');
425 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); 318 expect((_.rootElement as dom.InputElement).value).toEqual('misko');
426 }); 319 }));
427 320
428 it('should render null as the empty string', () { 321 it('should render null as the empty string', inject(() {
429 _.compile('<input type="search" ng-model="model">'); 322 _.compile('<input type="search" ng-model="model">');
430 _.rootScope.apply(); 323 _.rootScope.apply();
431 324
432 expect((_.rootElement as dom.InputElement).value).toEqual(''); 325 expect((_.rootElement as dom.InputElement).value).toEqual('');
433 326
434 _.rootScope.apply('model = null'); 327 _.rootScope.apply('model = null');
435 expect((_.rootElement as dom.InputElement).value).toEqual(''); 328 expect((_.rootElement as dom.InputElement).value).toEqual('');
436 }); 329 }));
437 330
438 it('should update model from the input value', () { 331 it('should update model from the input value', inject(() {
439 _.compile('<input type="search" ng-model="model" probe="p">'); 332 _.compile('<input type="search" ng-model="model" probe="p">');
440 Probe probe = _.rootScope.context['p']; 333 Probe probe = _.rootScope.context['p'];
441 var ngModel = probe.directive(NgModel); 334 var ngModel = probe.directive(NgModel);
442 InputElement inputElement = probe.element; 335 InputElement inputElement = probe.element;
443 336
444 inputElement.value = 'abc'; 337 inputElement.value = 'abc';
445 _.triggerEvent(inputElement, 'change'); 338 _.triggerEvent(inputElement, 'change');
446 expect(_.rootScope.context['model']).toEqual('abc'); 339 expect(_.rootScope.context['model']).toEqual('abc');
447 340
448 inputElement.value = 'def'; 341 inputElement.value = 'def';
449 var input = probe.directive(InputTextLike); 342 var input = probe.directive(InputTextLikeDirective);
450 input.processValue(); 343 input.processValue();
451 expect(_.rootScope.context['model']).toEqual('def'); 344 expect(_.rootScope.context['model']).toEqual('def');
452 }); 345 }));
453 346
454 it('should write to input only if value is different', 347 it('should write to input only if value is different', inject((Injector i, AstParser parser) {
455 (Injector i, Animate animate) {
456
457 var scope = _.rootScope; 348 var scope = _.rootScope;
458 var element = new dom.InputElement(); 349 var element = new dom.InputElement();
459 var ngElement = new NgElement(element, scope, animate);
460
461 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); 350 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement());
462 nodeAttrs['ng-model'] = 'model'; 351 nodeAttrs['ng-model'] = 'model';
463 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), 352 var model = new NgModel(scope, element, i.createChild([new Module()]), n ew NgNullForm(), parser, nodeAttrs);
464 nodeAttrs, new Animate());
465 dom.querySelector('body').append(element); 353 dom.querySelector('body').append(element);
466 var input = new InputTextLike(element, model, scope); 354 var input = new InputTextLikeDirective(element, model, scope);
467 355
468 element 356 element
469 ..value = 'abc' 357 ..value = 'abc'
470 ..selectionStart = 1 358 ..selectionStart = 1
471 ..selectionEnd = 2; 359 ..selectionEnd = 2;
472 360
473 scope.apply(() { 361 model.render('abc');
474 scope.context['model'] = 'abc';
475 });
476 362
477 expect(element.value).toEqual('abc'); 363 expect(element.value).toEqual('abc');
478 // No update. selectionStart/End is unchanged. 364 // No update. selectionStart/End is unchanged.
479 expect(element.selectionStart).toEqual(1); 365 expect(element.selectionStart).toEqual(1);
480 expect(element.selectionEnd).toEqual(2); 366 expect(element.selectionEnd).toEqual(2);
481 367
482 scope.apply(() { 368 model.render('xyz');
483 scope.context['model'] = 'xyz';
484 });
485 369
486 // Value updated. selectionStart/End changed. 370 // Value updated. selectionStart/End changed.
487 expect(element.value).toEqual('xyz'); 371 expect(element.value).toEqual('xyz');
488 expect(element.selectionStart).toEqual(3); 372 expect(element.selectionStart).toEqual(3);
489 expect(element.selectionEnd).toEqual(3); 373 expect(element.selectionEnd).toEqual(3);
490 }); 374 }));
491
492 it('should only render the input value upon the next digest', (Scope scope ) {
493 _.compile('<input type="search" ng-model="model" probe="p">');
494 Probe probe = _.rootScope.context['p'];
495 var ngModel = probe.directive(NgModel);
496 InputElement inputElement = probe.element;
497
498 ngModel.render('xyz');
499 scope.context['model'] = 'xyz';
500
501 expect(inputElement.value).not.toEqual('xyz');
502
503 scope.apply();
504
505 expect(inputElement.value).toEqual('xyz');
506 });
507 }); 375 });
508 376
509 describe('no type attribute', () { 377 describe('no type attribute', () {
510 it('should be set "text" as default value for "type" attribute', () { 378 it('should be set "text" as default value for "type" attribute', inject(() {
511 _.compile('<input ng-model="model">'); 379 _.compile('<input ng-model="model">');
512 _.rootScope.apply(); 380 _.rootScope.apply();
513 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual(' text'); 381 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual(' text');
514 }); 382 }));
515 383
516 it('should update input value from model', () { 384 it('should update input value from model', inject(() {
517 _.compile('<input ng-model="model">'); 385 _.compile('<input ng-model="model">');
518 _.rootScope.apply(); 386 _.rootScope.apply();
519 387
520 expect((_.rootElement as dom.InputElement).value).toEqual(''); 388 expect((_.rootElement as dom.InputElement).value).toEqual('');
521 389
522 _.rootScope.apply('model = "misko"'); 390 _.rootScope.apply('model = "misko"');
523 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); 391 expect((_.rootElement as dom.InputElement).value).toEqual('misko');
524 }); 392 }));
525 393
526 it('should render null as the empty string', () { 394 it('should render null as the empty string', inject(() {
527 _.compile('<input ng-model="model">'); 395 _.compile('<input ng-model="model">');
528 _.rootScope.apply(); 396 _.rootScope.apply();
529 397
530 expect((_.rootElement as dom.InputElement).value).toEqual(''); 398 expect((_.rootElement as dom.InputElement).value).toEqual('');
531 399
532 _.rootScope.apply('model = null'); 400 _.rootScope.apply('model = null');
533 expect((_.rootElement as dom.InputElement).value).toEqual(''); 401 expect((_.rootElement as dom.InputElement).value).toEqual('');
534 }); 402 }));
535 403
536 it('should update model from the input value', () { 404 it('should update model from the input value', inject(() {
537 _.compile('<input ng-model="model" probe="p">'); 405 _.compile('<input ng-model="model" probe="p">');
538 Probe probe = _.rootScope.context['p']; 406 Probe probe = _.rootScope.context['p'];
539 var ngModel = probe.directive(NgModel); 407 var ngModel = probe.directive(NgModel);
540 InputElement inputElement = probe.element; 408 InputElement inputElement = probe.element;
541 409
542 inputElement.value = 'abc'; 410 inputElement.value = 'abc';
543 _.triggerEvent(inputElement, 'change'); 411 _.triggerEvent(inputElement, 'change');
544 expect(_.rootScope.context['model']).toEqual('abc'); 412 expect(_.rootScope.context['model']).toEqual('abc');
545 413
546 inputElement.value = 'def'; 414 inputElement.value = 'def';
547 var input = probe.directive(InputTextLike); 415 var input = probe.directive(InputTextLikeDirective);
548 input.processValue(); 416 input.processValue();
549 expect(_.rootScope.context['model']).toEqual('def'); 417 expect(_.rootScope.context['model']).toEqual('def');
550 }); 418 }));
551 419
552 it('should write to input only if value is different', 420 it('should write to input only if value is different', inject((Injector i, AstParser parser) {
553 (Injector i, Animate animate) {
554
555 var scope = _.rootScope; 421 var scope = _.rootScope;
556 var element = new dom.InputElement(); 422 var element = new dom.InputElement();
557 var ngElement = new NgElement(element, scope, animate);
558
559 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); 423 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement());
560 nodeAttrs['ng-model'] = 'model'; 424 nodeAttrs['ng-model'] = 'model';
561 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), 425 var model = new NgModel(scope, element, i.createChild([new Module()]), n ew NgNullForm(), parser, nodeAttrs);
562 nodeAttrs, new Animate());
563 dom.querySelector('body').append(element); 426 dom.querySelector('body').append(element);
564 var input = new InputTextLike(element, model, scope); 427 var input = new InputTextLikeDirective(element, model, scope);
565 428
566 element 429 element
567 ..value = 'abc' 430 ..value = 'abc'
568 ..selectionStart = 1 431 ..selectionStart = 1
569 ..selectionEnd = 2; 432 ..selectionEnd = 2;
570 433
571 scope.apply(() { 434 model.render('abc');
572 scope.context['model'] = 'abc';
573 });
574 435
575 expect(element.value).toEqual('abc'); 436 expect(element.value).toEqual('abc');
576 expect(element.selectionStart).toEqual(1); 437 expect(element.selectionStart).toEqual(1);
577 expect(element.selectionEnd).toEqual(2); 438 expect(element.selectionEnd).toEqual(2);
578 439
579 scope.apply(() { 440 model.render('xyz');
580 scope.context['model'] = 'xyz';
581 });
582 441
583 expect(element.value).toEqual('xyz'); 442 expect(element.value).toEqual('xyz');
584 expect(element.selectionStart).toEqual(3); 443 expect(element.selectionStart).toEqual(3);
585 expect(element.selectionEnd).toEqual(3); 444 expect(element.selectionEnd).toEqual(3);
586 }); 445 }));
587
588 it('should only render the input value upon the next digest', (Scope scope ) {
589 _.compile('<input ng-model="model" probe="p">');
590 Probe probe = _.rootScope.context['p'];
591 var ngModel = probe.directive(NgModel);
592 InputElement inputElement = probe.element;
593
594 ngModel.render('xyz');
595 scope.context['model'] = 'xyz';
596
597 expect(inputElement.value).not.toEqual('xyz');
598
599 scope.apply();
600
601 expect(inputElement.value).toEqual('xyz');
602 });
603 }); 446 });
604 447
605 describe('type="checkbox"', () { 448 describe('type="checkbox"', () {
606 it('should update input value from model', (Scope scope) { 449 it('should update input value from model', inject((Scope scope) {
607 var element = _.compile('<input type="checkbox" ng-model="model">'); 450 var element = _.compile('<input type="checkbox" ng-model="model">');
608 451
609 scope.apply(() { 452 scope.apply(() {
610 scope.context['model'] = true; 453 scope.context['model'] = true;
611 }); 454 });
612 expect(element.checked).toBe(true); 455 expect(element.checked).toBe(true);
613 456
614 scope.apply(() { 457 scope.apply(() {
615 scope.context['model'] = false; 458 scope.context['model'] = false;
616 }); 459 });
617 expect(element.checked).toBe(false); 460 expect(element.checked).toBe(false);
618 }); 461 }));
619 462
620 it('should render as dirty when checked', (Scope scope) { 463 it('should render as dirty when checked', inject((Scope scope) {
621 var element = _.compile('<input type="text" ng-model="my_model" probe="i " />'); 464 var element = _.compile('<input type="text" ng-model="my_model" probe="i " />');
622 Probe probe = _.rootScope.context['i']; 465 Probe probe = _.rootScope.context['i'];
623 var model = probe.directive(NgModel); 466 var model = probe.directive(NgModel);
624 467
625 expect(model.pristine).toEqual(true); 468 expect(model.pristine).toEqual(true);
626 expect(model.dirty).toEqual(false); 469 expect(model.dirty).toEqual(false);
627 470
628 _.triggerEvent(element, 'change'); 471 _.triggerEvent(element, 'change');
629 472
630 expect(model.pristine).toEqual(false); 473 expect(model.pristine).toEqual(false);
631 expect(model.dirty).toEqual(true); 474 expect(model.dirty).toEqual(true);
632 }); 475 }));
633 476
634 it('should update input value from model using ng-true-value/false', (Scop e scope) { 477
478 it('should update input value from model using ng-true-value/false', injec t((Scope scope) {
635 var element = _.compile('<input type="checkbox" ng-model="model" ng-true -value="1" ng-false-value="0">'); 479 var element = _.compile('<input type="checkbox" ng-model="model" ng-true -value="1" ng-false-value="0">');
636 480
637 scope.apply(() { 481 scope.apply(() {
638 scope.context['model'] = 1; 482 scope.context['model'] = 1;
639 }); 483 });
640 expect(element.checked).toBe(true); 484 expect(element.checked).toBe(true);
641 485
642 scope.apply(() { 486 scope.apply(() {
643 scope.context['model'] = 0; 487 scope.context['model'] = 0;
644 }); 488 });
645 expect(element.checked).toBe(false); 489 expect(element.checked).toBe(false);
646 490
647 element.checked = true; 491 element.checked = true;
648 _.triggerEvent(element, 'change'); 492 _.triggerEvent(element, 'change');
649 expect(scope.context['model']).toBe(1); 493 expect(scope.context['model']).toBe(1);
650 494
651 element.checked = false; 495 element.checked = false;
652 _.triggerEvent(element, 'change'); 496 _.triggerEvent(element, 'change');
653 expect(scope.context['model']).toBe(0); 497 expect(scope.context['model']).toBe(0);
654 }); 498 }));
655 499
656 it('should allow non boolean values like null, 0, 1', (Scope scope) { 500
501 it('should allow non boolean values like null, 0, 1', inject((Scope scope) {
657 var element = _.compile('<input type="checkbox" ng-model="model">'); 502 var element = _.compile('<input type="checkbox" ng-model="model">');
658 503
659 scope.apply(() { 504 scope.apply(() {
660 scope.context['model'] = 0; 505 scope.context['model'] = 0;
661 }); 506 });
662 expect(element.checked).toBe(false); 507 expect(element.checked).toBe(false);
663 508
664 scope.apply(() { 509 scope.apply(() {
665 scope.context['model'] = 1; 510 scope.context['model'] = 1;
666 }); 511 });
667 expect(element.checked).toBe(true); 512 expect(element.checked).toBe(true);
668 513
669 scope.apply(() { 514 scope.apply(() {
670 scope.context['model'] = null; 515 scope.context['model'] = null;
671 }); 516 });
672 expect(element.checked).toBe(false); 517 expect(element.checked).toBe(false);
673 }); 518 }));
674 519
675 it('should update model from the input value', (Scope scope) { 520
521 it('should update model from the input value', inject((Scope scope) {
676 var element = _.compile('<input type="checkbox" ng-model="model">'); 522 var element = _.compile('<input type="checkbox" ng-model="model">');
677 523
678 element.checked = true; 524 element.checked = true;
679 _.triggerEvent(element, 'change'); 525 _.triggerEvent(element, 'change');
680 expect(scope.context['model']).toBe(true); 526 expect(scope.context['model']).toBe(true);
681 527
682 element.checked = false; 528 element.checked = false;
683 _.triggerEvent(element, 'change'); 529 _.triggerEvent(element, 'change');
684 expect(scope.context['model']).toBe(false); 530 expect(scope.context['model']).toBe(false);
685 }); 531 }));
686
687 it('should update model from the input using ng-true-value/false', (Scope scope) {
688 var element = _.compile('<input type="checkbox" ng-model="model" '
689 'ng-true-value="yes" ng-false-value="no">');
690 scope.apply(() {
691 scope.context['yes'] = 'yes sir!';
692 scope.context['no'] = 'no, sorry';
693 });
694
695 element.checked = true;
696 _.triggerEvent(element, 'change');
697 expect(scope.context['model']).toEqual('yes sir!');
698
699 element.checked = false;
700 _.triggerEvent(element, 'change');
701 expect(scope.context['model']).toEqual('no, sorry');
702 });
703
704 it('should only render the input value upon the next digest', (Scope scope ) {
705 _.compile('<input type="checkbox" ng-model="model" probe="p">');
706 Probe probe = _.rootScope.context['p'];
707 var ngModel = probe.directive(NgModel);
708 InputElement inputElement = probe.element;
709
710 ngModel.render('xyz');
711 scope.context['model'] = true;
712
713 expect(inputElement.checked).toBe(false);
714
715 scope.apply();
716
717 expect(inputElement.checked).toBe(true);
718 });
719 }); 532 });
720 533
721 describe('textarea', () { 534 describe('textarea', () {
722 it('should update textarea value from model', () { 535 it('should update textarea value from model', inject(() {
723 _.compile('<textarea ng-model="model">'); 536 _.compile('<textarea ng-model="model">');
724 _.rootScope.apply(); 537 _.rootScope.apply();
725 538
726 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); 539 expect((_.rootElement as dom.TextAreaElement).value).toEqual('');
727 540
728 _.rootScope.apply('model = "misko"'); 541 _.rootScope.apply('model = "misko"');
729 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); 542 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko');
730 }); 543 }));
731 544
732 it('should render null as the empty string', () { 545 it('should render null as the empty string', inject(() {
733 _.compile('<textarea ng-model="model">'); 546 _.compile('<textarea ng-model="model">');
734 _.rootScope.apply(); 547 _.rootScope.apply();
735 548
736 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); 549 expect((_.rootElement as dom.TextAreaElement).value).toEqual('');
737 550
738 _.rootScope.apply('model = null'); 551 _.rootScope.apply('model = null');
739 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); 552 expect((_.rootElement as dom.TextAreaElement).value).toEqual('');
740 }); 553 }));
741 554
742 it('should update model from the input value', () { 555 it('should update model from the input value', inject(() {
743 _.compile('<textarea ng-model="model" probe="p">'); 556 _.compile('<textarea ng-model="model" probe="p">');
744 Probe probe = _.rootScope.context['p']; 557 Probe probe = _.rootScope.context['p'];
745 var ngModel = probe.directive(NgModel); 558 var ngModel = probe.directive(NgModel);
746 TextAreaElement element = probe.element; 559 TextAreaElement element = probe.element;
747 560
748 element.value = 'abc'; 561 element.value = 'abc';
749 _.triggerEvent(element, 'change'); 562 _.triggerEvent(element, 'change');
750 expect(_.rootScope.context['model']).toEqual('abc'); 563 expect(_.rootScope.context['model']).toEqual('abc');
751 564
752 element.value = 'def'; 565 element.value = 'def';
753 var textarea = probe.directive(InputTextLike); 566 var textarea = probe.directive(InputTextLikeDirective);
754 textarea.processValue(); 567 textarea.processValue();
755 expect(_.rootScope.context['model']).toEqual('def'); 568 expect(_.rootScope.context['model']).toEqual('def');
756 569
757 }); 570 }));
758 571
759 // NOTE(deboer): This test passes on Dartium, but fails in the content_she ll. 572 // NOTE(deboer): This test passes on Dartium, but fails in the content_she ll.
760 // The Dart team is looking into this bug. 573 // The Dart team is looking into this bug.
761 xit('should write to input only if value is different', 574 xit('should write to input only if value is different', inject((Injector i , AstParser parser) {
762 (Injector i, Animate animate) {
763
764 var scope = _.rootScope; 575 var scope = _.rootScope;
765 var element = new dom.TextAreaElement(); 576 var element = new dom.TextAreaElement();
766 var ngElement = new NgElement(element, scope, animate);
767
768 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); 577 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement());
769 nodeAttrs['ng-model'] = 'model'; 578 nodeAttrs['ng-model'] = 'model';
770 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), 579 var model = new NgModel(scope, element, i.createChild([new Module()]), n ew NgNullForm(), parser, nodeAttrs);
771 nodeAttrs, new Animate());
772 dom.querySelector('body').append(element); 580 dom.querySelector('body').append(element);
773 var input = new InputTextLike(element, model, scope); 581 var input = new InputTextLikeDirective(element, model, scope);
774 582
775 element 583 element
776 ..value = 'abc' 584 ..value = 'abc'
777 ..selectionStart = 1 585 ..selectionStart = 1
778 ..selectionEnd = 2; 586 ..selectionEnd = 2;
779 587
780 model.render('abc'); 588 model.render('abc');
781 589
782 expect(element.value).toEqual('abc'); 590 expect(element.value).toEqual('abc');
783 expect(element.selectionStart).toEqual(1); 591 expect(element.selectionStart).toEqual(1);
784 expect(element.selectionEnd).toEqual(2); 592 expect(element.selectionEnd).toEqual(2);
785 593
786 model.render('xyz'); 594 model.render('xyz');
787 595
788 // Setting the value on a textarea doesn't update the selection the way it 596 // Setting the value on a textarea doesn't update the selection the way it
789 // does on input elements. This stays unchanged. 597 // does on input elements. This stays unchanged.
790 expect(element.value).toEqual('xyz'); 598 expect(element.value).toEqual('xyz');
791 expect(element.selectionStart).toEqual(0); 599 expect(element.selectionStart).toEqual(0);
792 expect(element.selectionEnd).toEqual(0); 600 expect(element.selectionEnd).toEqual(0);
793 }); 601 }));
794
795 it('should only render the input value upon the next digest', (Scope scope ) {
796 _.compile('<textarea ng-model="model" probe="p"></textarea>');
797 Probe probe = _.rootScope.context['p'];
798 var ngModel = probe.directive(NgModel);
799 TextAreaElement inputElement = probe.element;
800
801 ngModel.render('xyz');
802 scope.context['model'] = 'xyz';
803
804 expect(inputElement.value).not.toEqual('xyz');
805
806 scope.apply();
807
808 expect(inputElement.value).toEqual('xyz');
809 });
810 }); 602 });
811 603
812 describe('type="radio"', () { 604 describe('type="radio"', () {
813 it('should update input value from model', () { 605 it('should update input value from model', inject(() {
814 _.compile('<input type="radio" name="color" value="red" ng-model="color" probe="r">' + 606 _.compile('<input type="radio" name="color" value="red" ng-model="color" probe="r">' +
815 '<input type="radio" name="color" value="green" ng-model="colo r" probe="g">' + 607 '<input type="radio" name="color" value="green" ng-model="colo r" probe="g">' +
816 '<input type="radio" name="color" value="blue" ng-model="color " probe="b">'); 608 '<input type="radio" name="color" value="blue" ng-model="color " probe="b">');
817 _.rootScope.apply(); 609 _.rootScope.apply();
818 610
819 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; 611 RadioButtonInputElement redBtn = _.rootScope.context['r'].element;
820 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; 612 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element;
821 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; 613 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element;
822 614
823 expect(redBtn.checked).toBe(false); 615 expect(redBtn.checked).toBe(false);
(...skipping 20 matching lines...) Expand all
844 expect(_.rootScope.context['color']).toEqual('red'); 636 expect(_.rootScope.context['color']).toEqual('red');
845 expect(redBtn.checked).toBe(true); 637 expect(redBtn.checked).toBe(true);
846 expect(greenBtn.checked).toBe(false); 638 expect(greenBtn.checked).toBe(false);
847 expect(blueBtn.checked).toBe(false); 639 expect(blueBtn.checked).toBe(false);
848 640
849 _.triggerEvent(greenBtn, 'click'); 641 _.triggerEvent(greenBtn, 'click');
850 expect(_.rootScope.context['color']).toEqual('green'); 642 expect(_.rootScope.context['color']).toEqual('green');
851 expect(redBtn.checked).toBe(false); 643 expect(redBtn.checked).toBe(false);
852 expect(greenBtn.checked).toBe(true); 644 expect(greenBtn.checked).toBe(true);
853 expect(blueBtn.checked).toBe(false); 645 expect(blueBtn.checked).toBe(false);
854 }); 646 }));
855 647
856 it('should support ng-value', () { 648 it('should support ng-value', () {
857 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col or" probe="r">' + 649 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col or" probe="r">' +
858 '<input type="radio" name="color" ng-value="green" ng-model="c olor" probe="g">' + 650 '<input type="radio" name="color" ng-value="green" ng-model="c olor" probe="g">' +
859 '<input type="radio" name="color" ng-value="blue" ng-model="co lor" probe="b">'); 651 '<input type="radio" name="color" ng-value="blue" ng-model="co lor" probe="b">');
860 652
861 var red = {'name': 'RED'}; 653 var red = {'name': 'RED'};
862 var green = {'name': 'GREEN'}; 654 var green = {'name': 'GREEN'};
863 var blue = {'name': 'BLUE'}; 655 var blue = {'name': 'BLUE'};
864 _.rootScope.context 656 _.rootScope.context
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 expect(greenBtn.checked).toBe(false); 692 expect(greenBtn.checked).toBe(false);
901 expect(blueBtn.checked).toBe(false); 693 expect(blueBtn.checked).toBe(false);
902 694
903 _.triggerEvent(greenBtn, 'click'); 695 _.triggerEvent(greenBtn, 'click');
904 expect(_.rootScope.context['color']).toEqual(green); 696 expect(_.rootScope.context['color']).toEqual(green);
905 expect(redBtn.checked).toBe(false); 697 expect(redBtn.checked).toBe(false);
906 expect(greenBtn.checked).toBe(true); 698 expect(greenBtn.checked).toBe(true);
907 expect(blueBtn.checked).toBe(false); 699 expect(blueBtn.checked).toBe(false);
908 }); 700 });
909 701
910 it('should render as dirty when checked', (Scope scope) { 702 it('should render as dirty when checked', inject((Scope scope) {
911 var element = _.compile( 703 var element = _.compile(
912 '<div>' + 704 '<div>' +
913 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on " />' + 705 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on " />' +
914 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o ff" />' + 706 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o ff" />' +
915 '</div>' 707 '</div>'
916 ); 708 );
917 Probe probe = _.rootScope.context['i']; 709 Probe probe = _.rootScope.context['i'];
918 710
919 var model = probe.directive(NgModel); 711 var model = probe.directive(NgModel);
920 712
921 var input1 = element.querySelector("#on"); 713 var input1 = element.querySelector("#on");
922 var input2 = element.querySelector("#off"); 714 var input2 = element.querySelector("#off");
923 715
924 scope.apply();
925
926 expect(model.pristine).toEqual(true); 716 expect(model.pristine).toEqual(true);
927 expect(model.dirty).toEqual(false); 717 expect(model.dirty).toEqual(false);
928 718
929 expect(input1.classes.contains("ng-dirty")).toBe(false); 719 expect(input1.classes.contains("ng-dirty")).toBe(false);
930 expect(input2.classes.contains("ng-dirty")).toBe(false); 720 expect(input2.classes.contains("ng-dirty")).toBe(false);
931 expect(input1.classes.contains("ng-pristine")).toBe(true); 721 expect(input1.classes.contains("ng-pristine")).toBe(true);
932 expect(input1.classes.contains("ng-pristine")).toBe(true); 722 expect(input1.classes.contains("ng-pristine")).toBe(true);
933 723
934 input1.checked = true; 724 input1.checked = true;
935 _.triggerEvent(input1, 'click'); 725 _.triggerEvent(input1, 'click');
936 scope.apply();
937 726
938 expect(model.pristine).toEqual(false); 727 expect(model.pristine).toEqual(false);
939 expect(model.dirty).toEqual(true); 728 expect(model.dirty).toEqual(true);
940 729
941 input1.checked = false; 730 input1.checked = false;
942 input2.checked = true; 731 input2.checked = true;
943 _.triggerEvent(input2, 'click'); 732 _.triggerEvent(input2, 'click');
944 scope.apply();
945 733
946 expect(input1.classes.contains("ng-dirty")).toBe(true); 734 expect(input1.classes.contains("ng-dirty")).toBe(true);
947 expect(input2.classes.contains("ng-dirty")).toBe(true); 735 expect(input2.classes.contains("ng-dirty")).toBe(true);
948 expect(input1.classes.contains("ng-pristine")).toBe(false); 736 expect(input1.classes.contains("ng-pristine")).toBe(false);
949 expect(input1.classes.contains("ng-pristine")).toBe(false); 737 expect(input1.classes.contains("ng-pristine")).toBe(false);
950 }); 738 }));
951
952 it('should only render the input value upon the next digest', (Scope scope ) {
953 var element = _.compile(
954 '<div>' +
955 ' <input type="radio" id="on" ng-model="model" probe="i" value="on" / >' +
956 ' <input type="radio" id="off" ng-model="model" probe="j" value="off" />' +
957 '</div>'
958 );
959
960 Probe probe1 = _.rootScope.context['i'];
961 var ngModel1 = probe1.directive(NgModel);
962 InputElement inputElement1 = probe1.element;
963
964 Probe probe2 = _.rootScope.context['j'];
965 var ngModel2 = probe2.directive(NgModel);
966 InputElement inputElement2 = probe2.element;
967
968 ngModel1.render('on');
969 scope.context['model'] = 'on';
970
971 expect(inputElement1.checked).toBe(false);
972 expect(inputElement2.checked).toBe(false);
973
974 scope.apply();
975
976 expect(inputElement1.checked).toBe(true);
977 expect(inputElement2.checked).toBe(false);
978 });
979 }); 739 });
980 740
981 describe('type="search"', () { 741 describe('type="search"', () {
982 it('should update input value from model', () { 742 it('should update input value from model', inject(() {
983 _.compile('<input type="search" ng-model="model">'); 743 _.compile('<input type="search" ng-model="model">');
984 _.rootScope.apply(); 744 _.rootScope.apply();
985 745
986 expect((_.rootElement as dom.InputElement).value).toEqual(''); 746 expect((_.rootElement as dom.InputElement).value).toEqual('');
987 747
988 _.rootScope.apply('model = "matias"'); 748 _.rootScope.apply('model = "matias"');
989 expect((_.rootElement as dom.InputElement).value).toEqual('matias'); 749 expect((_.rootElement as dom.InputElement).value).toEqual('matias');
990 }); 750 }));
991 751
992 it('should render null as the empty string', () { 752 it('should render null as the empty string', inject(() {
993 _.compile('<input type="search" ng-model="model">'); 753 _.compile('<input type="search" ng-model="model">');
994 _.rootScope.apply(); 754 _.rootScope.apply();
995 755
996 expect((_.rootElement as dom.InputElement).value).toEqual(''); 756 expect((_.rootElement as dom.InputElement).value).toEqual('');
997 757
998 _.rootScope.apply('model = null'); 758 _.rootScope.apply('model = null');
999 expect((_.rootElement as dom.InputElement).value).toEqual(''); 759 expect((_.rootElement as dom.InputElement).value).toEqual('');
1000 }); 760 }));
1001 761
1002 it('should update model from the input value', () { 762 it('should update model from the input value', inject(() {
1003 _.compile('<input type="search" ng-model="model" probe="p">'); 763 _.compile('<input type="search" ng-model="model" probe="p">');
1004 Probe probe = _.rootScope.context['p']; 764 Probe probe = _.rootScope.context['p'];
1005 var ngModel = probe.directive(NgModel); 765 var ngModel = probe.directive(NgModel);
1006 InputElement inputElement = probe.element; 766 InputElement inputElement = probe.element;
1007 767
1008 inputElement.value = 'xzy'; 768 inputElement.value = 'xzy';
1009 _.triggerEvent(inputElement, 'change'); 769 _.triggerEvent(inputElement, 'change');
1010 expect(_.rootScope.context['model']).toEqual('xzy'); 770 expect(_.rootScope.context['model']).toEqual('xzy');
1011 771
1012 inputElement.value = '123'; 772 inputElement.value = '123';
1013 var input = probe.directive(InputTextLike); 773 var input = probe.directive(InputTextLikeDirective);
1014 input.processValue(); 774 input.processValue();
1015 expect(_.rootScope.context['model']).toEqual('123'); 775 expect(_.rootScope.context['model']).toEqual('123');
1016 }); 776 }));
1017
1018 it('should only render the input value upon the next digest', (Scope scope ) {
1019 _.compile('<input type="search" ng-model="model" probe="p">');
1020 Probe probe = _.rootScope.context['p'];
1021 var ngModel = probe.directive(NgModel);
1022 InputElement inputElement = probe.element;
1023
1024 ngModel.render('xyz');
1025 scope.context['model'] = 'xyz';
1026
1027 expect(inputElement.value).not.toEqual('xyz');
1028
1029 scope.apply();
1030
1031 expect(inputElement.value).toEqual('xyz');
1032 });
1033 }); 777 });
1034 778
1035 describe('contenteditable', () { 779 describe('contenteditable', () {
1036 it('should update content from model', () { 780 it('should update content from model', inject(() {
1037 _.compile('<p contenteditable ng-model="model">'); 781 _.compile('<p contenteditable ng-model="model">');
1038 _.rootScope.apply(); 782 _.rootScope.apply();
1039 783
1040 expect(_.rootElement.text).toEqual(''); 784 expect(_.rootElement.text).toEqual('');
1041 785
1042 _.rootScope.apply('model = "misko"'); 786 _.rootScope.apply('model = "misko"');
1043 expect(_.rootElement.text).toEqual('misko'); 787 expect(_.rootElement.text).toEqual('misko');
1044 }); 788 }));
1045 789
1046 it('should update model from the input value', () { 790 it('should update model from the input value', inject(() {
1047 _.compile('<p contenteditable ng-model="model">'); 791 _.compile('<p contenteditable ng-model="model">');
1048 Element element = _.rootElement; 792 Element element = _.rootElement;
1049 793
1050 element.innerHtml = 'abc'; 794 element.innerHtml = 'abc';
1051 _.triggerEvent(element, 'change'); 795 _.triggerEvent(element, 'change');
1052 expect(_.rootScope.context['model']).toEqual('abc'); 796 expect(_.rootScope.context['model']).toEqual('abc');
1053 797
1054 element.innerHtml = 'def'; 798 element.innerHtml = 'def';
1055 var input = ngInjector(element).get(ContentEditable); 799 var input = ngInjector(element).get(ContentEditableDirective);
1056 input.processValue(); 800 input.processValue();
1057 expect(_.rootScope.context['model']).toEqual('def'); 801 expect(_.rootScope.context['model']).toEqual('def');
1058 }); 802 }));
1059
1060 it('should only render the input value upon the next digest', (Scope scope ) {
1061 _.compile('<div contenteditable ng-model="model" probe="p"></div>');
1062 Probe probe = _.rootScope.context['p'];
1063 var ngModel = probe.directive(NgModel);
1064 Element element = probe.element;
1065
1066 ngModel.render('xyz');
1067 scope.context['model'] = 'xyz';
1068
1069 expect(element.innerHtml).not.toEqual('xyz');
1070
1071 scope.apply();
1072
1073 expect(element.innerHtml).toEqual('xyz');
1074 });
1075 }); 803 });
1076 804
1077 describe('pristine / dirty', () { 805 describe('pristine / dirty', () {
1078 it('should be set to pristine by default', (Scope scope) { 806 it('should be set to pristine by default', inject((Scope scope) {
1079 _.compile('<input type="text" ng-model="my_model" probe="i" />'); 807 _.compile('<input type="text" ng-model="my_model" probe="i" />');
1080 Probe probe = _.rootScope.context['i']; 808 Probe probe = _.rootScope.context['i'];
1081 var model = probe.directive(NgModel); 809 var model = probe.directive(NgModel);
1082 810
1083 expect(model.pristine).toEqual(true); 811 expect(model.pristine).toEqual(true);
1084 expect(model.dirty).toEqual(false); 812 expect(model.dirty).toEqual(false);
1085 }); 813 }));
1086 814
1087 it('should add and remove the correct CSS classes when set to dirty and to pristine', (Scope scope) { 815 it('should add and remove the correct CSS classes when set to dirty and to pristine', inject((Scope scope) {
1088 _.compile('<input type="text" ng-model="my_model" probe="i" />'); 816 _.compile('<input type="text" ng-model="my_model" probe="i" />');
1089 Probe probe = _.rootScope.context['i']; 817 Probe probe = _.rootScope.context['i'];
1090 NgModel model = probe.directive(NgModel); 818 NgModel model = probe.directive(NgModel);
1091 InputElement element = probe.element; 819 InputElement element = probe.element;
1092 820
1093 model.addInfo('ng-dirty'); 821 model.dirty = true;
1094 scope.apply();
1095
1096 expect(model.pristine).toEqual(false); 822 expect(model.pristine).toEqual(false);
1097 expect(model.dirty).toEqual(true); 823 expect(model.dirty).toEqual(true);
1098 expect(element).not.toHaveClass('ng-pristine'); 824 expect(element.classes.contains('ng-pristine')).toBe(false);
1099 expect(element).toHaveClass('ng-dirty'); 825 expect(element.classes.contains('ng-dirty')).toBe(true);
1100 826
1101 model.removeInfo('ng-dirty'); 827 model.pristine = true;
1102 scope.apply();
1103
1104 expect(model.pristine).toEqual(true); 828 expect(model.pristine).toEqual(true);
1105 expect(model.dirty).toEqual(false); 829 expect(model.dirty).toEqual(false);
1106 expect(element).toHaveClass('ng-pristine'); 830 expect(element.classes.contains('ng-pristine')).toBe(true);
1107 expect(element).not.toHaveClass('ng-dirty'); 831 expect(element.classes.contains('ng-dirty')).toBe(false);
1108 }); 832 }));
1109 833
1110 // TODO(matias): figure out why the 2nd apply is optional 834 it('should render the parent form/fieldset as dirty but not the other mode ls', inject((Scope scope) {
1111 it('should render the parent form/fieldset as dirty but not the other mode ls',
1112 (Scope scope) {
1113
1114 _.compile('<form name="myForm">' + 835 _.compile('<form name="myForm">' +
1115 ' <fieldset name="myFieldset">' + 836 ' <fieldset name="myFieldset">' +
1116 ' <input type="text" ng-model="my_model1" probe="myModel1" />' + 837 ' <input type="text" ng-model="my_model1" probe="myModel1" />' +
1117 ' <input type="text" ng-model="my_model2" probe="myModel2" />' + 838 ' <input type="text" ng-model="my_model2" probe="myModel2" />' +
1118 ' </fieldset>' + 839 ' </fieldset>' +
1119 '</form>'); 840 '</form>');
1120 841
1121 var formElement = _.rootScope.context['myForm'].element.node;
1122 var fieldsetElement = _.rootScope.context['myFieldset'].element.node;
1123 var inputElement1 = _.rootScope.context['myModel1'].element; 842 var inputElement1 = _.rootScope.context['myModel1'].element;
1124 var inputElement2 = _.rootScope.context['myModel2'].element; 843 var inputElement2 = _.rootScope.context['myModel2'].element;
844 var formElement = _.rootScope.context['myForm'].element;
845 var fieldsetElement = _.rootScope.context['myFieldset'].element;
1125 846
1126 scope.apply(); 847 expect(formElement.classes.contains('ng-pristine')).toBe(true);
848 expect(formElement.classes.contains('ng-dirty')).toBe(false);
1127 849
1128 expect(formElement).toHaveClass('ng-pristine'); 850 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(true);
1129 expect(formElement).not.toHaveClass('ng-dirty'); 851 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(false);
1130 852
1131 expect(fieldsetElement).toHaveClass('ng-pristine'); 853 expect(inputElement1.classes.contains('ng-pristine')).toBe(true);
1132 expect(fieldsetElement).not.toHaveClass('ng-dirty'); 854 expect(inputElement1.classes.contains('ng-dirty')).toBe(false);
1133 855
1134 expect(inputElement1).toHaveClass('ng-pristine'); 856 expect(inputElement2.classes.contains('ng-pristine')).toBe(true);
1135 expect(inputElement1).not.toHaveClass('ng-dirty'); 857 expect(inputElement2.classes.contains('ng-dirty')).toBe(false);
1136
1137 expect(inputElement2).toHaveClass('ng-pristine');
1138 expect(inputElement2).not.toHaveClass('ng-dirty');
1139 858
1140 inputElement1.value = '...hi...'; 859 inputElement1.value = '...hi...';
1141 _.triggerEvent(inputElement1, 'change'); 860 _.triggerEvent(inputElement1, 'change');
1142 scope.apply();
1143 861
1144 expect(formElement).not.toHaveClass('ng-pristine'); 862 expect(formElement.classes.contains('ng-pristine')).toBe(false);
1145 expect(formElement).toHaveClass('ng-dirty'); 863 expect(formElement.classes.contains('ng-dirty')).toBe(true);
1146 864
1147 expect(fieldsetElement).not.toHaveClass('ng-pristine'); 865 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(false);
1148 expect(fieldsetElement).toHaveClass('ng-dirty'); 866 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(true);
1149 867
1150 expect(inputElement1).not.toHaveClass('ng-pristine'); 868 expect(inputElement1.classes.contains('ng-pristine')).toBe(false);
1151 expect(inputElement1).toHaveClass('ng-dirty'); 869 expect(inputElement1.classes.contains('ng-dirty')).toBe(true);
1152 870
1153 expect(inputElement2).toHaveClass('ng-pristine'); 871 expect(inputElement2.classes.contains('ng-pristine')).toBe(true);
1154 expect(inputElement2).not.toHaveClass('ng-dirty'); 872 expect(inputElement2.classes.contains('ng-dirty')).toBe(false);
1155 }); 873 }));
1156 }); 874 });
1157 875
1158 describe('validation', () { 876 describe('validation', () {
1159 it('should happen automatically when the scope changes', (Scope scope) { 877 it('should happen automatically when the scope changes', inject((Scope sco pe) {
1160 _.compile('<input type="text" ng-model="model" probe="i" required>'); 878 _.compile('<input type="text" ng-model="model" probe="i" required>');
1161 _.rootScope.apply(); 879 _.rootScope.apply();
1162 880
1163 Probe probe = _.rootScope.context['i']; 881 Probe probe = _.rootScope.context['i'];
1164 var model = probe.directive(NgModel); 882 var model = probe.directive(NgModel);
1165 883
1166 expect(model.invalid).toBe(true); 884 expect(model.invalid).toBe(true);
1167 expect(model.valid).toBe(false); 885 expect(model.valid).toBe(false);
1168 886
1169 _.rootScope.apply('model = "viljami"'); 887 _.rootScope.apply('model = "viljami"');
1170 888
1171 expect(model.invalid).toBe(false); 889 expect(model.invalid).toBe(false);
1172 expect(model.valid).toBe(true); 890 expect(model.valid).toBe(true);
1173 }); 891 }));
1174 892
1175 it('should happen automatically upon user input via the onInput event', () { 893 it('should happen automatically upon user input via the onInput event', in ject(() {
1176 _.compile('<input type="text" ng-model="model" probe="i" required>'); 894 _.compile('<input type="text" ng-model="model" probe="i" required>');
1177 _.rootScope.apply();
1178 895
1179 Probe probe = _.rootScope.context['i']; 896 Probe probe = _.rootScope.context['i'];
1180 var model = probe.directive(NgModel); 897 var model = probe.directive(NgModel);
1181 InputElement inputElement = model.element.node; 898 InputElement inputElement = model.element;
1182 899
1183 expect(model.invalid).toBe(true); 900 expect(model.invalid).toBe(true);
1184 expect(model.valid).toBe(false); 901 expect(model.valid).toBe(false);
1185 902
1186 inputElement.value = 'some value'; 903 inputElement.value = 'some value';
1187 _.triggerEvent(inputElement, 'input'); 904 _.triggerEvent(inputElement, 'input');
1188 905
1189 expect(model.invalid).toBe(false); 906 expect(model.invalid).toBe(false);
1190 expect(model.valid).toBe(true); 907 expect(model.valid).toBe(true);
1191 }); 908 }));
1192 }); 909 });
1193 910
1194 describe('valid / invalid', () { 911 describe('valid / invalid', () {
1195 it('should add and remove the correct flags when set to valid and to inval id', (Scope scope) { 912 it('should add and remove the correct flags when set to valid and to inval id', inject((Scope scope) {
1196 _.compile('<input type="text" ng-model="my_model" probe="i" />'); 913 _.compile('<input type="text" ng-model="my_model" probe="i" />');
1197 Probe probe = _.rootScope.context['i']; 914 Probe probe = _.rootScope.context['i'];
1198 var model = probe.directive(NgModel); 915 var model = probe.directive(NgModel);
1199 InputElement element = probe.element; 916 InputElement element = probe.element;
1200 917
1201 model.addError('ng-required'); 918 model.invalid = true;
1202 model.validate();
1203 scope.apply();
1204
1205 expect(model.valid).toEqual(false); 919 expect(model.valid).toEqual(false);
1206 expect(model.invalid).toEqual(true); 920 expect(model.invalid).toEqual(true);
1207 //expect(element).not.toHaveClass('ng-valid'); 921 expect(element.classes.contains('ng-valid')).toBe(false);
1208 expect(element).toHaveClass('ng-invalid'); 922 expect(element.classes.contains('ng-invalid')).toBe(true);
1209 923
1210 model.removeError('ng-required'); 924 model.valid = true;
1211 model.validate();
1212 scope.apply();
1213
1214 expect(model.valid).toEqual(true); 925 expect(model.valid).toEqual(true);
1215 expect(model.invalid).toEqual(false); 926 expect(model.invalid).toEqual(false);
1216 expect(element).not.toHaveClass('ng-invalid'); 927 expect(element.classes.contains('ng-invalid')).toBe(false);
1217 // expect(element).toHaveClass('ng-valid'); 928 expect(element.classes.contains('ng-valid')).toBe(true);
1218 }); 929 }));
1219 930
1220 it('should set the validity with respect to all existing validations when setValidity() is used', (Scope scope) { 931 it('should set the validity with respect to all existing validations when setValidity() is used', inject((Scope scope) {
1221 _.compile('<input type="text" ng-model="my_model" probe="i" />'); 932 _.compile('<input type="text" ng-model="my_model" probe="i" />');
1222 Probe probe = _.rootScope.context['i']; 933 Probe probe = _.rootScope.context['i'];
1223 var model = probe.directive(NgModel); 934 var model = probe.directive(NgModel);
1224 935
1225 model.addError("required"); 936 model.setValidity("required", false);
1226 expect(model.valid).toEqual(false); 937 expect(model.valid).toEqual(false);
1227 expect(model.invalid).toEqual(true); 938 expect(model.invalid).toEqual(true);
1228 939
1229 model.addError("format"); 940 model.setValidity("format", false);
1230 expect(model.valid).toEqual(false); 941 expect(model.valid).toEqual(false);
1231 expect(model.invalid).toEqual(true); 942 expect(model.invalid).toEqual(true);
1232 943
1233 model.removeError("format"); 944 model.setValidity("format", true);
1234 expect(model.valid).toEqual(false); 945 expect(model.valid).toEqual(false);
1235 expect(model.invalid).toEqual(true); 946 expect(model.invalid).toEqual(true);
1236 947
1237 model.removeError("required"); 948 model.setValidity("required", true);
1238 expect(model.valid).toEqual(true); 949 expect(model.valid).toEqual(true);
1239 expect(model.invalid).toEqual(false); 950 expect(model.invalid).toEqual(false);
1240 }); 951 }));
1241 952
1242 it('should register each error only once when invalid', (Scope scope) { 953 it('should register each error only once when invalid', inject((Scope scop e) {
1243 _.compile('<input type="text" ng-model="my_model" probe="i" />'); 954 _.compile('<input type="text" ng-model="my_model" probe="i" />');
1244 Probe probe = _.rootScope.context['i']; 955 Probe probe = _.rootScope.context['i'];
1245 var model = probe.directive(NgModel); 956 var model = probe.directive(NgModel);
1246 957
1247 model.addError("distinct-error"); 958 model.setValidity("distinct-error", false);
1248 expect(model.valid).toEqual(false); 959 expect(model.valid).toEqual(false);
1249 expect(model.invalid).toEqual(true); 960 expect(model.invalid).toEqual(true);
1250 961
1251 model.addError("distinct-error"); 962 model.setValidity("distinct-error", false);
1252 expect(model.valid).toEqual(false); 963 expect(model.valid).toEqual(false);
1253 expect(model.invalid).toEqual(true); 964 expect(model.invalid).toEqual(true);
1254 965
1255 model.removeError("distinct-error"); 966 model.setValidity("distinct-error", true);
1256 expect(model.valid).toEqual(true); 967 expect(model.valid).toEqual(true);
1257 expect(model.invalid).toEqual(false); 968 expect(model.invalid).toEqual(false);
1258 }); 969 }));
1259 });
1260
1261 describe('error handling', () {
1262 it('should return true or false depending on if an error exists on a form' ,
1263 (Scope scope, TestBed _) {
1264
1265 _.compile('<input type="text" ng-model="input" name="input" probe="i" /> ');
1266 scope.apply();
1267
1268 Probe p = scope.context['i'];
1269 NgModel model = p.directive(NgModel);
1270
1271 expect(model.hasErrorState('big-failure')).toBe(false);
1272
1273 model.addError("big-failure");
1274
1275 expect(model.hasErrorState('big-failure')).toBe(true);
1276
1277 model.removeError("big-failure");
1278
1279 expect(model.hasErrorState('big-failure')).toBe(false);
1280 });
1281 }); 970 });
1282 971
1283 describe('text-like events', () { 972 describe('text-like events', () {
1284 it('should update the binding on the "input" event', () { 973 it('should update the binding on the "input" event', inject(() {
1285 _.compile('<input type="text" ng-model="model" probe="p">'); 974 _.compile('<input type="text" ng-model="model" probe="p">');
1286 Probe probe = _.rootScope.context['p']; 975 Probe probe = _.rootScope.context['p'];
1287 InputElement inputElement = probe.element; 976 InputElement inputElement = probe.element;
1288 977
1289 inputElement.value = 'waaaah'; 978 inputElement.value = 'waaaah';
1290 979
1291 expect(_.rootScope.context['model']).not.toEqual('waaaah'); 980 expect(_.rootScope.context['model']).not.toEqual('waaaah');
1292 981
1293 _.triggerEvent(inputElement, 'input'); 982 _.triggerEvent(inputElement, 'input');
1294 983
1295 expect(_.rootScope.context['model']).toEqual('waaaah'); 984 expect(_.rootScope.context['model']).toEqual('waaaah');
1296 }); 985 }));
1297 }); 986 });
1298 987
1299 describe('error messages', () { 988 describe('error messages', () {
1300 it('should produce a useful error for bad ng-model expressions', () { 989 it('should produce a useful error for bad ng-model expressions', () {
1301 expect(async(() { 990 expect(async(() {
1302 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe" ></textarea></div'); 991 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe" ></textarea></div');
1303 Probe probe = _.rootScope.context['loveProbe']; 992 Probe probe = _.rootScope.context['loveProbe'];
1304 TextAreaElement inputElement = probe.element; 993 TextAreaElement inputElement = probe.element;
1305 994
1306 inputElement.value = 'xzy'; 995 inputElement.value = 'xzy';
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1347 _.triggerEvent(input, 'blur'); 1036 _.triggerEvent(input, 'blur');
1348 1037
1349 expect(model.touched).toBe(true); 1038 expect(model.touched).toBe(true);
1350 expect(model.untouched).toBe(false); 1039 expect(model.untouched).toBe(false);
1351 1040
1352 model.reset(); 1041 model.reset();
1353 1042
1354 expect(model.touched).toBe(false); 1043 expect(model.touched).toBe(false);
1355 expect(model.untouched).toBe(true); 1044 expect(model.untouched).toBe(true);
1356 }); 1045 });
1357
1358 describe('validators', () {
1359 it('should display the valid and invalid CSS classes on the element for ea ch validation',
1360 (TestBed _, Scope scope) {
1361
1362 var input = _.compile('<input type="email" ng-model="myModel" />');
1363
1364 scope.apply(() {
1365 scope.context['myModel'] = 'value';
1366 });
1367
1368 expect(input).toHaveClass('ng-email-invalid');
1369 expect(input).not.toHaveClass('ng-email-valid');
1370
1371 scope.apply(() {
1372 scope.context['myModel'] = 'value@email.com';
1373 });
1374
1375 expect(input).toHaveClass('ng-email-valid');
1376 expect(input).not.toHaveClass('ng-email-invalid');
1377 });
1378
1379 it('should display the valid and invalid CSS classes on the element for cu stom validations',
1380 (TestBed _, Scope scope) {
1381
1382 var input = _.compile('<input type="text" ng-model="myModel" custom-inpu t-validation />');
1383
1384 scope.apply();
1385
1386 expect(input).toHaveClass('custom-invalid');
1387 expect(input).not.toHaveClass('custom-valid');
1388
1389 scope.apply(() {
1390 scope.context['myModel'] = 'yes';
1391 });
1392
1393 expect(input).toHaveClass('custom-valid');
1394 expect(input).not.toHaveClass('custom-invalid');
1395 });
1396
1397 it('should only validate twice during compilation and once upon scope dige st',
1398 (TestBed _, Scope scope) {
1399
1400 scope.context['required'] = true;
1401 _.compile('<input type="text" '
1402 'ng-model="model" '
1403 'ng-required="required" '
1404 'ng-pattern="pattern" '
1405 'counting-validator '
1406 'probe="i">');
1407
1408 scope.context['pattern'] = '^[aeiou]+\$';
1409 scope.context['required'] = true;
1410
1411 scope.apply();
1412
1413 var model = scope.context['i'].directive(NgModel);
1414 var counter = model.validators.firstWhere((validator) => validator.name == 'counting');
1415
1416 // TODO(#881): There is a bug in ngModel where the validators are valida ted too often.
1417 // Should be 2. One for ngModel and one for all the other ones
1418 // Currently, this count is 2 on Chrome and 3 on Firefox.
1419 expect(counter.count == 2 || counter.count == 3).toBe(true);
1420 expect(model.invalid).toBe(true);
1421
1422 counter.count = 0;
1423 scope.context['pattern'] = '';
1424 scope.context['required'] = false;
1425 scope.apply();
1426
1427 expect(counter.count).toBe(1);
1428 });
1429
1430 it('should only validate twice regardless of attribute order', (TestBed _, Scope scope) {
1431 scope.context['required'] = true;
1432 _.compile('<input type="text" '
1433 'ng-required="required" '
1434 'ng-pattern="pattern" '
1435 'counting-validator '
1436 'ng-model="model" '
1437 'probe="i">');
1438
1439 scope.context['pattern'] = '^[aeiou]+\$';
1440 scope.context['required'] = true;
1441
1442 scope.apply();
1443
1444 var model = scope.context['i'].directive(NgModel);
1445
1446 var counter = model.validators.firstWhere((validator) => validator.name == 'counting');
1447
1448 // TODO(#881): There is a bug in ngModel where the validators are valida ted too often.
1449 // Should be 2. One for ngModel and one for all the other ones
1450 // Currently, this count is 3 on Chrome and 1 on Firefox.
1451 expect(counter.count == 2 || counter.count == 3).toBe(true);
1452 });
1453 });
1454
1455 describe('converters', () {
1456 it('should parse the model value according to the given parser', (Scope sc ope) {
1457 _.compile('<input type="text" ng-model="model" probe="i">');
1458 scope.apply();
1459
1460 var probe = scope.context['i'];
1461 var input = probe.element;
1462 var model = probe.directive(NgModel);
1463 model.converter = new LowercaseValueParser();
1464
1465 input.value = 'HELLO';
1466 _.triggerEvent(input, 'change');
1467 _.rootScope.apply();
1468
1469 expect(model.viewValue).toEqual('HELLO');
1470 expect(model.modelValue).toEqual('hello');
1471 });
1472
1473 it('should format the model value according to the given formatter', (Scop e scope) {
1474 _.compile('<input type="text" ng-model="model" probe="i">');
1475 scope.apply();
1476
1477 var probe = scope.context['i'];
1478 var input = probe.element;
1479 var model = probe.directive(NgModel);
1480 model.converter = new UppercaseValueFormatter();
1481
1482 scope.apply(() {
1483 scope.context['model'] = 'greetings';
1484 });
1485
1486 expect(model.viewValue).toEqual('GREETINGS');
1487 expect(model.modelValue).toEqual('greetings');
1488 });
1489
1490 it('should retain the current input value if the parser fails', (Scope sco pe) {
1491 _.compile('<form name="myForm">' +
1492 ' <input type="text" ng-model="model1" name="myModel1" probe=" i">' +
1493 ' <input type="text" ng-model="model2" name="myModel2" probe=" j">' +
1494 '</form>');
1495 scope.apply();
1496
1497 var probe1 = scope.context['i'];
1498 var input1 = probe1.element;
1499 var model1 = probe1.directive(NgModel);
1500
1501 var probe2 = scope.context['j'];
1502 var input2 = probe2.element;
1503 var model2 = probe2.directive(NgModel);
1504
1505 model1.converter = new FailedValueParser();
1506
1507 input1.value = '123';
1508 _.triggerEvent(input1, 'change');
1509 _.rootScope.apply();
1510
1511 expect(model1.viewValue).toEqual('123');
1512 expect(input1.value).toEqual('123');
1513 expect(model1.modelValue).toEqual(null);
1514
1515 expect(model2.viewValue).toEqual(null);
1516 expect(input2.value).toEqual('');
1517 expect(model2.modelValue).toEqual(null);
1518 });
1519
1520 it('should reformat the viewValue when the formatter is changed', (Scope s cope) {
1521 _.compile('<input type="text" ng-model="model" probe="i">');
1522 scope.apply();
1523
1524 var probe = scope.context['i'];
1525 var input = probe.element;
1526 var model = probe.directive(NgModel);
1527 model.converter = new LowercaseValueParser();
1528
1529 input.value = 'HI THERE';
1530 _.triggerEvent(input, 'change');
1531 _.rootScope.apply();
1532
1533 expect(model.viewValue).toEqual('HI THERE');
1534 expect(model.modelValue).toEqual('hi there');
1535
1536 model.converter = new VowelValueParser();
1537
1538 expect(model.viewValue).toEqual('iee');
1539 expect(model.modelValue).toEqual('hi there');
1540 });
1541 });
1542 }); 1046 });
1543 } 1047 }
1544 1048
1545 @Controller( 1049 @NgController(
1546 selector: '[no-love]', 1050 selector: '[no-love]',
1547 publishAs: 'ctrl') 1051 publishAs: 'ctrl')
1548 class ControllerWithNoLove { 1052 class ControllerWithNoLove {
1549 var apathy = null; 1053 var apathy = null;
1550 } 1054 }
1551
1552 class LowercaseValueParser implements NgModelConverter {
1553 final name = 'lowercase';
1554 format(value) => value;
1555 parse(value) {
1556 return value != null ? value.toLowerCase() : null;
1557 }
1558 }
1559
1560 class UppercaseValueFormatter implements NgModelConverter {
1561 final name = 'uppercase';
1562 parse(value) => value;
1563 format(value) {
1564 return value != null ? value.toUpperCase() : null;
1565 }
1566 }
1567
1568 class FailedValueParser implements NgModelConverter {
1569 final name = 'failed';
1570 format(value) => value;
1571 parse(value) {
1572 throw new Exception();
1573 }
1574 }
1575
1576 class VowelValueParser implements NgModelConverter {
1577 final name = 'vowel';
1578 parse(value) => value;
1579 format(value) {
1580 if(value != null) {
1581 var exp = new RegExp("[^aeiouAEIOU]");
1582 value = value.replaceAll(exp, "");
1583 }
1584 return value;
1585 }
1586 }
1587
1588 @Decorator(
1589 selector: '[custom-input-validation]')
1590 class MyCustomInputValidator extends NgValidator {
1591 MyCustomInputValidator(NgModel ngModel) {
1592 ngModel.addValidator(this);
1593 }
1594
1595 final String name = 'custom';
1596
1597 bool isValid(name) {
1598 return name != null && name == 'yes';
1599 }
1600 }
1601
1602 @Decorator(
1603 selector: '[counting-validator]')
1604 class CountingValidator extends NgValidator {
1605
1606 final String name = 'counting';
1607 int count = 0;
1608
1609 CountingValidator(NgModel ngModel) {
1610 ngModel.addValidator(this);
1611 }
1612
1613 bool isValid(String modelValue) {
1614 count++;
1615 return true;
1616 }
1617 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698