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

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

Issue 50203004: port TemplateBinding to ed3266266e751b5ab1f75f8e0509d0d5f0ef35d8 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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
(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_bindings_test;
6
7 import 'dart:html';
8
9 @MirrorsUsed(targets: const [NodeBinding], override:
10 'template_binding.test.node_bindings_test')
11 import 'dart:mirrors';
12
13 import 'package:observe/observe.dart' show toObservable, PathObserver;
14 import 'package:template_binding/template_binding.dart'
15 show nodeBind, NodeBinding;
16 import 'package:unittest/html_config.dart';
17 import 'package:unittest/unittest.dart';
18 import 'utils.dart';
19
20 // Note: this file ported from
21 // https://github.com/toolkitchen/mdv/blob/master/tests/node_bindings.js
22
23 main() {
24 useHtmlConfiguration();
25
26 setUp(() {
27 document.body.append(testDiv = new DivElement());
28 });
29
30 tearDown(() {
31 testDiv.remove();
32 testDiv = null;
33 });
34
35
36 group('Text bindings', testBindings);
37 group('Element attribute bindings', elementBindings);
38 group('Form Element bindings', formBindings);
39 }
40
41 testBindings() {
42 observeTest('Basic', () {
43 var text = new Text('hi');
44 var model = toObservable({'a': 1});
45 nodeBind(text).bind('text', model, 'a');
46 expect(text.text, '1');
47
48 model['a'] = 2;
49 performMicrotaskCheckpoint();
50 expect(text.text, '2');
51
52 nodeBind(text).unbind('text');
53 model['a'] = 3;
54 performMicrotaskCheckpoint();
55 expect(text.text, '2');
56
57 // TODO(rafaelw): Throw on binding to unavailable property?
58 });
59
60 observeTest('No Path', () {
61 var text = new Text('hi');
62 var model = 1;
63 nodeBind(text).bind('text', model);
64 expect(text.text, '1');
65 });
66
67 observeTest('Path unreachable', () {
68 var text = testDiv.append(new Text('hi'));
69 var model = 1;
70 nodeBind(text).bind('text', model, 'a');
71 expect(text.text, '');
72 });
73
74 observeTest('Observer is Model', () {
75 _observer(x) => reflect(x).getField(
76 privateSymbol(NodeBinding, '_observer')).reflectee;
77
78 var text = new Text('');
79 var model = toObservable({'a': {'b': {'c': 1}}});
80 var observer = new PathObserver(model, 'a.b.c');
81 nodeBind(text).bind('text', observer, 'value');
82 expect(text.text, '1');
83
84 var binding = nodeBind(text).bindings['text'];
85 expect(binding, isNotNull);
86 expect(privateField(binding, '_observer'), observer,
87 reason: 'should reuse observer');
88
89 model['a']['b']['c'] = 2;
90 performMicrotaskCheckpoint();
91 expect(text.text, '2');
92 nodeBind(text).unbind('text');
93 });
94 }
95
96 elementBindings() {
97 observeTest('Basic', () {
98 var el = new DivElement();
99 var model = toObservable({'a': '1'});
100 nodeBind(el).bind('foo', model, 'a');
101 performMicrotaskCheckpoint();
102 expect(el.attributes['foo'], '1');
103
104 model['a'] = '2';
105 performMicrotaskCheckpoint();
106 expect(el.attributes['foo'], '2');
107
108 model['a'] = 232.2;
109 performMicrotaskCheckpoint();
110 expect(el.attributes['foo'], '232.2');
111
112 model['a'] = 232;
113 performMicrotaskCheckpoint();
114 expect(el.attributes['foo'], '232');
115
116 model['a'] = null;
117 performMicrotaskCheckpoint();
118 expect(el.attributes['foo'], '');
119 });
120
121 observeTest('No Path', () {
122 var el = testDiv.append(new DivElement());
123 var model = 1;
124 nodeBind(el).bind('foo', model);
125 expect(el.attributes['foo'], '1');
126 });
127
128 observeTest('Path unreachable', () {
129 var el = testDiv.append(new DivElement());
130 var model = toObservable({});
131 nodeBind(el).bind('foo', model, 'bar');
132 expect(el.attributes['foo'], '');
133 });
134
135 observeTest('Dashes', () {
136 var el = testDiv.append(new DivElement());
137 var model = toObservable({'a': '1'});
138 nodeBind(el).bind('foo-bar', model, 'a');
139 performMicrotaskCheckpoint();
140 expect(el.attributes['foo-bar'], '1');
141
142 model['a'] = '2';
143 performMicrotaskCheckpoint();
144 expect(el.attributes['foo-bar'], '2');
145 });
146
147 observeTest('Element.id, Element.hidden?', () {
148 var element = new DivElement();
149 var model = toObservable({'a': 1, 'b': 2});
150 nodeBind(element).bind('hidden?', model, 'a');
151 nodeBind(element).bind('id', model, 'b');
152
153 expect(element.attributes, contains('hidden'));
154 expect(element.attributes['hidden'], '');
155 expect(element.id, '2');
156
157 model['a'] = null;
158 performMicrotaskCheckpoint();
159 expect(element.attributes, isNot(contains('hidden')),
160 reason: 'null is false-y');
161
162 model['a'] = false;
163 performMicrotaskCheckpoint();
164 expect(element.attributes, isNot(contains('hidden')));
165
166 model['a'] = 'foo';
167 model['b'] = 'x';
168 performMicrotaskCheckpoint();
169 expect(element.attributes, contains('hidden'));
170 expect(element.attributes['hidden'], '');
171 expect(element.id, 'x');
172 });
173
174 observeTest('Element.id - path unreachable', () {
175 var element = testDiv.append(new DivElement());
176 var model = toObservable({});
177 nodeBind(element).bind('id', model, 'a');
178 expect(element.id, '');
179 });
180 }
181
182 formBindings() {
183 inputTextAreaValueTest(String tagName) {
184 var el = new Element.tag(tagName);
185 testDiv.nodes.add(el);
186 var model = toObservable({'x': 42});
187 nodeBind(el).bind('value', model, 'x');
188 expect(el.value, '42');
189
190 model['x'] = 'Hi';
191 expect(el.value, '42', reason: 'changes delivered async');
192 performMicrotaskCheckpoint();
193 expect(el.value, 'Hi');
194
195 el.value = 'changed';
196 dispatchEvent('input', el);
197 expect(model['x'], 'changed');
198
199 nodeBind(el).unbind('value');
200
201 el.value = 'changed again';
202 dispatchEvent('input', el);
203 expect(model['x'], 'changed');
204
205 nodeBind(el).bind('value', model, 'x');
206 model['x'] = null;
207 performMicrotaskCheckpoint();
208 expect(el.value, '');
209 }
210
211 inputTextAreaNoPath(String tagName) {
212 var el = testDiv.append(new Element.tag(tagName));
213 var model = 42;
214 nodeBind(el).bind('value', model);
215 expect(el.value, '42');
216 }
217
218 inputTextAreaPathUnreachable(String tagName) {
219 var el = testDiv.append(new Element.tag(tagName));
220 var model = toObservable({});
221 nodeBind(el).bind('value', model, 'a');
222 expect(el.value, '');
223 }
224
225 observeTest('Input.value',
226 () => inputTextAreaValueTest('input'));
227 observeTest('Input.value - no path',
228 () => inputTextAreaNoPath('input'));
229 observeTest('Input.value - path unreachable',
230 () => inputTextAreaPathUnreachable('input'));
231 observeTest('TextArea.value',
232 () => inputTextAreaValueTest('textarea'));
233 observeTest('TextArea.value - no path',
234 () => inputTextAreaNoPath('textarea'));
235 observeTest('TextArea.value - path unreachable',
236 () => inputTextAreaPathUnreachable('textarea'));
237
238 observeTest('Radio Input', () {
239 var input = new InputElement();
240 input.type = 'radio';
241 var model = toObservable({'x': true});
242 nodeBind(input).bind('checked', model, 'x');
243 expect(input.checked, true);
244
245 model['x'] = false;
246 expect(input.checked, true);
247 performMicrotaskCheckpoint();
248 expect(input.checked, false,reason: 'model change should update checked');
249
250 input.checked = true;
251 dispatchEvent('change', input);
252 expect(model['x'], true, reason: 'input.checked should set model');
253
254 nodeBind(input).unbind('checked');
255
256 input.checked = false;
257 dispatchEvent('change', input);
258 expect(model['x'], true,
259 reason: 'disconnected binding should not fire');
260 });
261
262 observeTest('Input.value - user value rejected', () {
263 var model = toObservable({'val': 'ping'});
264
265 var el = new InputElement();
266 nodeBind(el).bind('value', model, 'val');
267 performMicrotaskCheckpoint();
268 expect(el.value, 'ping');
269
270 el.value = 'pong';
271 dispatchEvent('input', el);
272 expect(model['val'], 'pong');
273
274 // Try a deep path.
275 model = toObservable({'a': {'b': {'c': 'ping'}}});
276
277 nodeBind(el).bind('value', model, 'a.b.c');
278 performMicrotaskCheckpoint();
279 expect(el.value, 'ping');
280
281 el.value = 'pong';
282 dispatchEvent('input', el);
283 expect(new PathObserver(model, 'a.b.c').value, 'pong');
284
285 // Start with the model property being absent.
286 model['a']['b'].remove('c');
287 performMicrotaskCheckpoint();
288 expect(el.value, '');
289
290 el.value = 'pong';
291 dispatchEvent('input', el);
292 expect(new PathObserver(model, 'a.b.c').value, 'pong');
293 performMicrotaskCheckpoint();
294
295 // Model property unreachable (and unsettable).
296 model['a'].remove('b');
297 performMicrotaskCheckpoint();
298 expect(el.value, '');
299
300 el.value = 'pong';
301 dispatchEvent('input', el);
302 expect(new PathObserver(model, 'a.b.c').value, null);
303 });
304
305 observeTest('(Checkbox)Input.checked', () {
306 var el = testDiv.append(new InputElement());
307 el.type = 'checkbox';
308
309 var model = toObservable({'x': true});
310 nodeBind(el).bind('checked', model, 'x');
311 expect(el.checked, true);
312
313 model['x'] = false;
314 expect(el.checked, true, reason: 'changes delivered async');
315 performMicrotaskCheckpoint();
316 expect(el.checked, false);
317
318 el.click();
319 expect(model['x'], true);
320 performMicrotaskCheckpoint();
321
322 el.click();
323 expect(model['x'], false);
324 });
325
326 observeTest('(Checkbox)Input.checked - path unreachable', () {
327 var input = testDiv.append(new InputElement());
328 input.type = 'checkbox';
329 var model = toObservable({});
330 nodeBind(input).bind('checked', model, 'x');
331 expect(input.checked, false);
332 });
333
334 observeTest('(Checkbox)Input.checked 2', () {
335 var model = toObservable({'val': true});
336
337 var el = testDiv.append(new InputElement());
338 el.type = 'checkbox';
339 nodeBind(el).bind('checked', model, 'val');
340 performMicrotaskCheckpoint();
341 expect(el.checked, true);
342
343 model['val'] = false;
344 performMicrotaskCheckpoint();
345 expect(el.checked, false);
346
347 el.click();
348 expect(model['val'], true);
349
350 el.click();
351 expect(model['val'], false);
352
353 el.onClick.listen((_) {
354 expect(model['val'], true);
355 });
356 el.onChange.listen((_) {
357 expect(model['val'], true);
358 });
359
360 el.dispatchEvent(new MouseEvent('click', view: window));
361 });
362
363 observeTest('(Checkbox)Input.checked - binding updated on click', () {
364 var model = toObservable({'val': true});
365
366 var el = new InputElement();
367 testDiv.append(el);
368 el.type = 'checkbox';
369 nodeBind(el).bind('checked', model, 'val');
370 performMicrotaskCheckpoint();
371 expect(el.checked, true);
372
373 el.onClick.listen((_) {
374 expect(model['val'], false);
375 });
376
377 el.dispatchEvent(new MouseEvent('click', view: window));
378 });
379
380 observeTest('(Checkbox)Input.checked - binding updated on change', () {
381 var model = toObservable({'val': true});
382
383 var el = new InputElement();
384 testDiv.append(el);
385 el.type = 'checkbox';
386 nodeBind(el).bind('checked', model, 'val');
387 performMicrotaskCheckpoint();
388 expect(el.checked, true);
389
390 el.onChange.listen((_) {
391 expect(model['val'], false);
392 });
393
394 el.dispatchEvent(new MouseEvent('click', view: window));
395 });
396
397 observeTest('(Radio)Input.checked', () {
398 var input = testDiv.append(new InputElement());
399 input.type = 'radio';
400 var model = toObservable({'x': true});
401 nodeBind(input).bind('checked', model, 'x');
402 expect(input.checked, true);
403
404 model['x'] = false;
405 expect(input.checked, true);
406 performMicrotaskCheckpoint();
407 expect(input.checked, false);
408
409 input.checked = true;
410 dispatchEvent('change', input);
411 expect(model['x'], true);
412
413 nodeBind(input).unbind('checked');
414
415 input.checked = false;
416 dispatchEvent('change', input);
417 expect(model['x'], true);
418 });
419
420 radioInputChecked2(host) {
421 var model = toObservable({'val1': true, 'val2': false, 'val3': false,
422 'val4': true});
423 var RADIO_GROUP_NAME = 'test';
424
425 var container = host.append(new DivElement());
426
427 var el1 = container.append(new InputElement());
428 el1.type = 'radio';
429 el1.name = RADIO_GROUP_NAME;
430 nodeBind(el1).bind('checked', model, 'val1');
431
432 var el2 = container.append(new InputElement());
433 el2.type = 'radio';
434 el2.name = RADIO_GROUP_NAME;
435 nodeBind(el2).bind('checked', model, 'val2');
436
437 var el3 = container.append(new InputElement());
438 el3.type = 'radio';
439 el3.name = RADIO_GROUP_NAME;
440 nodeBind(el3).bind('checked', model, 'val3');
441
442 var el4 = container.append(new InputElement());
443 el4.type = 'radio';
444 el4.name = 'othergroup';
445 nodeBind(el4).bind('checked', model, 'val4');
446
447 performMicrotaskCheckpoint();
448 expect(el1.checked, true);
449 expect(el2.checked, false);
450 expect(el3.checked, false);
451 expect(el4.checked, true);
452
453 model['val1'] = false;
454 model['val2'] = true;
455 performMicrotaskCheckpoint();
456 expect(el1.checked, false);
457 expect(el2.checked, true);
458 expect(el3.checked, false);
459 expect(el4.checked, true);
460
461 el1.checked = true;
462 dispatchEvent('change', el1);
463 expect(model['val1'], true);
464 expect(model['val2'], false);
465 expect(model['val3'], false);
466 expect(model['val4'], true);
467
468 el3.checked = true;
469 dispatchEvent('change', el3);
470 expect(model['val1'], false);
471 expect(model['val2'], false);
472 expect(model['val3'], true);
473 expect(model['val4'], true);
474 }
475
476 observeTest('(Radio)Input.checked 2', () {
477 radioInputChecked2(testDiv);
478 });
479
480 observeTest('(Radio)Input.checked 2 - ShadowRoot', () {
481 if (!ShadowRoot.supported) return;
482
483 var div = new DivElement();
484 var shadowRoot = div.createShadowRoot();
485 radioInputChecked2(shadowRoot);
486 unbindAll(shadowRoot);
487 });
488
489 radioInputCheckedMultipleForms(host) {
490 var model = toObservable({'val1': true, 'val2': false, 'val3': false,
491 'val4': true});
492 var RADIO_GROUP_NAME = 'observeTest';
493
494 var container = testDiv.append(new DivElement());
495 var form1 = new FormElement();
496 container.append(form1);
497 var form2 = new FormElement();
498 container.append(form2);
499
500 var el1 = new InputElement();
501 form1.append(el1);
502 el1.type = 'radio';
503 el1.name = RADIO_GROUP_NAME;
504 nodeBind(el1).bind('checked', model, 'val1');
505
506 var el2 = new InputElement();
507 form1.append(el2);
508 el2.type = 'radio';
509 el2.name = RADIO_GROUP_NAME;
510 nodeBind(el2).bind('checked', model, 'val2');
511
512 var el3 = new InputElement();
513 form2.append(el3);
514 el3.type = 'radio';
515 el3.name = RADIO_GROUP_NAME;
516 nodeBind(el3).bind('checked', model, 'val3');
517
518 var el4 = new InputElement();
519 form2.append(el4);
520 el4.type = 'radio';
521 el4.name = RADIO_GROUP_NAME;
522 nodeBind(el4).bind('checked', model, 'val4');
523
524 performMicrotaskCheckpoint();
525 expect(el1.checked, true);
526 expect(el2.checked, false);
527 expect(el3.checked, false);
528 expect(el4.checked, true);
529
530 el2.checked = true;
531 dispatchEvent('change', el2);
532 expect(model['val1'], false);
533 expect(model['val2'], true);
534
535 // Radio buttons in form2 should be unaffected
536 expect(model['val3'], false);
537 expect(model['val4'], true);
538
539 el3.checked = true;
540 dispatchEvent('change', el3);
541 expect(model['val3'], true);
542 expect(model['val4'], false);
543
544 // Radio buttons in form1 should be unaffected
545 expect(model['val1'], false);
546 expect(model['val2'], true);
547 }
548
549 observeTest('(Radio)Input.checked - multiple forms', () {
550 radioInputCheckedMultipleForms(testDiv);
551 });
552
553 observeTest('(Radio)Input.checked 2 - ShadowRoot', () {
554 if (!ShadowRoot.supported) return;
555
556 var shadowRoot = new DivElement().createShadowRoot();
557 radioInputChecked2(shadowRoot);
558 unbindAll(shadowRoot);
559 });
560
561 observeTest('Select.selectedIndex', () {
562 var select = new SelectElement();
563 testDiv.append(select);
564 var option0 = select.append(new OptionElement());
565 var option1 = select.append(new OptionElement());
566 var option2 = select.append(new OptionElement());
567
568 var model = toObservable({'val': 2});
569
570 nodeBind(select).bind('selectedIndex', model, 'val');
571 performMicrotaskCheckpoint();
572 expect(select.selectedIndex, 2);
573
574 select.selectedIndex = 1;
575 dispatchEvent('change', select);
576 expect(model['val'], 1);
577 });
578
579 observeTest('Select.selectedIndex - path NaN', () {
580 var select = new SelectElement();
581 testDiv.append(select);
582 var option0 = select.append(new OptionElement());
583 var option1 = select.append(new OptionElement());
584 option1.selected = true;
585 var option2 = select.append(new OptionElement());
586
587 var model = toObservable({'val': 'foo'});
588
589 nodeBind(select).bind('selectedIndex', model, 'val');
590 performMicrotaskCheckpoint();
591 expect(select.selectedIndex, 0);
592 });
593
594 observeTest('Select.selectedIndex - path unreachable', () {
595 var select = new SelectElement();
596 testDiv.append(select);
597 var option0 = select.append(new OptionElement());
598 var option1 = select.append(new OptionElement());
599 option1.selected = true;
600 var option2 = select.append(new OptionElement());
601
602 var model = toObservable({});
603
604 nodeBind(select).bind('selectedIndex', model, 'val');
605 performMicrotaskCheckpoint();
606 expect(select.selectedIndex, 0);
607 });
608
609 observeTest('Option.value', () {
610 var option = testDiv.append(new OptionElement());
611 var model = toObservable({'x': 42});
612 nodeBind(option).bind('value', model, 'x');
613 expect(option.value, '42');
614
615 model['x'] = 'Hi';
616 expect(option.value, '42');
617 performMicrotaskCheckpoint();
618 expect(option.value, 'Hi');
619 });
620
621 observeTest('Select.value', () {
622 var select = testDiv.append(new SelectElement());
623 testDiv.append(select);
624 var option0 = select.append(new OptionElement());
625 var option1 = select.append(new OptionElement());
626 var option2 = select.append(new OptionElement());
627
628 var model = toObservable({
629 'opt0': 'a',
630 'opt1': 'b',
631 'opt2': 'c',
632 'selected': 'b'
633 });
634
635 nodeBind(option0).bind('value', model, 'opt0');
636 nodeBind(option1).bind('value', model, 'opt1');
637 nodeBind(option2).bind('value', model, 'opt2');
638
639 nodeBind(select).bind('value', model, 'selected');
640 performMicrotaskCheckpoint();
641 expect(select.value, 'b');
642
643 select.value = 'c';
644 dispatchEvent('change', select);
645 expect(model['selected'], 'c');
646
647 model['opt2'] = 'X';
648 performMicrotaskCheckpoint();
649 expect(select.value, 'X');
650 expect(model['selected'], 'X');
651
652 model['selected'] = 'a';
653 performMicrotaskCheckpoint();
654 expect(select.value, 'a');
655 });
656 }
657
658 privateField(x, name) => reflect(x).getField(
659 privateSymbol(reflect(x).type, name)).reflectee;
660
661 // TODO(jmesserly): fix this when it's easier to get a private symbol.
662 privateSymbol(TypeMirror type, String name) {
663 while (type != null) {
664 var symbol = type.variables.keys.firstWhere(
665 (s) => MirrorSystem.getName(s) == name, orElse: () => null);
666 if (symbol != null) return symbol;
667 type = type.superclass;
668 }
669 return null;
670 }
OLDNEW
« no previous file with comments | « pkg/template_binding/test/node_bind_test.dart ('k') | pkg/template_binding/test/template_binding_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698