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