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

Side by Side Diff: dart/pkg/template_binding/test/node_bind_test.dart

Issue 336013003: Version 1.5.0-dev.4.14 (Closed) Base URL: http://dart.googlecode.com/svn/trunk/
Patch Set: Created 6 years, 6 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 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library template_binding.test.node_bind_test; 5 library template_binding.test.node_bind_test;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:html'; 8 import 'dart:html';
9 9
10 import 'package:observe/observe.dart' 10 import 'package:observe/observe.dart'
11 show toObservable, PathObserver, PropertyPath; 11 show toObservable, PathObserver, PropertyPath;
12 import 'package:template_binding/template_binding.dart' show nodeBind; 12 import 'package:template_binding/template_binding.dart'
13 show nodeBind, enableBindingsReflection;
13 14
14 import 'package:unittest/html_config.dart'; 15 import 'package:unittest/html_config.dart';
15 import 'package:unittest/unittest.dart'; 16 import 'package:unittest/unittest.dart';
16 import 'utils.dart'; 17 import 'utils.dart';
17 18
18 // Note: this file ported from 19 // Ported from: https://github.com/Polymer/NodeBind/blob/master/tests/tests.js
19 // https://github.com/toolkitchen/mdv/blob/master/tests/node_bindings.js 20
21 var bindings;
20 22
21 main() => dirtyCheckZone().run(() { 23 main() => dirtyCheckZone().run(() {
22 useHtmlConfiguration(); 24 useHtmlConfiguration();
23 25
24 setUp(() { 26 setUp(() {
25 document.body.append(testDiv = new DivElement()); 27 document.body.append(testDiv = new DivElement());
28 bindings = [];
26 }); 29 });
27 30
28 tearDown(() { 31 tearDown(() {
29 testDiv.remove(); 32 testDiv.remove();
30 testDiv = null; 33 testDiv = null;
34 for (var b in bindings) if (b != null) b.close();
35 bindings = null;
31 }); 36 });
32 37
33 group('Text bindings', testBindings); 38 group('Text bindings', testBindings);
34 group('Element attribute bindings', elementBindings); 39 group('Element attribute bindings', elementBindings);
35 group('Form Element bindings', formBindings); 40 group('Form Element bindings', formBindings);
36 }); 41 });
37 42
38 testBindings() { 43 testBindings() {
39 test('Basic', () { 44 test('Basic', () {
40 var text = new Text('hi'); 45 var text = new Text('hi');
41 var model = toObservable({'a': 1}); 46 var model = toObservable({'a': 1});
42 nodeBind(text).bind('text', new PathObserver(model, 'a')); 47 bindings.add(nodeBind(text).bind('text', new PathObserver(model, 'a')));
43 expect(text.text, '1'); 48 expect(text.text, '1');
44 49
45 model['a'] = 2; 50 model['a'] = 2;
46 return new Future(() { 51 return new Future(() {
47 expect(text.text, '2'); 52 expect(text.text, '2');
48
49 nodeBind(text).unbind('text');
50 model['a'] = 3;
51 }).then(endOfMicrotask).then((_) {
52 // TODO(rafaelw): Throw on binding to unavailable property?
53 expect(text.text, '2');
54 }); 53 });
55 }); 54 });
56 55
57 test('oneTime', () { 56 test('oneTime', () {
58 var text = new Text('hi'); 57 var text = new Text('hi');
59 nodeBind(text).bind('text', 1, oneTime: true); 58 bindings.add(nodeBind(text).bind('text', 1, oneTime: true));
60 expect(text.text, '1'); 59 expect(text.text, '1');
61 }); 60 });
62 61
63 test('No Path', () { 62 test('No Path', () {
64 var text = new Text('hi'); 63 var text = new Text('hi');
65 var model = 1; 64 var model = 1;
66 nodeBind(text).bind('text', new PathObserver(model)); 65 bindings.add(nodeBind(text).bind('text', new PathObserver(model)));
67 expect(text.text, '1'); 66 expect(text.text, '1');
68 }); 67 });
69 68
70 test('Path unreachable', () { 69 test('Path unreachable', () {
71 var text = testDiv.append(new Text('hi')); 70 var text = testDiv.append(new Text('hi'));
72 var model = 1; 71 var model = 1;
73 var pathObserver = new PathObserver(model, 'a'); 72 var pathObserver = new PathObserver(model, 'a');
74 expect(() => nodeBind(text).bind('text', pathObserver), throws); 73 expect(() => nodeBind(text).bind('text', pathObserver), throws);
75 expect(text.text, 'hi'); 74 expect(text.text, 'hi');
76 }); 75 });
77 76
78 test('Observer is Model', () { 77 test('Observer is Model', () {
79 var text = new Text(''); 78 // Dart note: we don't have _allObserversCount so we use binding reflection
80 var model = toObservable({'a': {'b': {'c': 1}}}); 79 // instead.
81 var observer = new PathObserver(model, 'a.b.c'); 80 enableBindingsReflection = true;
82 nodeBind(text).bind('text', observer);
83 expect(text.text, '1');
84 81
85 var binding = nodeBind(text).bindings['text']; 82 // This future is here so we can turn off bindings reflection reliably.
86 expect(binding, observer, reason: 'should reuse observer'); 83 Text text;
84 return new Future(() {
85 text = new Text('');
86 var model = toObservable({'a': {'b': {'c': 1}}});
87 var observer = new PathObserver(model, 'a.b.c');
88 bindings.add(nodeBind(text).bind('text', observer));
89 expect(text.text, '1');
87 90
88 model['a']['b']['c'] = 2; 91 var binding = nodeBind(text).bindings['text'];
89 return new Future(() { 92 expect(binding, observer, reason: 'should reuse observer');
93
94 model['a']['b']['c'] = 2;
95 }).then(endOfMicrotask).then((_) {
90 expect(text.text, '2'); 96 expect(text.text, '2');
91 nodeBind(text).unbind('text'); 97 }).whenComplete(() {
98 enableBindingsReflection = false;
92 }); 99 });
93 }); 100 });
94 } 101 }
95 102
96 elementBindings() { 103 elementBindings() {
104
97 test('Basic', () { 105 test('Basic', () {
98 var el = new DivElement(); 106 var el = new DivElement();
99 var model = toObservable({'a': '1'}); 107 var model = toObservable({'a': '1'});
100 nodeBind(el).bind('foo', new PathObserver(model, 'a')); 108 bindings.add(nodeBind(el).bind('foo', new PathObserver(model, 'a')));
101 109
102 return new Future(() { 110 return new Future(() {
103 expect(el.attributes['foo'], '1'); 111 expect(el.attributes['foo'], '1');
104 model['a'] = '2'; 112 model['a'] = '2';
105 }).then(endOfMicrotask).then((_) { 113 }).then(endOfMicrotask).then((_) {
106 expect(el.attributes['foo'], '2'); 114 expect(el.attributes['foo'], '2');
107 model['a'] = 232.2; 115 model['a'] = 232.2;
108 }).then(endOfMicrotask).then((_) { 116 }).then(endOfMicrotask).then((_) {
109 expect(el.attributes['foo'], '232.2'); 117 expect(el.attributes['foo'], '232.2');
110 model['a'] = 232; 118 model['a'] = 232;
111 }).then(endOfMicrotask).then((_) { 119 }).then(endOfMicrotask).then((_) {
112 expect(el.attributes['foo'], '232'); 120 expect(el.attributes['foo'], '232');
113 model['a'] = null; 121 model['a'] = null;
114 }).then(endOfMicrotask).then((_) { 122 }).then(endOfMicrotask).then((_) {
115 expect(el.attributes['foo'], ''); 123 expect(el.attributes['foo'], '');
116 }); 124 });
117 }); 125 });
118 126
127 // Dart specific test
128 test('enableBindingsReflection defaults to off', () {
129 expect(enableBindingsReflection, false);
130
131 var el = new DivElement();
132 var model = toObservable({'a': '1'});
133 bindings.add(nodeBind(el).bind('foo', new PathObserver(model, 'a')));
134
135 expect(nodeBind(el).bindings, null);
136 });
137
138 test('enableBindingsReflection', () {
139 enableBindingsReflection = true;
140 try {
141 var el = testDiv.append(new DivElement());
142 var model = toObservable({'a': '1'});
143 bindings.add(nodeBind(el).bind('foo', new PathObserver(model, 'a')));
144 bindings.add(nodeBind(el).bind('bar', new PathObserver(model, 'a')));
145 bindings.add(nodeBind(el).bind('baz', new PathObserver(model, 'a')));
146
147 expect(nodeBind(el).bindings.keys,
148 unorderedEquals(['foo', 'bar', 'baz']));
149
150 } finally {
151 enableBindingsReflection = false;
152 }
153 });
154
119 test('oneTime', () { 155 test('oneTime', () {
120 var el = testDiv.append(new DivElement()); 156 var el = testDiv.append(new DivElement());
121 var model = toObservable({'a': '1'}); 157 var model = toObservable({'a': '1'});
122 nodeBind(el).bind('foo', 1, oneTime: true); 158 bindings.add(nodeBind(el).bind('foo', 1, oneTime: true));
123 expect('1', el.attributes['foo']); 159 expect('1', el.attributes['foo']);
124 }); 160 });
125 161
126 test('No Path', () { 162 test('No Path', () {
127 var el = testDiv.append(new DivElement()); 163 var el = testDiv.append(new DivElement());
128 var model = 1; 164 var model = 1;
129 nodeBind(el).bind('foo', new PathObserver(model)); 165 bindings.add(nodeBind(el).bind('foo', new PathObserver(model)));
130 return new Future(() { 166 return new Future(() {
131 expect(el.attributes['foo'], '1'); 167 expect(el.attributes['foo'], '1');
132 }); 168 });
133 }); 169 });
134 170
135 test('Path unreachable', () { 171 test('Path unreachable', () {
136 var el = testDiv.append(new DivElement()); 172 var el = testDiv.append(new DivElement());
137 var model = toObservable({}); 173 var model = toObservable({});
138 nodeBind(el).bind('foo', new PathObserver(model, 'bar')); 174 bindings.add(nodeBind(el).bind('foo', new PathObserver(model, 'bar')));
139 return new Future(() { 175 return new Future(() {
140 expect(el.attributes['foo'], ''); 176 expect(el.attributes['foo'], '');
141 }); 177 });
142 }); 178 });
143 179
144 test('Dashes', () { 180 test('Dashes', () {
145 var el = testDiv.append(new DivElement()); 181 var el = testDiv.append(new DivElement());
146 var model = toObservable({'a': '1'}); 182 var model = toObservable({'a': '1'});
147 nodeBind(el).bind('foo-bar', new PathObserver(model, 'a')); 183 bindings.add(nodeBind(el).bind('foo-bar', new PathObserver(model, 'a')));
148 return new Future(() { 184 return new Future(() {
149 expect(el.attributes['foo-bar'], '1'); 185 expect(el.attributes['foo-bar'], '1');
150 model['a'] = '2'; 186 model['a'] = '2';
151 187
152 }).then(endOfMicrotask).then((_) { 188 }).then(endOfMicrotask).then((_) {
153 expect(el.attributes['foo-bar'], '2'); 189 expect(el.attributes['foo-bar'], '2');
154 }); 190 });
155 }); 191 });
156 192
157 test('Element.id, Element.hidden?', () { 193 test('Element.id, Element.hidden?', () {
158 var element = new DivElement(); 194 var element = new DivElement();
159 var model = toObservable({'a': 1, 'b': 2}); 195 var model = toObservable({'a': 1, 'b': 2});
160 nodeBind(element).bind('hidden?', new PathObserver(model, 'a')); 196 bindings.add(
161 nodeBind(element).bind('id', new PathObserver(model, 'b')); 197 nodeBind(element).bind('hidden?', new PathObserver(model, 'a')));
198 bindings.add(nodeBind(element).bind('id', new PathObserver(model, 'b')));
162 199
163 expect(element.attributes, contains('hidden')); 200 expect(element.attributes, contains('hidden'));
164 expect(element.attributes['hidden'], ''); 201 expect(element.attributes['hidden'], '');
165 expect(element.id, '2'); 202 expect(element.id, '2');
166 203
167 model['a'] = null; 204 model['a'] = null;
168 return new Future(() { 205 return new Future(() {
169 expect(element.attributes, isNot(contains('hidden')), 206 expect(element.attributes, isNot(contains('hidden')),
170 reason: 'null is false-y'); 207 reason: 'null is false-y');
171 208
172 model['a'] = false; 209 model['a'] = false;
173 }).then(endOfMicrotask).then((_) { 210 }).then(endOfMicrotask).then((_) {
174 expect(element.attributes, isNot(contains('hidden'))); 211 expect(element.attributes, isNot(contains('hidden')));
175 212
176 model['a'] = 'foo'; 213 model['a'] = 'foo';
177 model['b'] = 'x'; 214 model['b'] = 'x';
178 }).then(endOfMicrotask).then((_) { 215 }).then(endOfMicrotask).then((_) {
179 expect(element.attributes, contains('hidden')); 216 expect(element.attributes, contains('hidden'));
180 expect(element.attributes['hidden'], ''); 217 expect(element.attributes['hidden'], '');
181 expect(element.id, 'x'); 218 expect(element.id, 'x');
182 }); 219 });
183 }); 220 });
184 221
185 test('Element.id - path unreachable', () { 222 test('Element.id - path unreachable', () {
186 var element = testDiv.append(new DivElement()); 223 var element = testDiv.append(new DivElement());
187 var model = toObservable({}); 224 var model = toObservable({});
188 nodeBind(element).bind('id', new PathObserver(model, 'a')); 225 bindings.add(nodeBind(element).bind('id', new PathObserver(model, 'a')));
189 return new Future(() => expect(element.id, '')); 226 return new Future(() => expect(element.id, ''));
190 }); 227 });
191 } 228 }
192 229
193 formBindings() { 230 formBindings() {
194 inputTextAreaValueTest(String tagName) { 231 inputTextAreaValueTest(String tagName) {
195 var el = new Element.tag(tagName); 232 var el = new Element.tag(tagName);
196 testDiv.nodes.add(el); 233 testDiv.nodes.add(el);
197 var model = toObservable({'x': 42}); 234 var model = toObservable({'x': 42});
198 nodeBind(el).bind('value', new PathObserver(model, 'x')); 235 bindings.add(nodeBind(el).bind('value', new PathObserver(model, 'x')));
199 expect(el.value, '42'); 236 expect(el.value, '42');
200 237
201 model['x'] = 'Hi'; 238 model['x'] = 'Hi';
202 expect(el.value, '42', reason: 'changes delivered async'); 239 expect(el.value, '42', reason: 'changes delivered async');
203 return new Future(() { 240 return new Future(() {
204 expect(el.value, 'Hi'); 241 expect(el.value, 'Hi');
205 242
206 el.value = 'changed'; 243 el.value = 'changed';
207 dispatchEvent('input', el); 244 dispatchEvent('input', el);
208 expect(model['x'], 'changed'); 245 expect(model['x'], 'changed');
209
210 nodeBind(el).unbind('value');
211
212 el.value = 'changed again';
213 dispatchEvent('input', el);
214 expect(model['x'], 'changed');
215
216 nodeBind(el).bind('value', new PathObserver(model, 'x'));
217 model['x'] = null;
218 }).then(endOfMicrotask).then((_) {
219 expect(el.value, '');
220 }); 246 });
221 } 247 }
222 248
223 inputTextAreaValueOnetime(String tagName) { 249 inputTextAreaValueOnetime(String tagName) {
224 var el = testDiv.append(new Element.tag(tagName)); 250 var el = testDiv.append(new Element.tag(tagName));
225 nodeBind(el).bind('value', 42, oneTime: true); 251 bindings.add(nodeBind(el).bind('value', 42, oneTime: true));
226 expect(el.value, '42'); 252 expect(el.value, '42');
227 } 253 }
228 254
229 inputTextAreaNoPath(String tagName) { 255 inputTextAreaNoPath(String tagName) {
230 var el = testDiv.append(new Element.tag(tagName)); 256 var el = testDiv.append(new Element.tag(tagName));
231 var model = 42; 257 var model = 42;
232 nodeBind(el).bind('value', new PathObserver(model)); 258 bindings.add(nodeBind(el).bind('value', new PathObserver(model)));
233 expect(el.value, '42'); 259 expect(el.value, '42');
234 } 260 }
235 261
236 inputTextAreaPathUnreachable(String tagName) { 262 inputTextAreaPathUnreachable(String tagName) {
237 var el = testDiv.append(new Element.tag(tagName)); 263 var el = testDiv.append(new Element.tag(tagName));
238 var model = toObservable({}); 264 var model = toObservable({});
239 nodeBind(el).bind('value', new PathObserver(model, 'a')); 265 bindings.add(nodeBind(el).bind('value', new PathObserver(model, 'a')));
240 expect(el.value, ''); 266 expect(el.value, '');
241 } 267 }
242 268
243 test('Input.value', 269 test('Input.value',
244 () => inputTextAreaValueTest('input')); 270 () => inputTextAreaValueTest('input'));
245 271
246 test('Input.value - oneTime', 272 test('Input.value - oneTime',
247 () => inputTextAreaValueOnetime('input')); 273 () => inputTextAreaValueOnetime('input'));
248 274
249 test('Input.value - no path', 275 test('Input.value - no path',
(...skipping 11 matching lines...) Expand all
261 test('TextArea.value - no path', 287 test('TextArea.value - no path',
262 () => inputTextAreaNoPath('textarea')); 288 () => inputTextAreaNoPath('textarea'));
263 289
264 test('TextArea.value - path unreachable', 290 test('TextArea.value - path unreachable',
265 () => inputTextAreaPathUnreachable('textarea')); 291 () => inputTextAreaPathUnreachable('textarea'));
266 292
267 test('Radio Input', () { 293 test('Radio Input', () {
268 var input = new InputElement(); 294 var input = new InputElement();
269 input.type = 'radio'; 295 input.type = 'radio';
270 var model = toObservable({'x': true}); 296 var model = toObservable({'x': true});
271 nodeBind(input).bind('checked', new PathObserver(model, 'x')); 297 bindings.add(nodeBind(input).bind('checked', new PathObserver(model, 'x')));
272 expect(input.checked, true); 298 expect(input.checked, true);
273 299
274 model['x'] = false; 300 model['x'] = false;
275 expect(input.checked, true); 301 expect(input.checked, true);
276 return new Future(() { 302 return new Future(() {
277 expect(input.checked, false,reason: 'model change should update checked'); 303 expect(input.checked, false,reason: 'model change should update checked');
278 304
279 input.checked = true; 305 input.checked = true;
280 dispatchEvent('change', input); 306 dispatchEvent('change', input);
281 expect(model['x'], true, reason: 'input.checked should set model'); 307 expect(model['x'], true, reason: 'input.checked should set model');
282 308
283 nodeBind(input).unbind('checked'); 309 bindings[0].close();
284 310
285 input.checked = false; 311 input.checked = false;
286 dispatchEvent('change', input); 312 dispatchEvent('change', input);
287 expect(model['x'], true, 313 expect(model['x'], true,
288 reason: 'disconnected binding should not fire'); 314 reason: 'disconnected binding should not fire');
289 }); 315 });
290 }); 316 });
291 317
292 test('Input.value - user value rejected', () { 318 test('Input.value - user value rejected', () {
293 var model = toObservable({'val': 'ping'}); 319 var model = toObservable({'val': 'ping'});
294 320
321 var rejector = new PathObserver(model, 'val');
322 rejector.open(() {
323 model['val'] = 'ping';
324 });
325
295 var el = new InputElement(); 326 var el = new InputElement();
296 nodeBind(el).bind('value', new PathObserver(model, 'val')); 327 bindings.add(nodeBind(el).bind('value', new PathObserver(model, 'val')));
328
297 return new Future(() { 329 return new Future(() {
298 expect(el.value, 'ping'); 330 expect(el.value, 'ping');
299 331
300 el.value = 'pong'; 332 el.value = 'pong';
301 dispatchEvent('input', el); 333 dispatchEvent('input', el);
302 expect(model['val'], 'pong');
303 334
304 // Try a deep path.
305 model = toObservable({'a': {'b': {'c': 'ping'}}});
306
307 nodeBind(el).bind('value', new PathObserver(model, 'a.b.c'));
308 }).then(endOfMicrotask).then((_) { 335 }).then(endOfMicrotask).then((_) {
336 // rejector will have set the bound value back to 'ping'.
309 expect(el.value, 'ping'); 337 expect(el.value, 'ping');
310 338
311 el.value = 'pong'; 339 rejector.close();
312 dispatchEvent('input', el);
313 expect(new PropertyPath('a.b.c').getValueFrom(model), 'pong');
314
315 // Start with the model property being absent.
316 model['a']['b'].remove('c');
317 }).then(endOfMicrotask).then((_) {
318 expect(el.value, '');
319
320 el.value = 'pong';
321 dispatchEvent('input', el);
322 expect(new PropertyPath('a.b.c').getValueFrom(model), 'pong');
323 }).then(endOfMicrotask).then((_) {
324
325 // Model property unreachable (and unsettable).
326 model['a'].remove('b');
327 }).then(endOfMicrotask).then((_) {
328 expect(el.value, '');
329
330 el.value = 'pong';
331 dispatchEvent('input', el);
332 expect(new PropertyPath('a.b.c').getValueFrom(model), null);
333 }); 340 });
334 }); 341 });
335 342
336 test('Checkbox Input.checked', () { 343 test('Checkbox Input.checked', () {
337 var el = testDiv.append(new InputElement()); 344 var el = testDiv.append(new InputElement());
338 el.type = 'checkbox'; 345 el.type = 'checkbox';
339 346
340 var model = toObservable({'x': true}); 347 var model = toObservable({'x': true});
341 nodeBind(el).bind('checked', new PathObserver(model, 'x')); 348 bindings.add(nodeBind(el).bind('checked', new PathObserver(model, 'x')));
342 expect(el.checked, true); 349 expect(el.checked, true);
343 350
344 model['x'] = false; 351 model['x'] = false;
345 expect(el.checked, true, reason: 'changes delivered async'); 352 expect(el.checked, true, reason: 'changes delivered async');
346 return new Future(() { 353 return new Future(() {
347 expect(el.checked, false); 354 expect(el.checked, false);
348 355
349 el.click(); 356 el.click();
350 expect(model['x'], true); 357 expect(model['x'], true);
351 }).then(endOfMicrotask).then((_) { 358 }).then(endOfMicrotask).then((_) {
352 359
353 el.click(); 360 el.click();
354 expect(model['x'], false); 361 expect(model['x'], false);
355 }); 362 });
356 }); 363 });
357 364
358 test('Checkbox Input.checked - oneTime', () { 365 test('Checkbox Input.checked - oneTime', () {
359 var input = testDiv.append(new InputElement()); 366 var input = testDiv.append(new InputElement());
360 input.type = 'checkbox'; 367 input.type = 'checkbox';
361 nodeBind(input).bind('checked', true, oneTime: true); 368 bindings.add(nodeBind(input).bind('checked', true, oneTime: true));
362 expect(input.checked, true, reason: 'checked was set'); 369 expect(input.checked, true, reason: 'checked was set');
363 }); 370 });
364 371
365 test('Checkbox Input.checked - path unreachable', () { 372 test('Checkbox Input.checked - path unreachable', () {
366 var input = testDiv.append(new InputElement()); 373 var input = testDiv.append(new InputElement());
367 input.type = 'checkbox'; 374 input.type = 'checkbox';
368 var model = toObservable({}); 375 var model = toObservable({});
369 nodeBind(input).bind('checked', new PathObserver(model, 'x')); 376 bindings.add(nodeBind(input).bind('checked', new PathObserver(model, 'x')));
370 expect(input.checked, false); 377 expect(input.checked, false);
371 }); 378 });
372 379
373 test('Checkbox Input.checked 2', () { 380 test('Checkbox Input.checked 2', () {
374 var model = toObservable({'val': true}); 381 var model = toObservable({'val': true});
375 382
376 var el = testDiv.append(new InputElement()); 383 var el = testDiv.append(new InputElement());
377 el.type = 'checkbox'; 384 el.type = 'checkbox';
378 nodeBind(el).bind('checked', new PathObserver(model, 'val')); 385 bindings.add(nodeBind(el).bind('checked', new PathObserver(model, 'val')));
379 return new Future(() { 386 return new Future(() {
380 expect(el.checked, true); 387 expect(el.checked, true);
381 388
382 model['val'] = false; 389 model['val'] = false;
383 }).then(endOfMicrotask).then((_) { 390 }).then(endOfMicrotask).then((_) {
384 expect(el.checked, false); 391 expect(el.checked, false);
385 392
386 el.click(); 393 el.click();
387 expect(model['val'], true); 394 expect(model['val'], true);
388 395
(...skipping 10 matching lines...) Expand all
399 el.dispatchEvent(new MouseEvent('click', view: window)); 406 el.dispatchEvent(new MouseEvent('click', view: window));
400 }); 407 });
401 }); 408 });
402 409
403 test('Checkbox Input.checked - binding updated on click', () { 410 test('Checkbox Input.checked - binding updated on click', () {
404 var model = toObservable({'val': true}); 411 var model = toObservable({'val': true});
405 412
406 var el = new InputElement(); 413 var el = new InputElement();
407 testDiv.append(el); 414 testDiv.append(el);
408 el.type = 'checkbox'; 415 el.type = 'checkbox';
409 nodeBind(el).bind('checked', new PathObserver(model, 'val')); 416 bindings.add(nodeBind(el).bind('checked', new PathObserver(model, 'val')));
410 return new Future(() { 417 return new Future(() {
411 expect(el.checked, true); 418 expect(el.checked, true);
412 419
413 int fired = 0; 420 int fired = 0;
414 el.onClick.listen((_) { 421 el.onClick.listen((_) {
415 fired++; 422 fired++;
416 expect(model['val'], false); 423 expect(model['val'], false);
417 }); 424 });
418 425
419 el.dispatchEvent(new MouseEvent('click', view: window)); 426 el.dispatchEvent(new MouseEvent('click', view: window));
420 427
421 expect(fired, 1, reason: 'events dispatched synchronously'); 428 expect(fired, 1, reason: 'events dispatched synchronously');
422 }); 429 });
423 }); 430 });
424 431
425 test('Checkbox Input.checked - binding updated on change', () { 432 test('Checkbox Input.checked - binding updated on change', () {
426 var model = toObservable({'val': true}); 433 var model = toObservable({'val': true});
427 434
428 var el = new InputElement(); 435 var el = new InputElement();
429 testDiv.append(el); 436 testDiv.append(el);
430 el.type = 'checkbox'; 437 el.type = 'checkbox';
431 nodeBind(el).bind('checked', new PathObserver(model, 'val')); 438 bindings.add(nodeBind(el).bind('checked', new PathObserver(model, 'val')));
432 return new Future(() { 439 return new Future(() {
433 expect(el.checked, true); 440 expect(el.checked, true);
434 441
435 int fired = 0; 442 int fired = 0;
436 el.onChange.listen((_) { 443 el.onChange.listen((_) {
437 fired++; 444 fired++;
438 expect(model['val'], false); 445 expect(model['val'], false);
439 }); 446 });
440 447
441 el.dispatchEvent(new MouseEvent('click', view: window)); 448 el.dispatchEvent(new MouseEvent('click', view: window));
442 449
443 expect(fired, 1, reason: 'events dispatched synchronously'); 450 expect(fired, 1, reason: 'events dispatched synchronously');
444 }); 451 });
445 }); 452 });
446 453
447 test('Radio Input.checked', () { 454 test('Radio Input.checked', () {
448 var input = testDiv.append(new InputElement()); 455 var input = testDiv.append(new InputElement());
449 input.type = 'radio'; 456 input.type = 'radio';
450 var model = toObservable({'x': true}); 457 var model = toObservable({'x': true});
451 nodeBind(input).bind('checked', new PathObserver(model, 'x')); 458 bindings.add(nodeBind(input).bind('checked', new PathObserver(model, 'x')));
452 expect(input.checked, true); 459 expect(input.checked, true);
453 460
454 model['x'] = false; 461 model['x'] = false;
455 expect(input.checked, true); 462 expect(input.checked, true);
456 return new Future(() { 463 return new Future(() {
457 expect(input.checked, false); 464 expect(input.checked, false);
458 465
459 input.checked = true; 466 input.checked = true;
460 dispatchEvent('change', input); 467 dispatchEvent('change', input);
461 expect(model['x'], true); 468 expect(model['x'], true);
462
463 nodeBind(input).unbind('checked');
464
465 input.checked = false;
466 dispatchEvent('change', input);
467 expect(model['x'], true);
468 }); 469 });
469 }); 470 });
470 471
471 test('Radio Input.checked - oneTime', () { 472 test('Radio Input.checked - oneTime', () {
472 var input = testDiv.append(new InputElement()); 473 var input = testDiv.append(new InputElement());
473 input.type = 'radio'; 474 input.type = 'radio';
474 nodeBind(input).bind('checked', true, oneTime: true); 475 bindings.add(nodeBind(input).bind('checked', true, oneTime: true));
475 expect(input.checked, true, reason: 'checked was set'); 476 expect(input.checked, true, reason: 'checked was set');
476 }); 477 });
477 478
478 radioInputChecked2(host) { 479 radioInputChecked2(host) {
479 var model = toObservable({'val1': true, 'val2': false, 'val3': false, 480 var model = toObservable({'val1': true, 'val2': false, 'val3': false,
480 'val4': true}); 481 'val4': true});
481 var RADIO_GROUP_NAME = 'test'; 482 var RADIO_GROUP_NAME = 'test';
482 483
483 var container = host.append(new DivElement()); 484 var container = host.append(new DivElement());
484 485
485 var el1 = container.append(new InputElement()); 486 var el1 = container.append(new InputElement());
486 el1.type = 'radio'; 487 el1.type = 'radio';
487 el1.name = RADIO_GROUP_NAME; 488 el1.name = RADIO_GROUP_NAME;
488 nodeBind(el1).bind('checked', new PathObserver(model, 'val1')); 489 bindings.add(
490 nodeBind(el1).bind('checked', new PathObserver(model, 'val1')));
489 491
490 var el2 = container.append(new InputElement()); 492 var el2 = container.append(new InputElement());
491 el2.type = 'radio'; 493 el2.type = 'radio';
492 el2.name = RADIO_GROUP_NAME; 494 el2.name = RADIO_GROUP_NAME;
493 nodeBind(el2).bind('checked', new PathObserver(model, 'val2')); 495 bindings.add(
496 nodeBind(el2).bind('checked', new PathObserver(model, 'val2')));
494 497
495 var el3 = container.append(new InputElement()); 498 var el3 = container.append(new InputElement());
496 el3.type = 'radio'; 499 el3.type = 'radio';
497 el3.name = RADIO_GROUP_NAME; 500 el3.name = RADIO_GROUP_NAME;
498 nodeBind(el3).bind('checked', new PathObserver(model, 'val3')); 501 bindings.add(
502 nodeBind(el3).bind('checked', new PathObserver(model, 'val3')));
499 503
500 var el4 = container.append(new InputElement()); 504 var el4 = container.append(new InputElement());
501 el4.type = 'radio'; 505 el4.type = 'radio';
502 el4.name = 'othergroup'; 506 el4.name = 'othergroup';
503 nodeBind(el4).bind('checked', new PathObserver(model, 'val4')); 507 bindings.add(
508 nodeBind(el4).bind('checked', new PathObserver(model, 'val4')));
504 509
505 return new Future(() { 510 return new Future(() {
506 expect(el1.checked, true); 511 expect(el1.checked, true);
507 expect(el2.checked, false); 512 expect(el2.checked, false);
508 expect(el3.checked, false); 513 expect(el3.checked, false);
509 expect(el4.checked, true); 514 expect(el4.checked, true);
510 515
511 model['val1'] = false; 516 model['val1'] = false;
512 model['val2'] = true; 517 model['val2'] = true;
513 }).then(endOfMicrotask).then((_) { 518 }).then(endOfMicrotask).then((_) {
(...skipping 17 matching lines...) Expand all
531 expect(model['val4'], true); 536 expect(model['val4'], true);
532 }); 537 });
533 } 538 }
534 539
535 test('Radio Input.checked 2', () => radioInputChecked2(testDiv)); 540 test('Radio Input.checked 2', () => radioInputChecked2(testDiv));
536 541
537 test('Radio Input.checked 2 - ShadowRoot', () { 542 test('Radio Input.checked 2 - ShadowRoot', () {
538 if (!ShadowRoot.supported) return null; 543 if (!ShadowRoot.supported) return null;
539 544
540 var shadowRoot = new DivElement().createShadowRoot(); 545 var shadowRoot = new DivElement().createShadowRoot();
541 return radioInputChecked2(shadowRoot) 546 return radioInputChecked2(shadowRoot);
542 .whenComplete(() => unbindAll(shadowRoot));
543 }); 547 });
544 548
545 radioInputCheckedMultipleForms(host) { 549 radioInputCheckedMultipleForms(host) {
546 var model = toObservable({'val1': true, 'val2': false, 'val3': false, 550 var model = toObservable({'val1': true, 'val2': false, 'val3': false,
547 'val4': true}); 551 'val4': true});
548 var RADIO_GROUP_NAME = 'test'; 552 var RADIO_GROUP_NAME = 'test';
549 553
550 var container = testDiv.append(new DivElement()); 554 var container = testDiv.append(new DivElement());
551 var form1 = new FormElement(); 555 var form1 = new FormElement();
552 container.append(form1); 556 container.append(form1);
553 var form2 = new FormElement(); 557 var form2 = new FormElement();
554 container.append(form2); 558 container.append(form2);
555 559
556 var el1 = new InputElement(); 560 var el1 = new InputElement();
557 form1.append(el1); 561 form1.append(el1);
558 el1.type = 'radio'; 562 el1.type = 'radio';
559 el1.name = RADIO_GROUP_NAME; 563 el1.name = RADIO_GROUP_NAME;
560 nodeBind(el1).bind('checked', new PathObserver(model, 'val1')); 564 bindings.add(
565 nodeBind(el1).bind('checked', new PathObserver(model, 'val1')));
561 566
562 var el2 = new InputElement(); 567 var el2 = new InputElement();
563 form1.append(el2); 568 form1.append(el2);
564 el2.type = 'radio'; 569 el2.type = 'radio';
565 el2.name = RADIO_GROUP_NAME; 570 el2.name = RADIO_GROUP_NAME;
566 nodeBind(el2).bind('checked', new PathObserver(model, 'val2')); 571 bindings.add(
572 nodeBind(el2).bind('checked', new PathObserver(model, 'val2')));
567 573
568 var el3 = new InputElement(); 574 var el3 = new InputElement();
569 form2.append(el3); 575 form2.append(el3);
570 el3.type = 'radio'; 576 el3.type = 'radio';
571 el3.name = RADIO_GROUP_NAME; 577 el3.name = RADIO_GROUP_NAME;
572 nodeBind(el3).bind('checked', new PathObserver(model, 'val3')); 578 bindings.add(
579 nodeBind(el3).bind('checked', new PathObserver(model, 'val3')));
573 580
574 var el4 = new InputElement(); 581 var el4 = new InputElement();
575 form2.append(el4); 582 form2.append(el4);
576 el4.type = 'radio'; 583 el4.type = 'radio';
577 el4.name = RADIO_GROUP_NAME; 584 el4.name = RADIO_GROUP_NAME;
578 nodeBind(el4).bind('checked', new PathObserver(model, 'val4')); 585 bindings.add(
586 nodeBind(el4).bind('checked', new PathObserver(model, 'val4')));
579 587
580 return new Future(() { 588 return new Future(() {
581 expect(el1.checked, true); 589 expect(el1.checked, true);
582 expect(el2.checked, false); 590 expect(el2.checked, false);
583 expect(el3.checked, false); 591 expect(el3.checked, false);
584 expect(el4.checked, true); 592 expect(el4.checked, true);
585 593
586 el2.checked = true; 594 el2.checked = true;
587 dispatchEvent('change', el2); 595 dispatchEvent('change', el2);
588 expect(model['val1'], false); 596 expect(model['val1'], false);
(...skipping 15 matching lines...) Expand all
604 } 612 }
605 613
606 test('Radio Input.checked - multiple forms', () { 614 test('Radio Input.checked - multiple forms', () {
607 return radioInputCheckedMultipleForms(testDiv); 615 return radioInputCheckedMultipleForms(testDiv);
608 }); 616 });
609 617
610 test('Radio Input.checked - multiple forms - ShadowRoot', () { 618 test('Radio Input.checked - multiple forms - ShadowRoot', () {
611 if (!ShadowRoot.supported) return null; 619 if (!ShadowRoot.supported) return null;
612 620
613 var shadowRoot = new DivElement().createShadowRoot(); 621 var shadowRoot = new DivElement().createShadowRoot();
614 return radioInputCheckedMultipleForms(shadowRoot) 622 return radioInputCheckedMultipleForms(shadowRoot);
615 .whenComplete(() => unbindAll(shadowRoot));
616 }); 623 });
617 624
618 test('Select.selectedIndex', () { 625 test('Select.selectedIndex', () {
619 var select = new SelectElement(); 626 var select = new SelectElement();
620 testDiv.append(select); 627 testDiv.append(select);
621 var option0 = select.append(new OptionElement()); 628 var option0 = select.append(new OptionElement());
622 var option1 = select.append(new OptionElement()); 629 var option1 = select.append(new OptionElement());
623 var option2 = select.append(new OptionElement()); 630 var option2 = select.append(new OptionElement());
624 631
625 var model = toObservable({'val': 2}); 632 var model = toObservable({'val': 2});
626 633
627 nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val')); 634 bindings.add(
635 nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val')));
628 return new Future(() { 636 return new Future(() {
629 expect(select.selectedIndex, 2); 637 expect(select.selectedIndex, 2);
630 638
631 select.selectedIndex = 1; 639 select.selectedIndex = 1;
632 dispatchEvent('change', select); 640 dispatchEvent('change', select);
633 expect(model['val'], 1); 641 expect(model['val'], 1);
634 }); 642 });
635 }); 643 });
636 644
637 test('Select.selectedIndex - oneTime', () { 645 test('Select.selectedIndex - oneTime', () {
638 var select = new SelectElement(); 646 var select = new SelectElement();
639 testDiv.append(select); 647 testDiv.append(select);
640 var option0 = select.append(new OptionElement()); 648 var option0 = select.append(new OptionElement());
641 var option1 = select.append(new OptionElement()); 649 var option1 = select.append(new OptionElement());
642 var option2 = select.append(new OptionElement()); 650 var option2 = select.append(new OptionElement());
643 651
644 nodeBind(select).bind('selectedIndex', 2, oneTime: true); 652 bindings.add(nodeBind(select).bind('selectedIndex', 2, oneTime: true));
645 return new Future(() => expect(select.selectedIndex, 2)); 653 return new Future(() => expect(select.selectedIndex, 2));
646 }); 654 });
647 655
648 test('Select.selectedIndex - invalid path', () { 656 test('Select.selectedIndex - invalid path', () {
649 var select = new SelectElement(); 657 var select = new SelectElement();
650 testDiv.append(select); 658 testDiv.append(select);
651 var option0 = select.append(new OptionElement()); 659 var option0 = select.append(new OptionElement());
652 var option1 = select.append(new OptionElement()); 660 var option1 = select.append(new OptionElement());
653 option1.selected = true; 661 option1.selected = true;
654 var option2 = select.append(new OptionElement()); 662 var option2 = select.append(new OptionElement());
655 663
656 var model = toObservable({'val': 'foo'}); 664 var model = toObservable({'val': 'foo'});
657 665
658 nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val')); 666 bindings.add(
667 nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val')));
659 return new Future(() => expect(select.selectedIndex, 0)); 668 return new Future(() => expect(select.selectedIndex, 0));
660 }); 669 });
661 670
662 test('Select.selectedIndex - path unreachable', () { 671 test('Select.selectedIndex - path unreachable', () {
663 var select = new SelectElement(); 672 var select = new SelectElement();
664 testDiv.append(select); 673 testDiv.append(select);
665 var option0 = select.append(new OptionElement()); 674 var option0 = select.append(new OptionElement());
666 var option1 = select.append(new OptionElement()); 675 var option1 = select.append(new OptionElement());
667 option1.selected = true; 676 option1.selected = true;
668 var option2 = select.append(new OptionElement()); 677 var option2 = select.append(new OptionElement());
669 678
670 var model = toObservable({}); 679 var model = toObservable({});
671 680
672 nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val')); 681 bindings.add(
682 nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val')));
673 return new Future(() => expect(select.selectedIndex, 0)); 683 return new Future(() => expect(select.selectedIndex, 0));
674 }); 684 });
675 685
676 test('Option.value', () { 686 test('Option.value', () {
677 var option = testDiv.append(new OptionElement()); 687 var option = testDiv.append(new OptionElement());
678 var model = toObservable({'x': 42}); 688 var model = toObservable({'x': 42});
679 nodeBind(option).bind('value', new PathObserver(model, 'x')); 689 bindings.add(nodeBind(option).bind('value', new PathObserver(model, 'x')));
680 expect(option.value, '42'); 690 expect(option.value, '42');
681 691
682 model['x'] = 'Hi'; 692 model['x'] = 'Hi';
683 expect(option.value, '42'); 693 expect(option.value, '42');
684 return new Future(() => expect(option.value, 'Hi')); 694 return new Future(() => expect(option.value, 'Hi'));
685 }); 695 });
686 696
687 test('Option.value - oneTime', () { 697 test('Option.value - oneTime', () {
688 var option = testDiv.append(new OptionElement()); 698 var option = testDiv.append(new OptionElement());
689 nodeBind(option).bind('value', 42, oneTime: true); 699 bindings.add(nodeBind(option).bind('value', 42, oneTime: true));
690 expect(option.value, '42'); 700 expect(option.value, '42');
691 }); 701 });
692 702
693 test('Select.value', () { 703 test('Select.value', () {
694 var select = testDiv.append(new SelectElement()); 704 var select = testDiv.append(new SelectElement());
695 testDiv.append(select); 705 testDiv.append(select);
696 var option0 = select.append(new OptionElement()); 706 var option0 = select.append(new OptionElement());
697 var option1 = select.append(new OptionElement()); 707 var option1 = select.append(new OptionElement());
698 var option2 = select.append(new OptionElement()); 708 var option2 = select.append(new OptionElement());
699 709
700 var model = toObservable({ 710 var model = toObservable({
701 'opt0': 'a', 711 'opt0': 'a',
702 'opt1': 'b', 712 'opt1': 'b',
703 'opt2': 'c', 713 'opt2': 'c',
704 'selected': 'b' 714 'selected': 'b'
705 }); 715 });
706 716
707 nodeBind(option0).bind('value', new PathObserver(model, 'opt0')); 717 bindings.add(
708 nodeBind(option1).bind('value', new PathObserver(model, 'opt1')); 718 nodeBind(option0).bind('value', new PathObserver(model, 'opt0')));
709 nodeBind(option2).bind('value', new PathObserver(model, 'opt2')); 719 bindings.add(
710 720 nodeBind(option1).bind('value', new PathObserver(model, 'opt1')));
711 nodeBind(select).bind('value', new PathObserver(model, 'selected')); 721 bindings.add(
722 nodeBind(option2).bind('value', new PathObserver(model, 'opt2')));
723 bindings.add(
724 nodeBind(select).bind('value', new PathObserver(model, 'selected')));
712 return new Future(() { 725 return new Future(() {
713 expect(select.value, 'b'); 726 expect(select.value, 'b');
714 727
715 select.value = 'c'; 728 select.value = 'c';
716 dispatchEvent('change', select); 729 dispatchEvent('change', select);
717 expect(model['selected'], 'c'); 730 expect(model['selected'], 'c');
718 731
719 model['opt2'] = 'X'; 732 model['opt2'] = 'X';
720 }).then(endOfMicrotask).then((_) { 733 }).then(endOfMicrotask).then((_) {
721 expect(select.value, 'X'); 734 expect(select.value, 'X');
722 expect(model['selected'], 'X'); 735 expect(model['selected'], 'X');
723 736
724 model['selected'] = 'a'; 737 model['selected'] = 'a';
725 }).then(endOfMicrotask).then((_) { 738 }).then(endOfMicrotask).then((_) {
726 expect(select.value, 'a'); 739 expect(select.value, 'a');
727 }); 740 });
728 }); 741 });
729 } 742 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698