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

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

Issue 335943003: merge to trunk all changes from 36817 until 37378 under the packages: polymer, (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
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
« no previous file with comments | « pkg/template_binding/test/node_bind_test.dart ('k') | pkg/template_binding/test/utils.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.template_binding_test; 5 library template_binding.test.template_binding_test;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:html'; 8 import 'dart:html';
9 import 'dart:js' show JsObject;
9 import 'dart:math' as math; 10 import 'dart:math' as math;
10 import 'package:observe/observe.dart'; 11 import 'package:observe/observe.dart';
11 import 'package:template_binding/template_binding.dart'; 12 import 'package:template_binding/template_binding.dart';
12 import 'package:unittest/html_config.dart'; 13 import 'package:unittest/html_config.dart';
13 import 'package:unittest/unittest.dart'; 14 import 'package:unittest/unittest.dart';
14 15
15 // TODO(jmesserly): merge this file? 16 // TODO(jmesserly): merge this file?
16 import 'binding_syntax.dart' show syntaxTests; 17 import 'binding_syntax.dart' show syntaxTests;
17 import 'utils.dart'; 18 import 'utils.dart';
18 19
19 // Note: this file ported from 20 // Note: this file ported from TemplateBinding's tests/tests.js
20 // https://github.com/Polymer/TemplateBinding/blob/fcb7a502794f19544f2d4b77c96ee bb70830591d/tests/tests.js
21 21
22 // TODO(jmesserly): submit a small cleanup patch to original. I fixed some 22 // TODO(jmesserly): submit a small cleanup patch to original. I fixed some
23 // cases where "div" and "t" were unintentionally using the JS global scope; 23 // cases where "div" and "t" were unintentionally using the JS global scope;
24 // look for "assertNodesAre". 24 // look for "assertNodesAre".
25 25
26 main() => dirtyCheckZone().run(() { 26 main() => dirtyCheckZone().run(() {
27 useHtmlConfiguration(); 27 useHtmlConfiguration();
28 28
29 // Load MutationObserver polyfill in case IE needs it. 29 // Load MutationObserver polyfill in case IE needs it.
30 var script = new ScriptElement() 30 var script = new ScriptElement()
31 ..src = '/root_dart/pkg/mutation_observer/lib/mutation_observer.min.js'; 31 ..src = '/root_dart/pkg/mutation_observer/lib/mutation_observer.min.js';
32 var polyfillLoaded = script.onLoad.first; 32 var polyfillLoaded = script.onLoad.first;
33 document.head.append(script); 33 document.head.append(script);
34 34
35 setUp(() => polyfillLoaded.then((_) { 35 setUp(() => polyfillLoaded.then((_) {
36 document.body.append(testDiv = new DivElement()); 36 document.body.append(testDiv = new DivElement());
37 })); 37 }));
38 38
39 tearDown(() { 39 tearDown(() {
40 testDiv.remove(); 40 testDiv.remove();
41 clearAllTemplates(testDiv);
41 testDiv = null; 42 testDiv = null;
42 }); 43 });
43 44
44 test('MutationObserver is supported', () { 45 test('MutationObserver is supported', () {
45 expect(MutationObserver.supported, true, reason: 'polyfill was loaded.'); 46 expect(MutationObserver.supported, true, reason: 'polyfill was loaded.');
46 }); 47 });
47 48
48 group('Template', templateInstantiationTests); 49 group('Template', templateInstantiationTests);
49 50
50 group('Binding Delegate API', () { 51 group('Binding Delegate API', () {
(...skipping 21 matching lines...) Expand all
72 expect(node, isNotNull); 73 expect(node, isNotNull);
73 while (node != null) { 74 while (node != null) {
74 expect(expando[node], node.text); 75 expect(expando[node], node.text);
75 node = node.nextNode; 76 node = node.nextNode;
76 } 77 }
77 } 78 }
78 79
79 templateInstantiationTests() { 80 templateInstantiationTests() {
80 // Dart note: renamed some of these tests to have unique names 81 // Dart note: renamed some of these tests to have unique names
81 82
82 test('Bind (simple)', () { 83 test('accessing bindingDelegate getter without Bind', () {
84 var div = createTestHtml('<template>');
85 var template = div.firstChild;
86 expect(templateBind(template).bindingDelegate, null);
87 });
88
89 test('Bind - simple', () {
83 var div = createTestHtml('<template bind={{}}>text</template>'); 90 var div = createTestHtml('<template bind={{}}>text</template>');
84 templateBind(div.firstChild).model = {}; 91 templateBind(div.firstChild).model = {};
85 return new Future(() { 92 return new Future(() {
86 expect(div.nodes.length, 2); 93 expect(div.nodes.length, 2);
87 expect(div.nodes.last.text, 'text'); 94 expect(div.nodes.last.text, 'text');
88 95
89 // Dart note: null is used instead of undefined to clear the template. 96 // Dart note: null is used instead of undefined to clear the template.
90 templateBind(div.firstChild).model = null; 97 templateBind(div.firstChild).model = null;
91 98
92 }).then(endOfMicrotask).then((_) { 99 }).then(endOfMicrotask).then((_) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 expect(template.nodes.length, 0); 132 expect(template.nodes.length, 0);
126 expect(template.nextNode, null); 133 expect(template.nextNode, null);
127 }); 134 });
128 }); 135 });
129 136
130 test('Bind - no defaultView', () { 137 test('Bind - no defaultView', () {
131 var div = createTestHtml('<template bind>text</template>'); 138 var div = createTestHtml('<template bind>text</template>');
132 var template = div.firstChild; 139 var template = div.firstChild;
133 var doc = document.implementation.createHtmlDocument(''); 140 var doc = document.implementation.createHtmlDocument('');
134 doc.adoptNode(div); 141 doc.adoptNode(div);
135 recursivelySetTemplateModel(template, {}); 142 templateBind(template).model = {};
136 return new Future(() => expect(div.nodes.length, 1)); 143 return new Future(() => expect(div.nodes.length, 2));
137 }); 144 });
138 145
139 test('Empty Bind', () { 146 test('Empty Bind', () {
140 var div = createTestHtml('<template bind>text</template>'); 147 var div = createTestHtml('<template bind>text</template>');
141 var template = div.firstChild; 148 var template = div.firstChild;
142 templateBind(template).model = {}; 149 templateBind(template).model = {};
143 return new Future(() { 150 return new Future(() {
144 expect(div.nodes.length, 2); 151 expect(div.nodes.length, 2);
145 expect(div.nodes.last.text, 'text'); 152 expect(div.nodes.last.text, 'text');
146 }); 153 });
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 templateBind(template).model = null; 356 templateBind(template).model = null;
350 357
351 }).then(endOfMicrotask).then((_) { 358 }).then(endOfMicrotask).then((_) {
352 expect(div.nodes.length, 1); 359 expect(div.nodes.length, 1);
353 }); 360 });
354 }); 361 });
355 362
356 test('Bind If, 2', () { 363 test('Bind If, 2', () {
357 var div = createTestHtml( 364 var div = createTestHtml(
358 '<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>'); 365 '<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>');
366 var template = div.firstChild;
359 var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } }); 367 var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } });
360 recursivelySetTemplateModel(div, m); 368 templateBind(template).model = m;
361 return new Future(() { 369 return new Future(() {
362 expect(div.nodes.length, 1); 370 expect(div.nodes.length, 1);
363 371
364 m['bar'] = 1; 372 m['bar'] = 1;
365 }).then(endOfMicrotask).then((_) { 373 }).then(endOfMicrotask).then((_) {
366 expect(div.nodes.length, 2); 374 expect(div.nodes.length, 2);
367 expect(div.lastChild.text, 'baz'); 375 expect(div.lastChild.text, 'baz');
368 }); 376 });
369 }); 377 });
370 378
(...skipping 13 matching lines...) Expand all
384 expect(div.lastChild.text, 'foo'); 392 expect(div.lastChild.text, 'foo');
385 393
386 templateBind(template).model = null; 394 templateBind(template).model = null;
387 }).then(endOfMicrotask).then((_) { 395 }).then(endOfMicrotask).then((_) {
388 expect(div.nodes.length, 1); 396 expect(div.nodes.length, 1);
389 }); 397 });
390 }); 398 });
391 399
392 test('Empty-If', () { 400 test('Empty-If', () {
393 var div = createTestHtml('<template if>{{ value }}</template>'); 401 var div = createTestHtml('<template if>{{ value }}</template>');
402 var template = div.firstChild;
394 var m = toObservable({ 'value': 'foo' }); 403 var m = toObservable({ 'value': 'foo' });
395 recursivelySetTemplateModel(div, null); 404 templateBind(template).model = null;
396 return new Future(() { 405 return new Future(() {
397 expect(div.nodes.length, 1); 406 expect(div.nodes.length, 1);
398 407
399 recursivelySetTemplateModel(div, m); 408 templateBind(template).model = m;
400 }).then(endOfMicrotask).then((_) { 409 }).then(endOfMicrotask).then((_) {
401 expect(div.nodes.length, 2); 410 expect(div.nodes.length, 2);
402 expect(div.lastChild.text, 'foo'); 411 expect(div.lastChild.text, 'foo');
403 }); 412 });
404 }); 413 });
405 414
406 test('OneTime - simple text', () { 415 test('OneTime - simple text', () {
407 var div = createTestHtml('<template bind>[[ value ]]</template>'); 416 var div = createTestHtml('<template bind>[[ value ]]</template>');
417 var template = div.firstChild;
408 var m = toObservable({ 'value': 'foo' }); 418 var m = toObservable({ 'value': 'foo' });
409 recursivelySetTemplateModel(div, m); 419 templateBind(template).model = m;
410 return new Future(() { 420 return new Future(() {
411 expect(div.nodes.length, 2); 421 expect(div.nodes.length, 2);
412 expect(div.lastChild.text, 'foo'); 422 expect(div.lastChild.text, 'foo');
413 423
414 m['value'] = 'bar'; 424 m['value'] = 'bar';
415 425
416 }).then(endOfMicrotask).then((_) { 426 }).then(endOfMicrotask).then((_) {
417 // unchanged. 427 // unchanged.
418 expect(div.lastChild.text, 'foo'); 428 expect(div.lastChild.text, 'foo');
419 }); 429 });
420 }); 430 });
421 431
422 test('OneTime - compound text', () { 432 test('OneTime - compound text', () {
423 var div = createTestHtml( 433 var div = createTestHtml(
424 '<template bind>[[ foo ]] bar [[ baz ]]</template>'); 434 '<template bind>[[ foo ]] bar [[ baz ]]</template>');
435 var template = div.firstChild;
425 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); 436 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' });
426 recursivelySetTemplateModel(div, m); 437 templateBind(template).model = m;
427 return new Future(() { 438 return new Future(() {
428 expect(div.nodes.length, 2); 439 expect(div.nodes.length, 2);
429 expect(div.lastChild.text, 'FOO bar BAZ'); 440 expect(div.lastChild.text, 'FOO bar BAZ');
430 441
431 m['foo'] = 'FI'; 442 m['foo'] = 'FI';
432 m['baz'] = 'BA'; 443 m['baz'] = 'BA';
433 444
434 }).then(endOfMicrotask).then((_) { 445 }).then(endOfMicrotask).then((_) {
435 // unchanged. 446 // unchanged.
436 expect(div.nodes.length, 2); 447 expect(div.nodes.length, 2);
437 expect(div.lastChild.text, 'FOO bar BAZ'); 448 expect(div.lastChild.text, 'FOO bar BAZ');
438 }); 449 });
439 }); 450 });
440 451
441 test('OneTime/Dynamic Mixed - compound text', () { 452 test('OneTime/Dynamic Mixed - compound text', () {
442 var div = createTestHtml( 453 var div = createTestHtml(
443 '<template bind>[[ foo ]] bar {{ baz }}</template>'); 454 '<template bind>[[ foo ]] bar {{ baz }}</template>');
455 var template = div.firstChild;
444 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); 456 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' });
445 recursivelySetTemplateModel(div, m); 457 templateBind(template).model = m;
446 return new Future(() { 458 return new Future(() {
447 expect(div.nodes.length, 2); 459 expect(div.nodes.length, 2);
448 expect(div.lastChild.text, 'FOO bar BAZ'); 460 expect(div.lastChild.text, 'FOO bar BAZ');
449 461
450 m['foo'] = 'FI'; 462 m['foo'] = 'FI';
451 m['baz'] = 'BA'; 463 m['baz'] = 'BA';
452 464
453 }).then(endOfMicrotask).then((_) { 465 }).then(endOfMicrotask).then((_) {
454 // unchanged [[ foo ]]. 466 // unchanged [[ foo ]].
455 expect(div.nodes.length, 2); 467 expect(div.nodes.length, 2);
456 expect(div.lastChild.text, 'FOO bar BA'); 468 expect(div.lastChild.text, 'FOO bar BA');
457 }); 469 });
458 }); 470 });
459 471
460 test('OneTime - simple attribute', () { 472 test('OneTime - simple attribute', () {
461 var div = createTestHtml( 473 var div = createTestHtml(
462 '<template bind><div foo="[[ value ]]"></div></template>'); 474 '<template bind><div foo="[[ value ]]"></div></template>');
475 var template = div.firstChild;
463 var m = toObservable({ 'value': 'foo' }); 476 var m = toObservable({ 'value': 'foo' });
464 recursivelySetTemplateModel(div, m); 477 templateBind(template).model = m;
465 return new Future(() { 478 return new Future(() {
466 expect(div.nodes.length, 2); 479 expect(div.nodes.length, 2);
467 expect(div.lastChild.attributes['foo'], 'foo'); 480 expect(div.lastChild.attributes['foo'], 'foo');
468 481
469 m['value'] = 'bar'; 482 m['value'] = 'bar';
470 483
471 }).then(endOfMicrotask).then((_) { 484 }).then(endOfMicrotask).then((_) {
472 // unchanged. 485 // unchanged.
473 expect(div.nodes.length, 2); 486 expect(div.nodes.length, 2);
474 expect(div.lastChild.attributes['foo'], 'foo'); 487 expect(div.lastChild.attributes['foo'], 'foo');
475 }); 488 });
476 }); 489 });
477 490
478 test('OneTime - compound attribute', () { 491 test('OneTime - compound attribute', () {
479 var div = createTestHtml( 492 var div = createTestHtml(
480 '<template bind>' 493 '<template bind>'
481 '<div foo="[[ value ]]:[[ otherValue ]]"></div>' 494 '<div foo="[[ value ]]:[[ otherValue ]]"></div>'
482 '</template>'); 495 '</template>');
496 var template = div.firstChild;
483 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); 497 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' });
484 recursivelySetTemplateModel(div, m); 498 templateBind(template).model = m;
485 return new Future(() { 499 return new Future(() {
486 expect(div.nodes.length, 2); 500 expect(div.nodes.length, 2);
487 expect(div.lastChild.attributes['foo'], 'foo:bar'); 501 expect(div.lastChild.attributes['foo'], 'foo:bar');
488 502
489 m['value'] = 'baz'; 503 m['value'] = 'baz';
490 m['otherValue'] = 'bot'; 504 m['otherValue'] = 'bot';
491 505
492 }).then(endOfMicrotask).then((_) { 506 }).then(endOfMicrotask).then((_) {
493 // unchanged. 507 // unchanged.
494 expect(div.lastChild.attributes['foo'], 'foo:bar'); 508 expect(div.lastChild.attributes['foo'], 'foo:bar');
495 }); 509 });
496 }); 510 });
497 511
498 test('OneTime/Dynamic mixed - compound attribute', () { 512 test('OneTime/Dynamic mixed - compound attribute', () {
499 var div = createTestHtml( 513 var div = createTestHtml(
500 '<template bind>' 514 '<template bind>'
501 '<div foo="{{ value }}:[[ otherValue ]]"></div>' 515 '<div foo="{{ value }}:[[ otherValue ]]"></div>'
502 '</template>'); 516 '</template>');
517 var template = div.firstChild;
503 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); 518 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' });
504 recursivelySetTemplateModel(div, m); 519 templateBind(template).model = m;
505 return new Future(() { 520 return new Future(() {
506 expect(div.nodes.length, 2); 521 expect(div.nodes.length, 2);
507 expect(div.lastChild.attributes['foo'], 'foo:bar'); 522 expect(div.lastChild.attributes['foo'], 'foo:bar');
508 523
509 m['value'] = 'baz'; 524 m['value'] = 'baz';
510 m['otherValue'] = 'bot'; 525 m['otherValue'] = 'bot';
511 526
512 }).then(endOfMicrotask).then((_) { 527 }).then(endOfMicrotask).then((_) {
513 // unchanged [[ otherValue ]]. 528 // unchanged [[ otherValue ]].
514 expect(div.lastChild.attributes['foo'], 'baz:bar'); 529 expect(div.lastChild.attributes['foo'], 'baz:bar');
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 expect(div.nodes[1].text, '1'); 700 expect(div.nodes[1].text, '1');
686 701
687 templateBind(template).model = null; 702 templateBind(template).model = null;
688 }).then(endOfMicrotask).then((_) { 703 }).then(endOfMicrotask).then((_) {
689 expect(div.nodes.length, 1); 704 expect(div.nodes.length, 1);
690 }); 705 });
691 }); 706 });
692 707
693 test('TextTemplateWithNullStringBinding', () { 708 test('TextTemplateWithNullStringBinding', () {
694 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>'); 709 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>');
710 var template = div.firstChild;
695 var model = toObservable({'b': 'B'}); 711 var model = toObservable({'b': 'B'});
696 recursivelySetTemplateModel(div, model); 712 templateBind(template).model = model;
697 713
698 return new Future(() { 714 return new Future(() {
699 expect(div.nodes.length, 2); 715 expect(div.nodes.length, 2);
700 expect(div.nodes.last.text, 'aBc'); 716 expect(div.nodes.last.text, 'aBc');
701 717
702 model['b'] = 'b'; 718 model['b'] = 'b';
703 }).then(endOfMicrotask).then((_) { 719 }).then(endOfMicrotask).then((_) {
704 expect(div.nodes.last.text, 'abc'); 720 expect(div.nodes.last.text, 'abc');
705 721
706 model['b'] = null; 722 model['b'] = null;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 756
741 model['data'] = null; 757 model['data'] = null;
742 }).then(endOfMicrotask).then((_) { 758 }).then(endOfMicrotask).then((_) {
743 expect(div.nodes.length, 1); 759 expect(div.nodes.length, 1);
744 }); 760 });
745 }); 761 });
746 762
747 test('TextTemplateWithBindingAndConditional', () { 763 test('TextTemplateWithBindingAndConditional', () {
748 var div = createTestHtml( 764 var div = createTestHtml(
749 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>'); 765 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>');
766 var template = div.firstChild;
750 var model = toObservable({'b': 'B', 'd': 1}); 767 var model = toObservable({'b': 'B', 'd': 1});
751 recursivelySetTemplateModel(div, model); 768 templateBind(template).model = model;
752 769
753 return new Future(() { 770 return new Future(() {
754 expect(div.nodes.length, 2); 771 expect(div.nodes.length, 2);
755 expect(div.nodes.last.text, 'aBc'); 772 expect(div.nodes.last.text, 'aBc');
756 773
757 model['b'] = 'b'; 774 model['b'] = 'b';
758 }).then(endOfMicrotask).then((_) { 775 }).then(endOfMicrotask).then((_) {
759 expect(div.nodes.last.text, 'abc'); 776 expect(div.nodes.last.text, 'abc');
760 777
761 // TODO(jmesserly): MDV set this to empty string and relies on JS conversi on 778 // TODO(jmesserly): MDV set this to empty string and relies on JS conversi on
762 // rules. Is that intended? 779 // rules. Is that intended?
763 // See https://github.com/Polymer/TemplateBinding/issues/59 780 // See https://github.com/Polymer/TemplateBinding/issues/59
764 model['d'] = null; 781 model['d'] = null;
765 }).then(endOfMicrotask).then((_) { 782 }).then(endOfMicrotask).then((_) {
766 expect(div.nodes.length, 1); 783 expect(div.nodes.length, 1);
767 784
768 model['d'] = 'here'; 785 model['d'] = 'here';
769 model['b'] = 'd'; 786 model['b'] = 'd';
770 787
771 }).then(endOfMicrotask).then((_) { 788 }).then(endOfMicrotask).then((_) {
772 expect(div.nodes.length, 2); 789 expect(div.nodes.length, 2);
773 expect(div.nodes.last.text, 'adc'); 790 expect(div.nodes.last.text, 'adc');
774 }); 791 });
775 }); 792 });
776 793
777 test('TemplateWithTextBinding2', () { 794 test('TemplateWithTextBinding2', () {
778 var div = createTestHtml( 795 var div = createTestHtml(
779 '<template bind="{{ b }}">a{{value}}c</template>'); 796 '<template bind="{{ b }}">a{{value}}c</template>');
780 expect(div.nodes.length, 1); 797 expect(div.nodes.length, 1);
798 var template = div.firstChild;
781 var model = toObservable({'b': {'value': 'B'}}); 799 var model = toObservable({'b': {'value': 'B'}});
782 recursivelySetTemplateModel(div, model); 800 templateBind(template).model = model;
783 801
784 return new Future(() { 802 return new Future(() {
785 expect(div.nodes.length, 2); 803 expect(div.nodes.length, 2);
786 expect(div.nodes.last.text, 'aBc'); 804 expect(div.nodes.last.text, 'aBc');
787 805
788 model['b'] = toObservable({'value': 'b'}); 806 model['b'] = toObservable({'value': 'b'});
789 }).then(endOfMicrotask).then((_) { 807 }).then(endOfMicrotask).then((_) {
790 expect(div.nodes.last.text, 'abc'); 808 expect(div.nodes.last.text, 'abc');
791 }); 809 });
792 }); 810 });
793 811
794 test('TemplateWithAttributeBinding', () { 812 test('TemplateWithAttributeBinding', () {
795 var div = createTestHtml( 813 var div = createTestHtml(
796 '<template bind="{{}}">' 814 '<template bind="{{}}">'
797 '<div foo="a{{b}}c"></div>' 815 '<div foo="a{{b}}c"></div>'
798 '</template>'); 816 '</template>');
817 var template = div.firstChild;
799 var model = toObservable({'b': 'B'}); 818 var model = toObservable({'b': 'B'});
800 recursivelySetTemplateModel(div, model); 819 templateBind(template).model = model;
801 820
802 return new Future(() { 821 return new Future(() {
803 expect(div.nodes.length, 2); 822 expect(div.nodes.length, 2);
804 expect(div.nodes.last.attributes['foo'], 'aBc'); 823 expect(div.nodes.last.attributes['foo'], 'aBc');
805 824
806 model['b'] = 'b'; 825 model['b'] = 'b';
807 }).then(endOfMicrotask).then((_) { 826 }).then(endOfMicrotask).then((_) {
808 expect(div.nodes.last.attributes['foo'], 'abc'); 827 expect(div.nodes.last.attributes['foo'], 'abc');
809 828
810 model['b'] = 'X'; 829 model['b'] = 'X';
811 }).then(endOfMicrotask).then((_) { 830 }).then(endOfMicrotask).then((_) {
812 expect(div.nodes.last.attributes['foo'], 'aXc'); 831 expect(div.nodes.last.attributes['foo'], 'aXc');
813 }); 832 });
814 }); 833 });
815 834
816 test('TemplateWithConditionalBinding', () { 835 test('TemplateWithConditionalBinding', () {
817 var div = createTestHtml( 836 var div = createTestHtml(
818 '<template bind="{{}}">' 837 '<template bind="{{}}">'
819 '<div foo?="{{b}}"></div>' 838 '<div foo?="{{b}}"></div>'
820 '</template>'); 839 '</template>');
840 var template = div.firstChild;
821 var model = toObservable({'b': 'b'}); 841 var model = toObservable({'b': 'b'});
822 recursivelySetTemplateModel(div, model); 842 templateBind(template).model = model;
823 843
824 return new Future(() { 844 return new Future(() {
825 expect(div.nodes.length, 2); 845 expect(div.nodes.length, 2);
826 expect(div.nodes.last.attributes['foo'], ''); 846 expect(div.nodes.last.attributes['foo'], '');
827 expect(div.nodes.last.attributes, isNot(contains('foo?'))); 847 expect(div.nodes.last.attributes, isNot(contains('foo?')));
828 848
829 model['b'] = null; 849 model['b'] = null;
830 }).then(endOfMicrotask).then((_) { 850 }).then(endOfMicrotask).then((_) {
831 expect(div.nodes.last.attributes, isNot(contains('foo'))); 851 expect(div.nodes.last.attributes, isNot(contains('foo')));
832 }); 852 });
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
908 test('Repeat - Reuse Instances', () { 928 test('Repeat - Reuse Instances', () {
909 var div = createTestHtml('<template repeat>{{ val }}</template>'); 929 var div = createTestHtml('<template repeat>{{ val }}</template>');
910 930
911 var model = toObservable([ 931 var model = toObservable([
912 {'val': 10}, 932 {'val': 10},
913 {'val': 5}, 933 {'val': 5},
914 {'val': 2}, 934 {'val': 2},
915 {'val': 8}, 935 {'val': 8},
916 {'val': 1} 936 {'val': 1}
917 ]); 937 ]);
918 recursivelySetTemplateModel(div, model);
919 var template = div.firstChild; 938 var template = div.firstChild;
939 templateBind(template).model = model;
920 940
921 return new Future(() { 941 return new Future(() {
922 expect(div.nodes.length, 6); 942 expect(div.nodes.length, 6);
923 943
924 addExpandos(template.nextNode); 944 addExpandos(template.nextNode);
925 checkExpandos(template.nextNode); 945 checkExpandos(template.nextNode);
926 946
927 model.sort((a, b) => a['val'] - b['val']); 947 model.sort((a, b) => a['val'] - b['val']);
928 }).then(endOfMicrotask).then((_) { 948 }).then(endOfMicrotask).then((_) {
929 checkExpandos(template.nextNode); 949 checkExpandos(template.nextNode);
930 950
931 model = toObservable(model.reversed); 951 model = toObservable(model.reversed);
932 recursivelySetTemplateModel(div, model); 952 templateBind(template).model = model;
933 }).then(endOfMicrotask).then((_) { 953 }).then(endOfMicrotask).then((_) {
934 checkExpandos(template.nextNode); 954 checkExpandos(template.nextNode);
935 955
936 for (var item in model) { 956 for (var item in model) {
937 item['val'] += 1; 957 item['val'] += 1;
938 } 958 }
939 959
940 }).then(endOfMicrotask).then((_) { 960 }).then(endOfMicrotask).then((_) {
941 expect(div.nodes[1].text, "11"); 961 expect(div.nodes[1].text, "11");
942 expect(div.nodes[2].text, "9"); 962 expect(div.nodes[2].text, "9");
943 expect(div.nodes[3].text, "6"); 963 expect(div.nodes[3].text, "6");
944 expect(div.nodes[4].text, "3"); 964 expect(div.nodes[4].text, "3");
945 expect(div.nodes[5].text, "2"); 965 expect(div.nodes[5].text, "2");
946 }); 966 });
947 }); 967 });
948 968
949 test('Bind - Reuse Instance', () { 969 test('Bind - Reuse Instance', () {
950 var div = createTestHtml( 970 var div = createTestHtml(
951 '<template bind="{{ foo }}">{{ bar }}</template>'); 971 '<template bind="{{ foo }}">{{ bar }}</template>');
952 972
973 var template = div.firstChild;
953 var model = toObservable({ 'foo': { 'bar': 5 }}); 974 var model = toObservable({ 'foo': { 'bar': 5 }});
954 recursivelySetTemplateModel(div, model); 975 templateBind(template).model = model;
955 var template = div.firstChild;
956 976
957 return new Future(() { 977 return new Future(() {
958 expect(div.nodes.length, 2); 978 expect(div.nodes.length, 2);
959 979
960 addExpandos(template.nextNode); 980 addExpandos(template.nextNode);
961 checkExpandos(template.nextNode); 981 checkExpandos(template.nextNode);
962 982
963 model = toObservable({'foo': model['foo']}); 983 model = toObservable({'foo': model['foo']});
964 recursivelySetTemplateModel(div, model); 984 templateBind(template).model = model;
965 }).then(endOfMicrotask).then((_) { 985 }).then(endOfMicrotask).then((_) {
966 checkExpandos(template.nextNode); 986 checkExpandos(template.nextNode);
967 }); 987 });
968 }); 988 });
969 989
970 test('Repeat-Empty', () { 990 test('Repeat-Empty', () {
971 var div = createTestHtml( 991 var div = createTestHtml(
972 '<template repeat>text</template>'); 992 '<template repeat>text</template>');
973 993
994 var template = div.firstChild;
974 var model = toObservable([0, 1, 2]); 995 var model = toObservable([0, 1, 2]);
975 recursivelySetTemplateModel(div, model); 996 templateBind(template).model = model;
976 997
977 return new Future(() { 998 return new Future(() {
978 expect(div.nodes.length, 4); 999 expect(div.nodes.length, 4);
979 1000
980 model.length = 1; 1001 model.length = 1;
981 }).then(endOfMicrotask).then((_) { 1002 }).then(endOfMicrotask).then((_) {
982 expect(div.nodes.length, 2); 1003 expect(div.nodes.length, 2);
983 1004
984 model.addAll(toObservable([3, 4])); 1005 model.addAll(toObservable([3, 4]));
985 }).then(endOfMicrotask).then((_) { 1006 }).then(endOfMicrotask).then((_) {
986 expect(div.nodes.length, 4); 1007 expect(div.nodes.length, 4);
987 1008
988 model.removeRange(1, 2); 1009 model.removeRange(1, 2);
989 }).then(endOfMicrotask).then((_) { 1010 }).then(endOfMicrotask).then((_) {
990 expect(div.nodes.length, 3); 1011 expect(div.nodes.length, 3);
991 }); 1012 });
992 }); 1013 });
993 1014
994 test('Removal from iteration needs to unbind', () { 1015 test('Removal from iteration needs to unbind', () {
995 var div = createTestHtml( 1016 var div = createTestHtml(
996 '<template repeat="{{}}"><a>{{v}}</a></template>'); 1017 '<template repeat="{{}}"><a>{{v}}</a></template>');
1018 var template = div.firstChild;
997 var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, 1019 var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3},
998 {'v': 4}]); 1020 {'v': 4}]);
999 recursivelySetTemplateModel(div, model); 1021 templateBind(template).model = model;
1000 1022
1001 var nodes, vs; 1023 var nodes, vs;
1002 return new Future(() { 1024 return new Future(() {
1003 1025
1004 nodes = div.nodes.skip(1).toList(); 1026 nodes = div.nodes.skip(1).toList();
1005 vs = model.toList(); 1027 vs = model.toList();
1006 1028
1007 for (var i = 0; i < 5; i++) { 1029 for (var i = 0; i < 5; i++) {
1008 expect(nodes[i].text, '$i'); 1030 expect(nodes[i].text, '$i');
1009 } 1031 }
1010 1032
1011 model.length = 3; 1033 model.length = 3;
1012 }).then(endOfMicrotask).then((_) { 1034 }).then(endOfMicrotask).then((_) {
1013 for (var i = 0; i < 5; i++) { 1035 for (var i = 0; i < 5; i++) {
1014 expect(nodes[i].text, '$i'); 1036 expect(nodes[i].text, '$i');
1015 } 1037 }
1016 1038
1017 vs[3]['v'] = 33; 1039 vs[3]['v'] = 33;
1018 vs[4]['v'] = 44; 1040 vs[4]['v'] = 44;
1019 }).then(endOfMicrotask).then((_) { 1041 }).then(endOfMicrotask).then((_) {
1020 for (var i = 0; i < 5; i++) { 1042 for (var i = 0; i < 5; i++) {
1021 expect(nodes[i].text, '$i'); 1043 expect(nodes[i].text, '$i');
1022 } 1044 }
1023 }); 1045 });
1024 }); 1046 });
1025 1047
1048 test('Template.clear', () {
1049 var div = createTestHtml(
1050 '<template repeat>{{}}</template>');
1051 var template = div.firstChild;
1052 templateBind(template).model = [0, 1, 2];
1053
1054 return new Future(() {
1055 expect(div.nodes.length, 4);
1056 expect(div.nodes[1].text, '0');
1057 expect(div.nodes[2].text, '1');
1058 expect(div.nodes[3].text, '2');
1059
1060 // clear() synchronously removes instances and clears the model.
1061 templateBind(div.firstChild).clear();
1062 expect(div.nodes.length, 1);
1063 expect(templateBind(template).model, null);
1064
1065 // test that template still works if new model assigned
1066 templateBind(template).model = [3, 4];
1067
1068 }).then(endOfMicrotask).then((_) {
1069 expect(div.nodes.length, 3);
1070 expect(div.nodes[1].text, '3');
1071 expect(div.nodes[2].text, '4');
1072 });
1073 });
1074
1026 test('DOM Stability on Iteration', () { 1075 test('DOM Stability on Iteration', () {
1027 var div = createTestHtml( 1076 var div = createTestHtml(
1028 '<template repeat="{{}}">{{}}</template>'); 1077 '<template repeat="{{}}">{{}}</template>');
1078 var template = div.firstChild;
1029 var model = toObservable([1, 2, 3, 4, 5]); 1079 var model = toObservable([1, 2, 3, 4, 5]);
1030 recursivelySetTemplateModel(div, model); 1080 templateBind(template).model = model;
1031 1081
1032 var nodes; 1082 var nodes;
1033 return new Future(() { 1083 return new Future(() {
1034 // Note: the node at index 0 is the <template>. 1084 // Note: the node at index 0 is the <template>.
1035 nodes = div.nodes.toList(); 1085 nodes = div.nodes.toList();
1036 expect(nodes.length, 6, reason: 'list has 5 items'); 1086 expect(nodes.length, 6, reason: 'list has 5 items');
1037 1087
1038 model.removeAt(0); 1088 model.removeAt(0);
1039 model.removeLast(); 1089 model.removeLast();
1040 1090
(...skipping 30 matching lines...) Expand all
1071 expect(identical(div.nodes[5], nodes[4]), true); 1121 expect(identical(div.nodes[5], nodes[4]), true);
1072 expect(identical(div.nodes[6], nodes[5]), true); 1122 expect(identical(div.nodes[6], nodes[5]), true);
1073 }); 1123 });
1074 }); 1124 });
1075 1125
1076 test('Repeat2', () { 1126 test('Repeat2', () {
1077 var div = createTestHtml( 1127 var div = createTestHtml(
1078 '<template repeat="{{}}">{{value}}</template>'); 1128 '<template repeat="{{}}">{{value}}</template>');
1079 expect(div.nodes.length, 1); 1129 expect(div.nodes.length, 1);
1080 1130
1131 var template = div.firstChild;
1081 var model = toObservable([ 1132 var model = toObservable([
1082 {'value': 0}, 1133 {'value': 0},
1083 {'value': 1}, 1134 {'value': 1},
1084 {'value': 2} 1135 {'value': 2}
1085 ]); 1136 ]);
1086 recursivelySetTemplateModel(div, model); 1137 templateBind(template).model = model;
1087 1138
1088 return new Future(() { 1139 return new Future(() {
1089 expect(div.nodes.length, 4); 1140 expect(div.nodes.length, 4);
1090 expect(div.nodes[1].text, '0'); 1141 expect(div.nodes[1].text, '0');
1091 expect(div.nodes[2].text, '1'); 1142 expect(div.nodes[2].text, '1');
1092 expect(div.nodes[3].text, '2'); 1143 expect(div.nodes[3].text, '2');
1093 1144
1094 model[1]['value'] = 'One'; 1145 model[1]['value'] = 'One';
1095 }).then(endOfMicrotask).then((_) { 1146 }).then(endOfMicrotask).then((_) {
1096 expect(div.nodes.length, 4); 1147 expect(div.nodes.length, 4);
1097 expect(div.nodes[1].text, '0'); 1148 expect(div.nodes[1].text, '0');
1098 expect(div.nodes[2].text, 'One'); 1149 expect(div.nodes[2].text, 'One');
1099 expect(div.nodes[3].text, '2'); 1150 expect(div.nodes[3].text, '2');
1100 1151
1101 model.replaceRange(0, 1, toObservable([{'value': 'Zero'}])); 1152 model.replaceRange(0, 1, toObservable([{'value': 'Zero'}]));
1102 }).then(endOfMicrotask).then((_) { 1153 }).then(endOfMicrotask).then((_) {
1103 expect(div.nodes.length, 4); 1154 expect(div.nodes.length, 4);
1104 expect(div.nodes[1].text, 'Zero'); 1155 expect(div.nodes[1].text, 'Zero');
1105 expect(div.nodes[2].text, 'One'); 1156 expect(div.nodes[2].text, 'One');
1106 expect(div.nodes[3].text, '2'); 1157 expect(div.nodes[3].text, '2');
1107 }); 1158 });
1108 }); 1159 });
1109 1160
1110 test('TemplateWithInputValue', () { 1161 test('TemplateWithInputValue', () {
1111 var div = createTestHtml( 1162 var div = createTestHtml(
1112 '<template bind="{{}}">' 1163 '<template bind="{{}}">'
1113 '<input value="{{x}}">' 1164 '<input value="{{x}}">'
1114 '</template>'); 1165 '</template>');
1166 var template = div.firstChild;
1115 var model = toObservable({'x': 'hi'}); 1167 var model = toObservable({'x': 'hi'});
1116 recursivelySetTemplateModel(div, model); 1168 templateBind(template).model = model;
1117 1169
1118 return new Future(() { 1170 return new Future(() {
1119 expect(div.nodes.length, 2); 1171 expect(div.nodes.length, 2);
1120 expect(div.nodes.last.value, 'hi'); 1172 expect(div.nodes.last.value, 'hi');
1121 1173
1122 model['x'] = 'bye'; 1174 model['x'] = 'bye';
1123 expect(div.nodes.last.value, 'hi'); 1175 expect(div.nodes.last.value, 'hi');
1124 }).then(endOfMicrotask).then((_) { 1176 }).then(endOfMicrotask).then((_) {
1125 expect(div.nodes.last.value, 'bye'); 1177 expect(div.nodes.last.value, 'bye');
1126 1178
1127 div.nodes.last.value = 'hello'; 1179 div.nodes.last.value = 'hello';
1128 dispatchEvent('input', div.nodes.last); 1180 dispatchEvent('input', div.nodes.last);
1129 expect(model['x'], 'hello'); 1181 expect(model['x'], 'hello');
1130 }).then(endOfMicrotask).then((_) { 1182 }).then(endOfMicrotask).then((_) {
1131 expect(div.nodes.last.value, 'hello'); 1183 expect(div.nodes.last.value, 'hello');
1132 }); 1184 });
1133 }); 1185 });
1134 1186
1135 ////////////////////////////////////////////////////////////////////////////// 1187 //////////////////////////////////////////////////////////////////////////////
1136 1188
1137 test('Decorated', () { 1189 test('Decorated', () {
1138 var div = createTestHtml( 1190 var div = createTestHtml(
1139 '<template bind="{{ XX }}" id="t1">' 1191 '<template bind="{{ XX }}" id="t1">'
1140 '<p>Crew member: {{name}}, Job title: {{title}}</p>' 1192 '<p>Crew member: {{name}}, Job title: {{title}}</p>'
1141 '</template>' 1193 '</template>'
1142 '<template bind="{{ XY }}" id="t2" ref="t1"></template>'); 1194 '<template bind="{{ XY }}" id="t2" ref="t1"></template>');
1143 1195
1196 var t1 = document.getElementById('t1');
1197 var t2 = document.getElementById('t2');
1144 var model = toObservable({ 1198 var model = toObservable({
1145 'XX': {'name': 'Leela', 'title': 'Captain'}, 1199 'XX': {'name': 'Leela', 'title': 'Captain'},
1146 'XY': {'name': 'Fry', 'title': 'Delivery boy'}, 1200 'XY': {'name': 'Fry', 'title': 'Delivery boy'},
1147 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'} 1201 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
1148 }); 1202 });
1149 recursivelySetTemplateModel(div, model); 1203 templateBind(t1).model = model;
1204 templateBind(t2).model = model;
1150 1205
1151 return new Future(() { 1206 return new Future(() {
1152 var t1 = document.getElementById('t1');
1153 var instance = t1.nextElementSibling; 1207 var instance = t1.nextElementSibling;
1154 expect(instance.text, 'Crew member: Leela, Job title: Captain'); 1208 expect(instance.text, 'Crew member: Leela, Job title: Captain');
1155 1209
1156 var t2 = document.getElementById('t2');
1157 instance = t2.nextElementSibling; 1210 instance = t2.nextElementSibling;
1158 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy'); 1211 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
1159 1212
1160 expect(div.children.length, 4); 1213 expect(div.children.length, 4);
1161 expect(div.nodes.length, 4); 1214 expect(div.nodes.length, 4);
1162 1215
1163 expect(div.nodes[1].tagName, 'P'); 1216 expect(div.nodes[1].tagName, 'P');
1164 expect(div.nodes[3].tagName, 'P'); 1217 expect(div.nodes[3].tagName, 'P');
1165 }); 1218 });
1166 }); 1219 });
1167 1220
1168 test('DefaultStyles', () { 1221 test('DefaultStyles', () {
1169 var t = new Element.tag('template'); 1222 var t = new Element.tag('template');
1170 TemplateBindExtension.decorate(t); 1223 TemplateBindExtension.decorate(t);
1171 1224
1172 document.body.append(t); 1225 document.body.append(t);
1173 expect(t.getComputedStyle().display, 'none'); 1226 expect(t.getComputedStyle().display, 'none');
1174 1227
1175 t.remove(); 1228 t.remove();
1176 }); 1229 });
1177 1230
1178 1231
1179 test('Bind', () { 1232 test('Bind', () {
1180 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>'); 1233 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>');
1234 var template = div.firstChild;
1181 var model = toObservable({'name': 'Leela'}); 1235 var model = toObservable({'name': 'Leela'});
1182 recursivelySetTemplateModel(div, model); 1236 templateBind(template).model = model;
1183 1237
1184 return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); 1238 return new Future(() => expect(div.nodes[1].text, 'Hi Leela'));
1185 }); 1239 });
1186 1240
1187 test('BindPlaceHolderHasNewLine', () { 1241 test('BindPlaceHolderHasNewLine', () {
1188 var div = createTestHtml( 1242 var div = createTestHtml(
1189 '<template bind="{{}}">Hi {{\nname\n}}</template>'); 1243 '<template bind="{{}}">Hi {{\nname\n}}</template>');
1244 var template = div.firstChild;
1190 var model = toObservable({'name': 'Leela'}); 1245 var model = toObservable({'name': 'Leela'});
1191 recursivelySetTemplateModel(div, model); 1246 templateBind(template).model = model;
1192 1247
1193 return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); 1248 return new Future(() => expect(div.nodes[1].text, 'Hi Leela'));
1194 }); 1249 });
1195 1250
1196 test('BindWithRef', () { 1251 test('BindWithRef', () {
1197 var id = 't${new math.Random().nextInt(100)}'; 1252 var id = 't${new math.Random().nextInt(100)}';
1198 var div = createTestHtml( 1253 var div = createTestHtml(
1199 '<template id="$id">' 1254 '<template id="$id">'
1200 'Hi {{ name }}' 1255 'Hi {{ name }}'
1201 '</template>' 1256 '</template>'
1202 '<template ref="$id" bind="{{}}"></template>'); 1257 '<template ref="$id" bind="{{}}"></template>');
1203 1258
1204 var t1 = div.nodes.first; 1259 var t1 = div.nodes.first;
1205 var t2 = div.nodes[1]; 1260 var t2 = div.nodes[1];
1206 1261
1207 expect(templateBind(t2).ref, t1);
1208
1209 var model = toObservable({'name': 'Fry'}); 1262 var model = toObservable({'name': 'Fry'});
1210 recursivelySetTemplateModel(div, model); 1263 templateBind(t1).model = model;
1264 templateBind(t2).model = model;
1211 1265
1212 return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); 1266 return new Future(() => expect(t2.nextNode.text, 'Hi Fry'));
1213 }); 1267 });
1214 1268
1269 test('Ref at multiple', () {
1270 // Note: this test is asserting that template "ref"erences can be located
1271 // at various points. In particular:
1272 // -in the document (at large) (e.g. ref=doc)
1273 // -within template content referenced from sub-content
1274 // -both before and after the reference
1275 // The following asserts ensure that all referenced templates content is
1276 // found.
1277 var div = createTestHtml(
1278 '<template bind>'
1279 '<template bind ref=doc></template>'
1280 '<template id=elRoot>EL_ROOT</template>'
1281 '<template bind>'
1282 '<template bind ref=elRoot></template>'
1283 '<template bind>'
1284 '<template bind ref=subA></template>'
1285 '<template id=subB>SUB_B</template>'
1286 '<template bind>'
1287 '<template bind ref=subB></template>'
1288 '</template>'
1289 '</template>'
1290 '<template id=subA>SUB_A</template>'
1291 '</template>'
1292 '</template>'
1293 '<template id=doc>DOC</template>');
1294 var t = div.firstChild;
1295 var fragment = templateBind(t).createInstance({});
1296 expect(fragment.nodes.length, 14);
1297 expect(fragment.nodes[1].text, 'DOC');
1298 expect(fragment.nodes[5].text, 'EL_ROOT');
1299 expect(fragment.nodes[8].text, 'SUB_A');
1300 expect(fragment.nodes[12].text, 'SUB_B');
1301 div.append(fragment);
1302 });
1215 1303
1216 test('Update Ref', () { 1304 test('Update Ref', () {
1305 // Updating ref by observing the attribute is dependent on MutationObserver
1217 var div = createTestHtml( 1306 var div = createTestHtml(
1218 '<template id=A>Hi, {{}}</template>' 1307 '<template id=A>Hi, {{}}</template>'
1219 '<template id=B>Hola, {{}}</template>' 1308 '<template id=B>Hola, {{}}</template>'
1220 '<template ref=A repeat></template>'); 1309 '<template ref=A repeat></template>');
1221 1310
1311 var template = div.nodes[2];
1222 var model = new ObservableList.from(['Fry']); 1312 var model = new ObservableList.from(['Fry']);
1223 recursivelySetTemplateModel(div, model); 1313 templateBind(template).model = model;
1224 1314
1225 return new Future(() { 1315 return new Future(() {
1226 expect(div.nodes.length, 4); 1316 expect(div.nodes.length, 4);
1227 expect('Hi, Fry', div.nodes[3].text); 1317 expect('Hi, Fry', div.nodes[3].text);
1228 1318
1229 div.nodes[2].attributes['ref'] = 'B'; 1319 div.nodes[2].attributes['ref'] = 'B';
1230 model.add('Leela'); 1320 model.add('Leela');
1231 1321
1322 }).then(nextMicrotask).then((x) {
1323 expect(div.nodes.length, 5);
1324
1325 expect('Hola, Fry', div.nodes[3].text);
1326 expect('Hola, Leela', div.nodes[4].text);
1327 });
1328 });
1329
1330 test('Bound Ref', () {
1331 var div = createTestHtml(
1332 '<template id=A>Hi, {{}}</template>'
1333 '<template id=B>Hola, {{}}</template>'
1334 '<template ref="{{ ref }}" repeat="{{ people }}"></template>');
1335
1336 var template = div.nodes[2];
1337 var model = toObservable({'ref': 'A', 'people': ['Fry']});
1338 templateBind(template).model = model;
1339
1340 return new Future(() {
1341 expect(div.nodes.length, 4);
1342 expect('Hi, Fry', div.nodes[3].text);
1343
1344 model['ref'] = 'B';
1345 model['people'].add('Leela');
1346
1232 }).then(endOfMicrotask).then((x) { 1347 }).then(endOfMicrotask).then((x) {
1233 expect(div.nodes.length, 5); 1348 expect(div.nodes.length, 5);
1234 1349
1235 expect('Hi, Fry', div.nodes[3].text); 1350 expect('Hola, Fry', div.nodes[3].text);
1236 expect('Hola, Leela', div.nodes[4].text); 1351 expect('Hola, Leela', div.nodes[4].text);
1237 }); 1352 });
1238 }); 1353 });
1239 1354
1240 test('BindWithDynamicRef', () { 1355 test('BindWithDynamicRef', () {
1241 var id = 't${new math.Random().nextInt(100)}'; 1356 var id = 't${new math.Random().nextInt(100)}';
1242 var div = createTestHtml( 1357 var div = createTestHtml(
1243 '<template id="$id">' 1358 '<template id="$id">'
1244 'Hi {{ name }}' 1359 'Hi {{ name }}'
1245 '</template>' 1360 '</template>'
1246 '<template ref="{{ id }}" bind="{{}}"></template>'); 1361 '<template ref="{{ id }}" bind="{{}}"></template>');
1247 1362
1248 var t1 = div.firstChild; 1363 var t1 = div.firstChild;
1249 var t2 = div.nodes[1]; 1364 var t2 = div.nodes[1];
1250 var model = toObservable({'name': 'Fry', 'id': id }); 1365 var model = toObservable({'name': 'Fry', 'id': id });
1251 recursivelySetTemplateModel(div, model); 1366 templateBind(t1).model = model;
1367 templateBind(t2).model = model;
1252 1368
1253 return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); 1369 return new Future(() => expect(t2.nextNode.text, 'Hi Fry'));
1254 }); 1370 });
1255 1371
1256 assertNodesAre(div, [arguments]) { 1372 assertNodesAre(div, [arguments]) {
1257 var expectedLength = arguments.length; 1373 var expectedLength = arguments.length;
1258 expect(div.nodes.length, expectedLength + 1); 1374 expect(div.nodes.length, expectedLength + 1);
1259 1375
1260 for (var i = 0; i < arguments.length; i++) { 1376 for (var i = 0; i < arguments.length; i++) {
1261 var targetNode = div.nodes[i + 1]; 1377 var targetNode = div.nodes[i + 1];
1262 expect(targetNode.text, arguments[i]); 1378 expect(targetNode.text, arguments[i]);
1263 } 1379 }
1264 } 1380 }
1265 1381
1266 test('Repeat3', () { 1382 test('Repeat3', () {
1267 var div = createTestHtml( 1383 var div = createTestHtml(
1268 '<template repeat="{{ contacts }}">Hi {{ name }}</template>'); 1384 '<template repeat="{{ contacts }}">Hi {{ name }}</template>');
1269 var t = div.nodes.first; 1385 var t = div.nodes.first;
1270 1386
1271 var m = toObservable({ 1387 var m = toObservable({
1272 'contacts': [ 1388 'contacts': [
1273 {'name': 'Raf'}, 1389 {'name': 'Raf'},
1274 {'name': 'Arv'}, 1390 {'name': 'Arv'},
1275 {'name': 'Neal'} 1391 {'name': 'Neal'}
1276 ] 1392 ]
1277 }); 1393 });
1278 1394
1279 recursivelySetTemplateModel(div, m); 1395 templateBind(t).model = m;
1280 return new Future(() { 1396 return new Future(() {
1281 1397
1282 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 1398 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
1283 1399
1284 m['contacts'].add(toObservable({'name': 'Alex'})); 1400 m['contacts'].add(toObservable({'name': 'Alex'}));
1285 }).then(endOfMicrotask).then((_) { 1401 }).then(endOfMicrotask).then((_) {
1286 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); 1402 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
1287 1403
1288 m['contacts'].replaceRange(0, 2, 1404 m['contacts'].replaceRange(0, 2,
1289 toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); 1405 toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
(...skipping 23 matching lines...) Expand all
1313 }).then(endOfMicrotask).then((_) { 1429 }).then(endOfMicrotask).then((_) {
1314 assertNodesAre(div, []); 1430 assertNodesAre(div, []);
1315 }); 1431 });
1316 }); 1432 });
1317 1433
1318 test('RepeatModelSet', () { 1434 test('RepeatModelSet', () {
1319 var div = createTestHtml( 1435 var div = createTestHtml(
1320 '<template repeat="{{ contacts }}">' 1436 '<template repeat="{{ contacts }}">'
1321 'Hi {{ name }}' 1437 'Hi {{ name }}'
1322 '</template>'); 1438 '</template>');
1439 var template = div.firstChild;
1323 var m = toObservable({ 1440 var m = toObservable({
1324 'contacts': [ 1441 'contacts': [
1325 {'name': 'Raf'}, 1442 {'name': 'Raf'},
1326 {'name': 'Arv'}, 1443 {'name': 'Arv'},
1327 {'name': 'Neal'} 1444 {'name': 'Neal'}
1328 ] 1445 ]
1329 }); 1446 });
1330 recursivelySetTemplateModel(div, m); 1447 templateBind(template).model = m;
1331 return new Future(() { 1448 return new Future(() {
1332 var t = div.nodes.first;
1333 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 1449 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
1334 }); 1450 });
1335 }); 1451 });
1336 1452
1337 test('RepeatEmptyPath', () { 1453 test('RepeatEmptyPath', () {
1338 var div = createTestHtml( 1454 var div = createTestHtml(
1339 '<template repeat="{{}}">Hi {{ name }}</template>'); 1455 '<template repeat="{{}}">Hi {{ name }}</template>');
1340 var t = div.nodes.first; 1456 var t = div.nodes.first;
1341 1457
1342 var m = toObservable([ 1458 var m = toObservable([
1343 {'name': 'Raf'}, 1459 {'name': 'Raf'},
1344 {'name': 'Arv'}, 1460 {'name': 'Arv'},
1345 {'name': 'Neal'} 1461 {'name': 'Neal'}
1346 ]); 1462 ]);
1347 recursivelySetTemplateModel(div, m); 1463 templateBind(t).model = m;
1348 return new Future(() { 1464 return new Future(() {
1349 1465
1350 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 1466 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
1351 1467
1352 m.add(toObservable({'name': 'Alex'})); 1468 m.add(toObservable({'name': 'Alex'}));
1353 }).then(endOfMicrotask).then((_) { 1469 }).then(endOfMicrotask).then((_) {
1354 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); 1470 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
1355 1471
1356 m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])) ; 1472 m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])) ;
1357 }).then(endOfMicrotask).then((_) { 1473 }).then(endOfMicrotask).then((_) {
(...skipping 18 matching lines...) Expand all
1376 assertNodesAre(div, ['Hi Alex']); 1492 assertNodesAre(div, ['Hi Alex']);
1377 }); 1493 });
1378 }); 1494 });
1379 1495
1380 test('RepeatNullModel', () { 1496 test('RepeatNullModel', () {
1381 var div = createTestHtml( 1497 var div = createTestHtml(
1382 '<template repeat="{{}}">Hi {{ name }}</template>'); 1498 '<template repeat="{{}}">Hi {{ name }}</template>');
1383 var t = div.nodes.first; 1499 var t = div.nodes.first;
1384 1500
1385 var m = null; 1501 var m = null;
1386 recursivelySetTemplateModel(div, m); 1502 templateBind(t).model = m;
1387 1503
1388 expect(div.nodes.length, 1); 1504 expect(div.nodes.length, 1);
1389 1505
1390 t.attributes['iterate'] = ''; 1506 t.attributes['iterate'] = '';
1391 m = toObservable({}); 1507 m = toObservable({});
1392 recursivelySetTemplateModel(div, m); 1508 templateBind(t).model = m;
1393 return new Future(() => expect(div.nodes.length, 1)); 1509 return new Future(() => expect(div.nodes.length, 1));
1394 }); 1510 });
1395 1511
1396 test('RepeatReuse', () { 1512 test('RepeatReuse', () {
1397 var div = createTestHtml( 1513 var div = createTestHtml(
1398 '<template repeat="{{}}">Hi {{ name }}</template>'); 1514 '<template repeat="{{}}">Hi {{ name }}</template>');
1399 var t = div.nodes.first; 1515 var t = div.nodes.first;
1400 1516
1401 var m = toObservable([ 1517 var m = toObservable([
1402 {'name': 'Raf'}, 1518 {'name': 'Raf'},
1403 {'name': 'Arv'}, 1519 {'name': 'Arv'},
1404 {'name': 'Neal'} 1520 {'name': 'Neal'}
1405 ]); 1521 ]);
1406 recursivelySetTemplateModel(div, m); 1522 templateBind(t).model = m;
1407 1523
1408 var node1, node2, node3; 1524 var node1, node2, node3;
1409 return new Future(() { 1525 return new Future(() {
1410 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 1526 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
1411 node1 = div.nodes[1]; 1527 node1 = div.nodes[1];
1412 node2 = div.nodes[2]; 1528 node2 = div.nodes[2];
1413 node3 = div.nodes[3]; 1529 node3 = div.nodes[3];
1414 1530
1415 m.replaceRange(1, 2, toObservable([{'name': 'Erik'}])); 1531 m.replaceRange(1, 2, toObservable([{'name': 'Erik'}]));
1416 }).then(endOfMicrotask).then((_) { 1532 }).then(endOfMicrotask).then((_) {
1417 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']); 1533 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
1418 expect(div.nodes[1], node1, 1534 expect(div.nodes[1], node1,
1419 reason: 'model[0] did not change so the node should not have changed') ; 1535 reason: 'model[0] did not change so the node should not have changed') ;
1420 expect(div.nodes[2], isNot(equals(node2)), 1536 expect(div.nodes[2], isNot(equals(node2)),
1421 reason: 'Should not reuse when replacing'); 1537 reason: 'Should not reuse when replacing');
1422 expect(div.nodes[3], node3, 1538 expect(div.nodes[3], node3,
1423 reason: 'model[2] did not change so the node should not have changed') ; 1539 reason: 'model[2] did not change so the node should not have changed') ;
1424 1540
1425 node2 = div.nodes[2]; 1541 node2 = div.nodes[2];
1426 m.insert(0, toObservable({'name': 'Alex'})); 1542 m.insert(0, toObservable({'name': 'Alex'}));
1427 }).then(endOfMicrotask).then((_) { 1543 }).then(endOfMicrotask).then((_) {
1428 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']); 1544 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
1429 }); 1545 });
1430 }); 1546 });
1431 1547
1432 test('TwoLevelsDeepBug', () { 1548 test('TwoLevelsDeepBug', () {
1433 var div = createTestHtml( 1549 var div = createTestHtml(
1434 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>'); 1550 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>');
1435 1551 var template = div.firstChild;
1436 var model = toObservable({'foo': 'bar'}); 1552 var model = toObservable({'foo': 'bar'});
1437 recursivelySetTemplateModel(div, model); 1553 templateBind(template).model = model;
1438 return new Future(() { 1554 return new Future(() {
1439 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar'); 1555 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
1440 }); 1556 });
1441 }); 1557 });
1442 1558
1443 test('Checked', () { 1559 test('Checked', () {
1444 var div = createTestHtml( 1560 var div = createTestHtml(
1445 '<template bind>' 1561 '<template bind>'
1446 '<input type="checkbox" checked="{{a}}">' 1562 '<input type="checkbox" checked="{{a}}">'
1447 '</template>'); 1563 '</template>');
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1595 expect(div.nodes[i++].tagName, 'TEMPLATE');
1480 expect(div.nodes[i++].text, '2'); 1596 expect(div.nodes[i++].text, '2');
1481 1597
1482 m['a']['b'] = 11; 1598 m['a']['b'] = 11;
1483 }).then(endOfMicrotask).then((_) { 1599 }).then(endOfMicrotask).then((_) {
1484 expect(div.nodes[start].text, '11'); 1600 expect(div.nodes[start].text, '11');
1485 1601
1486 m['a']['c'] = toObservable({'d': 22}); 1602 m['a']['c'] = toObservable({'d': 22});
1487 }).then(endOfMicrotask).then((_) { 1603 }).then(endOfMicrotask).then((_) {
1488 expect(div.nodes[start + 2].text, '22'); 1604 expect(div.nodes[start + 2].text, '22');
1605
1606 //clearAllTemplates(div);
1489 }); 1607 });
1490 } 1608 }
1491 1609
1492 test('Nested', () => nestedHelper( 1610 test('Nested', () => nestedHelper(
1493 '<template bind="{{a}}">' 1611 '<template bind="{{a}}">'
1494 '{{b}}' 1612 '{{b}}'
1495 '<template bind="{{c}}">' 1613 '<template bind="{{c}}">'
1496 '{{d}}' 1614 '{{d}}'
1497 '</template>' 1615 '</template>'
1498 '</template>', 1)); 1616 '</template>', 1));
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1619 '<template ref="inner" repeat="{{c}}"></template>' 1737 '<template ref="inner" repeat="{{c}}"></template>'
1620 '</template>', 2)); 1738 '</template>', 2));
1621 1739
1622 test('NestedRepeatSelfRef', () { 1740 test('NestedRepeatSelfRef', () {
1623 var div = createTestHtml( 1741 var div = createTestHtml(
1624 '<template id="t" repeat="{{}}">' 1742 '<template id="t" repeat="{{}}">'
1625 '{{name}}' 1743 '{{name}}'
1626 '<template ref="t" repeat="{{items}}"></template>' 1744 '<template ref="t" repeat="{{items}}"></template>'
1627 '</template>'); 1745 '</template>');
1628 1746
1747 var template = div.firstChild;
1748
1629 var m = toObservable([ 1749 var m = toObservable([
1630 { 1750 {
1631 'name': 'Item 1', 1751 'name': 'Item 1',
1632 'items': [ 1752 'items': [
1633 { 1753 {
1634 'name': 'Item 1.1', 1754 'name': 'Item 1.1',
1635 'items': [ 1755 'items': [
1636 { 1756 {
1637 'name': 'Item 1.1.1', 1757 'name': 'Item 1.1.1',
1638 'items': [] 1758 'items': []
1639 } 1759 }
1640 ] 1760 ]
1641 }, 1761 },
1642 { 1762 {
1643 'name': 'Item 1.2' 1763 'name': 'Item 1.2'
1644 } 1764 }
1645 ] 1765 ]
1646 }, 1766 },
1647 { 1767 {
1648 'name': 'Item 2', 1768 'name': 'Item 2',
1649 'items': [] 1769 'items': []
1650 }, 1770 },
1651 ]); 1771 ]);
1652 1772
1653 recursivelySetTemplateModel(div, m); 1773 templateBind(template).model = m;
1654 1774
1655 int i = 1; 1775 int i = 1;
1656 return new Future(() { 1776 return new Future(() {
1657 expect(div.nodes[i++].text, 'Item 1'); 1777 expect(div.nodes[i++].text, 'Item 1');
1658 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1778 expect(div.nodes[i++].tagName, 'TEMPLATE');
1659 expect(div.nodes[i++].text, 'Item 1.1'); 1779 expect(div.nodes[i++].text, 'Item 1.1');
1660 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1780 expect(div.nodes[i++].tagName, 'TEMPLATE');
1661 expect(div.nodes[i++].text, 'Item 1.1.1'); 1781 expect(div.nodes[i++].text, 'Item 1.1.1');
1662 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1782 expect(div.nodes[i++].tagName, 'TEMPLATE');
1663 expect(div.nodes[i++].text, 'Item 1.2'); 1783 expect(div.nodes[i++].text, 'Item 1.2');
(...skipping 15 matching lines...) Expand all
1679 test('Attribute Template Option/Optgroup', () { 1799 test('Attribute Template Option/Optgroup', () {
1680 var div = createTestHtml( 1800 var div = createTestHtml(
1681 '<template bind>' 1801 '<template bind>'
1682 '<select selectedIndex="{{ selected }}">' 1802 '<select selectedIndex="{{ selected }}">'
1683 '<optgroup template repeat="{{ groups }}" label="{{ name }}">' 1803 '<optgroup template repeat="{{ groups }}" label="{{ name }}">'
1684 '<option template repeat="{{ items }}">{{ val }}</option>' 1804 '<option template repeat="{{ items }}">{{ val }}</option>'
1685 '</optgroup>' 1805 '</optgroup>'
1686 '</select>' 1806 '</select>'
1687 '</template>'); 1807 '</template>');
1688 1808
1809 var template = div.firstChild;
1689 var m = toObservable({ 1810 var m = toObservable({
1690 'selected': 1, 1811 'selected': 1,
1691 'groups': [{ 1812 'groups': [{
1692 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }] 1813 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }]
1693 }], 1814 }],
1694 }); 1815 });
1695 1816
1696 recursivelySetTemplateModel(div, m); 1817 templateBind(template).model = m;
1697 1818
1698 var completer = new Completer(); 1819 var completer = new Completer();
1699 1820
1700 new MutationObserver((records, observer) { 1821 new MutationObserver((records, observer) {
1701 var select = div.nodes[0].nextNode; 1822 var select = div.nodes[0].nextNode;
1702 if (select == null || select.querySelector('option') == null) return; 1823 if (select == null || select.querySelector('option') == null) return;
1703 1824
1704 observer.disconnect(); 1825 observer.disconnect();
1705 new Future(() { 1826 new Future(() {
1706 expect(select.nodes.length, 2); 1827 expect(select.nodes.length, 2);
1707 1828
1708 expect(select.selectedIndex, 1, reason: 'selected index should update ' 1829 expect(select.selectedIndex, 1, reason: 'selected index should update '
1709 'after template expands.'); 1830 'after template expands.');
1710 1831
1711 expect(select.nodes[0].tagName, 'TEMPLATE'); 1832 expect(select.nodes[0].tagName, 'TEMPLATE');
1712 expect((templateBind(templateBind(select.nodes[0]).ref)
1713 .content.nodes[0] as Element).tagName, 'OPTGROUP');
1714
1715 var optgroup = select.nodes[1]; 1833 var optgroup = select.nodes[1];
1716 expect(optgroup.nodes[0].tagName, 'TEMPLATE'); 1834 expect(optgroup.nodes[0].tagName, 'TEMPLATE');
1717 expect(optgroup.nodes[1].tagName, 'OPTION'); 1835 expect(optgroup.nodes[1].tagName, 'OPTION');
1718 expect(optgroup.nodes[1].text, '0'); 1836 expect(optgroup.nodes[1].text, '0');
1719 expect(optgroup.nodes[2].tagName, 'OPTION'); 1837 expect(optgroup.nodes[2].tagName, 'OPTION');
1720 expect(optgroup.nodes[2].text, '1'); 1838 expect(optgroup.nodes[2].text, '1');
1721 1839
1722 completer.complete(); 1840 completer.complete();
1723 }); 1841 });
1724 })..observe(div, childList: true, subtree: true); 1842 })..observe(div, childList: true, subtree: true);
1725 1843
1726 Observable.dirtyCheck(); 1844 Observable.dirtyCheck();
1727 1845
1728 return completer.future; 1846 return completer.future;
1729 }); 1847 });
1730 1848
1731 test('NestedIterateTableMixedSemanticNative', () { 1849 test('NestedIterateTableMixedSemanticNative', () {
1732 if (!parserHasNativeTemplate) return null; 1850 if (!parserHasNativeTemplate) return null;
1733 1851
1734 var div = createTestHtml( 1852 var div = createTestHtml(
1735 '<table><tbody>' 1853 '<table><tbody>'
1736 '<template repeat="{{}}">' 1854 '<template repeat="{{}}">'
1737 '<tr>' 1855 '<tr>'
1738 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' 1856 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>'
1739 '</tr>' 1857 '</tr>'
1740 '</template>' 1858 '</template>'
1741 '</tbody></table>'); 1859 '</tbody></table>');
1860 var template = div.firstChild.firstChild.firstChild;
1742 1861
1743 var m = toObservable([ 1862 var m = toObservable([
1744 [{ 'val': 0 }, { 'val': 1 }], 1863 [{ 'val': 0 }, { 'val': 1 }],
1745 [{ 'val': 2 }, { 'val': 3 }] 1864 [{ 'val': 2 }, { 'val': 3 }]
1746 ]); 1865 ]);
1747 1866
1748 recursivelySetTemplateModel(div, m); 1867 templateBind(template).model = m;
1749 return new Future(() { 1868 return new Future(() {
1750 var tbody = div.nodes[0].nodes[0]; 1869 var tbody = div.nodes[0].nodes[0];
1751 1870
1752 // 1 for the <tr template>, 2 * (1 tr) 1871 // 1 for the <tr template>, 2 * (1 tr)
1753 expect(tbody.nodes.length, 3); 1872 expect(tbody.nodes.length, 3);
1754 1873
1755 // 1 for the <td template>, 2 * (1 td) 1874 // 1 for the <td template>, 2 * (1 td)
1756 expect(tbody.nodes[1].nodes.length, 3); 1875 expect(tbody.nodes[1].nodes.length, 3);
1757 1876
1758 expect(tbody.nodes[1].nodes[1].text, '0'); 1877 expect(tbody.nodes[1].nodes[1].text, '0');
(...skipping 10 matching lines...) Expand all
1769 }); 1888 });
1770 }); 1889 });
1771 1890
1772 test('NestedIterateTable', () { 1891 test('NestedIterateTable', () {
1773 var div = createTestHtml( 1892 var div = createTestHtml(
1774 '<table><tbody>' 1893 '<table><tbody>'
1775 '<tr template repeat="{{}}">' 1894 '<tr template repeat="{{}}">'
1776 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' 1895 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>'
1777 '</tr>' 1896 '</tr>'
1778 '</tbody></table>'); 1897 '</tbody></table>');
1898 var template = div.firstChild.firstChild.firstChild;
1779 1899
1780 var m = toObservable([ 1900 var m = toObservable([
1781 [{ 'val': 0 }, { 'val': 1 }], 1901 [{ 'val': 0 }, { 'val': 1 }],
1782 [{ 'val': 2 }, { 'val': 3 }] 1902 [{ 'val': 2 }, { 'val': 3 }]
1783 ]); 1903 ]);
1784 1904
1785 recursivelySetTemplateModel(div, m); 1905 templateBind(template).model = m;
1786 return new Future(() { 1906 return new Future(() {
1787 1907
1788 var i = 1; 1908 var i = 1;
1789 var tbody = div.nodes[0].nodes[0]; 1909 var tbody = div.nodes[0].nodes[0];
1790 1910
1791 // 1 for the <tr template>, 2 * (1 tr) 1911 // 1 for the <tr template>, 2 * (1 tr)
1792 expect(tbody.nodes.length, 3); 1912 expect(tbody.nodes.length, 3);
1793 1913
1794 // 1 for the <td template>, 2 * (1 td) 1914 // 1 for the <td template>, 2 * (1 td)
1795 expect(tbody.nodes[1].nodes.length, 3); 1915 expect(tbody.nodes[1].nodes.length, 3);
(...skipping 10 matching lines...) Expand all
1806 expect(tbody.nodes[2].nodes[2].attributes['class'], '3'); 1926 expect(tbody.nodes[2].nodes[2].attributes['class'], '3');
1807 }); 1927 });
1808 }); 1928 });
1809 1929
1810 test('NestedRepeatDeletionOfMultipleSubTemplates', () { 1930 test('NestedRepeatDeletionOfMultipleSubTemplates', () {
1811 var div = createTestHtml( 1931 var div = createTestHtml(
1812 '<ul>' 1932 '<ul>'
1813 '<template repeat="{{}}" id=t1>' 1933 '<template repeat="{{}}" id=t1>'
1814 '<li>{{name}}' 1934 '<li>{{name}}'
1815 '<ul>' 1935 '<ul>'
1816 '<template ref=t1 repaet="{{items}}"></template>' 1936 '<template ref=t1 repeat="{{items}}"></template>'
1817 '</ul>' 1937 '</ul>'
1818 '</li>' 1938 '</li>'
1819 '</template>' 1939 '</template>'
1820 '</ul>'); 1940 '</ul>');
1821 1941
1822 var m = toObservable([ 1942 var m = toObservable([
1823 { 1943 {
1824 'name': 'Item 1', 1944 'name': 'Item 1',
1825 'items': [ 1945 'items': [
1826 { 1946 {
1827 'name': 'Item 1.1' 1947 'name': 'Item 1.1'
1828 } 1948 }
1829 ] 1949 ]
1830 } 1950 }
1831 ]); 1951 ]);
1952 var ul = div.firstChild;
1953 var t = ul.firstChild;
1832 1954
1833 recursivelySetTemplateModel(div, m); 1955 templateBind(t).model = m;
1834 return new Future(() => m.removeAt(0)); 1956 return new Future(() {
1957 expect(ul.nodes.length, 2);
1958 var ul2 = ul.nodes[1].nodes[1];
1959 expect(ul2.nodes.length, 2);
1960 var ul3 = ul2.nodes[1].nodes[1];
1961 expect(ul3.nodes.length, 1);
1962
1963 m.removeAt(0);
1964 }).then(endOfMicrotask).then((_) {
1965 expect(ul.nodes.length, 1);
1966 });
1835 }); 1967 });
1836 1968
1837 test('DeepNested', () { 1969 test('DeepNested', () {
1838 var div = createTestHtml( 1970 var div = createTestHtml(
1839 '<template bind="{{a}}">' 1971 '<template bind="{{a}}">'
1840 '<p>' 1972 '<p>'
1841 '<template bind="{{b}}">' 1973 '<template bind="{{b}}">'
1842 '{{ c }}' 1974 '{{ c }}'
1843 '</template>' 1975 '</template>'
1844 '</p>' 1976 '</p>'
1845 '</template>'); 1977 '</template>');
1846 1978 var template = div.firstChild;
1847 var m = toObservable({ 1979 var m = toObservable({
1848 'a': { 1980 'a': {
1849 'b': { 1981 'b': {
1850 'c': 42 1982 'c': 42
1851 } 1983 }
1852 } 1984 }
1853 }); 1985 });
1854 recursivelySetTemplateModel(div, m); 1986 templateBind(template).model = m;
1855 return new Future(() { 1987 return new Future(() {
1856 expect(div.nodes[1].tagName, 'P'); 1988 expect(div.nodes[1].tagName, 'P');
1857 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE'); 1989 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
1858 expect(div.nodes[1].nodes[1].text, '42'); 1990 expect(div.nodes[1].nodes[1].text, '42');
1859 }); 1991 });
1860 }); 1992 });
1861 1993
1862 test('TemplateContentRemoved', () { 1994 test('TemplateContentRemoved', () {
1863 var div = createTestHtml('<template bind="{{}}">{{ }}</template>'); 1995 var div = createTestHtml('<template bind="{{}}">{{ }}</template>');
1996 var template = div.firstChild;
1864 var model = 42; 1997 var model = 42;
1865 1998
1866 recursivelySetTemplateModel(div, model); 1999 templateBind(template).model = model;
1867 return new Future(() { 2000 return new Future(() {
1868 expect(div.nodes[1].text, '42'); 2001 expect(div.nodes[1].text, '42');
1869 expect(div.nodes[0].text, ''); 2002 expect(div.nodes[0].text, '');
1870 }); 2003 });
1871 }); 2004 });
1872 2005
1873 test('TemplateContentRemovedEmptyArray', () { 2006 test('TemplateContentRemovedEmptyArray', () {
1874 var div = createTestHtml('<template iterate>Remove me</template>'); 2007 var div = createTestHtml('<template iterate>Remove me</template>');
1875 var model = toObservable([]); 2008 var template = div.firstChild;
1876 2009 templateBind(template).model = [];
1877 recursivelySetTemplateModel(div, model);
1878 return new Future(() { 2010 return new Future(() {
1879 expect(div.nodes.length, 1); 2011 expect(div.nodes.length, 1);
1880 expect(div.nodes[0].text, ''); 2012 expect(div.nodes[0].text, '');
1881 }); 2013 });
1882 }); 2014 });
1883 2015
1884 test('TemplateContentRemovedNested', () { 2016 test('TemplateContentRemovedNested', () {
1885 var div = createTestHtml( 2017 var div = createTestHtml(
1886 '<template bind="{{}}">' 2018 '<template bind="{{}}">'
1887 '{{ a }}' 2019 '{{ a }}'
1888 '<template bind="{{}}">' 2020 '<template bind="{{}}">'
1889 '{{ b }}' 2021 '{{ b }}'
1890 '</template>' 2022 '</template>'
1891 '</template>'); 2023 '</template>');
1892 2024 var template = div.firstChild;
1893 var model = toObservable({ 2025 var model = toObservable({
1894 'a': 1, 2026 'a': 1,
1895 'b': 2 2027 'b': 2
1896 }); 2028 });
1897 recursivelySetTemplateModel(div, model); 2029 templateBind(template).model = model;
1898 return new Future(() { 2030 return new Future(() {
1899 expect(div.nodes[0].text, ''); 2031 expect(div.nodes[0].text, '');
1900 expect(div.nodes[1].text, '1'); 2032 expect(div.nodes[1].text, '1');
1901 expect(div.nodes[2].text, ''); 2033 expect(div.nodes[2].text, '');
1902 expect(div.nodes[3].text, '2'); 2034 expect(div.nodes[3].text, '2');
1903 }); 2035 });
1904 }); 2036 });
1905 2037
1906 test('BindWithUndefinedModel', () { 2038 test('BindWithUndefinedModel', () {
1907 var div = createTestHtml( 2039 var div = createTestHtml(
1908 '<template bind="{{}}" if="{{}}">{{ a }}</template>'); 2040 '<template bind="{{}}" if="{{}}">{{ a }}</template>');
2041 var template = div.firstChild;
1909 2042
1910 var model = toObservable({'a': 42}); 2043 var model = toObservable({'a': 42});
1911 recursivelySetTemplateModel(div, model); 2044 templateBind(template).model = model;
1912 return new Future(() { 2045 return new Future(() {
1913 expect(div.nodes[1].text, '42'); 2046 expect(div.nodes[1].text, '42');
1914 2047
1915 model = null; 2048 model = null;
1916 recursivelySetTemplateModel(div, model); 2049 templateBind(template).model = model;
1917 }).then(endOfMicrotask).then((_) { 2050 }).then(endOfMicrotask).then((_) {
1918 expect(div.nodes.length, 1); 2051 expect(div.nodes.length, 1);
1919 2052
1920 model = toObservable({'a': 42}); 2053 model = toObservable({'a': 42});
1921 recursivelySetTemplateModel(div, model); 2054 templateBind(template).model = model;
1922 }).then(endOfMicrotask).then((_) { 2055 }).then(endOfMicrotask).then((_) {
1923 expect(div.nodes[1].text, '42'); 2056 expect(div.nodes[1].text, '42');
1924 }); 2057 });
1925 }); 2058 });
1926 2059
1927 test('BindNested', () { 2060 test('BindNested', () {
1928 var div = createTestHtml( 2061 var div = createTestHtml(
1929 '<template bind="{{}}">' 2062 '<template bind="{{}}">'
1930 'Name: {{ name }}' 2063 'Name: {{ name }}'
1931 '<template bind="{{wife}}" if="{{wife}}">' 2064 '<template bind="{{wife}}" if="{{wife}}">'
1932 'Wife: {{ name }}' 2065 'Wife: {{ name }}'
1933 '</template>' 2066 '</template>'
1934 '<template bind="{{child}}" if="{{child}}">' 2067 '<template bind="{{child}}" if="{{child}}">'
1935 'Child: {{ name }}' 2068 'Child: {{ name }}'
1936 '</template>' 2069 '</template>'
1937 '</template>'); 2070 '</template>');
1938 2071 var template = div.firstChild;
1939 var m = toObservable({ 2072 var m = toObservable({
1940 'name': 'Hermes', 2073 'name': 'Hermes',
1941 'wife': { 2074 'wife': {
1942 'name': 'LaBarbara' 2075 'name': 'LaBarbara'
1943 } 2076 }
1944 }); 2077 });
1945 recursivelySetTemplateModel(div, m); 2078 templateBind(template).model = m;
2079
1946 return new Future(() { 2080 return new Future(() {
1947 expect(div.nodes.length, 5); 2081 expect(div.nodes.length, 5);
1948 expect(div.nodes[1].text, 'Name: Hermes'); 2082 expect(div.nodes[1].text, 'Name: Hermes');
1949 expect(div.nodes[3].text, 'Wife: LaBarbara'); 2083 expect(div.nodes[3].text, 'Wife: LaBarbara');
1950 2084
1951 m['child'] = toObservable({'name': 'Dwight'}); 2085 m['child'] = toObservable({'name': 'Dwight'});
2086
1952 }).then(endOfMicrotask).then((_) { 2087 }).then(endOfMicrotask).then((_) {
1953 expect(div.nodes.length, 6); 2088 expect(div.nodes.length, 6);
1954 expect(div.nodes[5].text, 'Child: Dwight'); 2089 expect(div.nodes[5].text, 'Child: Dwight');
1955 2090
1956 m.remove('wife'); 2091 m.remove('wife');
2092
1957 }).then(endOfMicrotask).then((_) { 2093 }).then(endOfMicrotask).then((_) {
1958 expect(div.nodes.length, 5); 2094 expect(div.nodes.length, 5);
1959 expect(div.nodes[4].text, 'Child: Dwight'); 2095 expect(div.nodes[4].text, 'Child: Dwight');
1960 }); 2096 });
1961 }); 2097 });
1962 2098
1963 test('BindRecursive', () { 2099 test('BindRecursive', () {
1964 var div = createTestHtml( 2100 var div = createTestHtml(
1965 '<template bind="{{}}" if="{{}}" id="t">' 2101 '<template bind="{{}}" if="{{}}" id="t">'
1966 'Name: {{ name }}' 2102 'Name: {{ name }}'
1967 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>' 2103 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>'
1968 '</template>'); 2104 '</template>');
1969 2105 var template = div.firstChild;
1970 var m = toObservable({ 2106 var m = toObservable({
1971 'name': 'Fry', 2107 'name': 'Fry',
1972 'friend': { 2108 'friend': {
1973 'name': 'Bender' 2109 'name': 'Bender'
1974 } 2110 }
1975 }); 2111 });
1976 recursivelySetTemplateModel(div, m); 2112 templateBind(template).model = m;
1977 return new Future(() { 2113 return new Future(() {
1978 expect(div.nodes.length, 5); 2114 expect(div.nodes.length, 5);
1979 expect(div.nodes[1].text, 'Name: Fry'); 2115 expect(div.nodes[1].text, 'Name: Fry');
1980 expect(div.nodes[3].text, 'Name: Bender'); 2116 expect(div.nodes[3].text, 'Name: Bender');
1981 2117
1982 m['friend']['friend'] = toObservable({'name': 'Leela'}); 2118 m['friend']['friend'] = toObservable({'name': 'Leela'});
1983 }).then(endOfMicrotask).then((_) { 2119 }).then(endOfMicrotask).then((_) {
1984 expect(div.nodes.length, 7); 2120 expect(div.nodes.length, 7);
1985 expect(div.nodes[5].text, 'Name: Leela'); 2121 expect(div.nodes[5].text, 'Name: Leela');
1986 2122
1987 m['friend'] = toObservable({'name': 'Leela'}); 2123 m['friend'] = toObservable({'name': 'Leela'});
1988 }).then(endOfMicrotask).then((_) { 2124 }).then(endOfMicrotask).then((_) {
1989 expect(div.nodes.length, 5); 2125 expect(div.nodes.length, 5);
1990 expect(div.nodes[3].text, 'Name: Leela'); 2126 expect(div.nodes[3].text, 'Name: Leela');
1991 }); 2127 });
1992 }); 2128 });
1993 2129
1994 test('Template - Self is terminator', () { 2130 test('Template - Self is terminator', () {
1995 var div = createTestHtml( 2131 var div = createTestHtml(
1996 '<template repeat>{{ foo }}' 2132 '<template repeat>{{ foo }}'
1997 '<template bind></template>' 2133 '<template bind></template>'
1998 '</template>'); 2134 '</template>');
2135 var template = div.firstChild;
1999 2136
2000 var m = toObservable([{ 'foo': 'bar' }]); 2137 var m = toObservable([{ 'foo': 'bar' }]);
2001 recursivelySetTemplateModel(div, m); 2138 templateBind(template).model = m;
2002 return new Future(() { 2139 return new Future(() {
2003 2140
2004 m.add(toObservable({ 'foo': 'baz' })); 2141 m.add(toObservable({ 'foo': 'baz' }));
2005 recursivelySetTemplateModel(div, m); 2142 templateBind(template).model = m;
2006 }).then(endOfMicrotask).then((_) { 2143 }).then(endOfMicrotask).then((_) {
2007 2144
2008 expect(div.nodes.length, 5); 2145 expect(div.nodes.length, 5);
2009 expect(div.nodes[1].text, 'bar'); 2146 expect(div.nodes[1].text, 'bar');
2010 expect(div.nodes[3].text, 'baz'); 2147 expect(div.nodes[3].text, 'baz');
2011 }); 2148 });
2012 }); 2149 });
2013 2150
2014 test('Template - Same Contents, Different Array has no effect', () { 2151 test('Template - Same Contents, Different Array has no effect', () {
2015 if (!MutationObserver.supported) return null; 2152 if (!MutationObserver.supported) return null;
2016 2153
2017 var div = createTestHtml('<template repeat>{{ foo }}</template>'); 2154 var div = createTestHtml('<template repeat>{{ foo }}</template>');
2155 var template = div.firstChild;
2018 2156
2019 var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]); 2157 var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]);
2020 recursivelySetTemplateModel(div, m); 2158 templateBind(template).model = m;
2021 var observer = new MutationObserver((x, y) {}); 2159 var observer = new MutationObserver((x, y) {});
2022 return new Future(() { 2160 return new Future(() {
2023 observer.observe(div, childList: true); 2161 observer.observe(div, childList: true);
2024 2162
2025 var template = div.firstChild; 2163 var template = div.firstChild;
2026 templateBind(template).model = new ObservableList.from(m); 2164 templateBind(template).model = new ObservableList.from(m);
2027 }).then(endOfMicrotask).then((_) { 2165 }).then(endOfMicrotask).then((_) {
2028 var records = observer.takeRecords(); 2166 var records = observer.takeRecords();
2029 expect(records.length, 0); 2167 expect(records.length, 0);
2030 }); 2168 });
2031 }); 2169 });
2032 2170
2033 test('RecursiveRef', () { 2171 test('RecursiveRef', () {
2034 var div = createTestHtml( 2172 var div = createTestHtml(
2035 '<template bind>' 2173 '<template bind>'
2036 '<template id=src>{{ foo }}</template>' 2174 '<template id=src>{{ foo }}</template>'
2037 '<template bind ref=src></template>' 2175 '<template bind ref=src></template>'
2038 '</template>'); 2176 '</template>');
2039 2177
2040 var m = toObservable({'foo': 'bar'}); 2178 var m = toObservable({'foo': 'bar'});
2041 recursivelySetTemplateModel(div, m); 2179 templateBind(div.firstChild).model = m;
2042 return new Future(() { 2180 return new Future(() {
2043 expect(div.nodes.length, 4); 2181 expect(div.nodes.length, 4);
2044 expect(div.nodes[3].text, 'bar'); 2182 expect(div.nodes[3].text, 'bar');
2045 }); 2183 });
2046 }); 2184 });
2047 2185
2186 test('baseURI', () {
2187 // TODO(jmesserly): Dart's setInnerHtml breaks this test -- the template
2188 // URL is created as blank despite the NullTreeSanitizer.
2189 // Use JS interop as a workaround.
2190 //var div = createTestHtml('<template bind>'
2191 // '<div style="background: url(foo.jpg)"></div></template>');
2192 var div = new DivElement();
2193 new JsObject.fromBrowserObject(div)['innerHTML'] = '<template bind>'
2194 '<div style="background: url(foo.jpg)"></div></template>';
2195 testDiv.append(div);
2196 TemplateBindExtension.decorate(div.firstChild);
2197
2198 var local = document.createElement('div');
2199 local.attributes['style'] = 'background: url(foo.jpg)';
2200 div.append(local);
2201 var template = div.firstChild;
2202 templateBind(template).model = {};
2203 return new Future(() {
2204 expect(div.nodes[1].style.backgroundImage, local.style.backgroundImage);
2205 });
2206 });
2207
2048 test('ChangeRefId', () { 2208 test('ChangeRefId', () {
2049 var div = createTestHtml( 2209 var div = createTestHtml(
2050 '<template id="a">a:{{ }}</template>' 2210 '<template id="a">a:{{ }}</template>'
2051 '<template id="b">b:{{ }}</template>' 2211 '<template id="b">b:{{ }}</template>'
2052 '<template repeat="{{}}">' 2212 '<template repeat="{{}}">'
2053 '<template ref="a" bind="{{}}"></template>' 2213 '<template ref="a" bind="{{}}"></template>'
2054 '</template>'); 2214 '</template>');
2215 var template = div.nodes[2];
2055 var model = toObservable([]); 2216 var model = toObservable([]);
2056 recursivelySetTemplateModel(div, model); 2217 templateBind(template).model = model;
2057 return new Future(() { 2218 return new Future(() {
2058 expect(div.nodes.length, 3); 2219 expect(div.nodes.length, 3);
2059 2220
2060 document.getElementById('a').id = 'old-a'; 2221 document.getElementById('a').id = 'old-a';
2061 document.getElementById('b').id = 'a'; 2222 document.getElementById('b').id = 'a';
2062 2223
2063 model..add(1)..add(2); 2224 model..add(1)..add(2);
2064 }).then(endOfMicrotask).then((_) { 2225 }).then(endOfMicrotask).then((_) {
2065 2226
2066 expect(div.nodes.length, 7); 2227 expect(div.nodes.length, 7);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2111 expect(templateBind(templateB).content.ownerDocument, 2272 expect(templateBind(templateB).content.ownerDocument,
2112 templateBind(templateA).content.ownerDocument); 2273 templateBind(templateA).content.ownerDocument);
2113 }); 2274 });
2114 2275
2115 test('BindShadowDOM', () { 2276 test('BindShadowDOM', () {
2116 if (!ShadowRoot.supported) return null; 2277 if (!ShadowRoot.supported) return null;
2117 2278
2118 var root = createShadowTestHtml( 2279 var root = createShadowTestHtml(
2119 '<template bind="{{}}">Hi {{ name }}</template>'); 2280 '<template bind="{{}}">Hi {{ name }}</template>');
2120 var model = toObservable({'name': 'Leela'}); 2281 var model = toObservable({'name': 'Leela'});
2121 recursivelySetTemplateModel(root, model); 2282 templateBind(root.firstChild).model = model;
2122 return new Future(() => expect(root.nodes[1].text, 'Hi Leela')); 2283 return new Future(() => expect(root.nodes[1].text, 'Hi Leela'));
2123 }); 2284 });
2124 2285
2125 // Dart note: this test seems gone from JS. Keeping for posterity sake. 2286 // Dart note: this test seems gone from JS. Keeping for posterity sake.
2126 test('BindShadowDOM createInstance', () { 2287 test('BindShadowDOM createInstance', () {
2127 if (!ShadowRoot.supported) return null; 2288 if (!ShadowRoot.supported) return null;
2128 2289
2129 var model = toObservable({'name': 'Leela'}); 2290 var model = toObservable({'name': 'Leela'});
2130 var template = new Element.html('<template>Hi {{ name }}</template>'); 2291 var template = new Element.html('<template>Hi {{ name }}</template>');
2131 var root = createShadowTestHtml(''); 2292 var root = createShadowTestHtml('');
2132 root.nodes.add(templateBind(template).createInstance(model)); 2293 root.nodes.add(templateBind(template).createInstance(model));
2133 2294
2134 return new Future(() { 2295 return new Future(() {
2135 expect(root.text, 'Hi Leela'); 2296 expect(root.text, 'Hi Leela');
2136 2297
2137 model['name'] = 'Fry'; 2298 model['name'] = 'Fry';
2138 }).then(endOfMicrotask).then((_) { 2299 }).then(endOfMicrotask).then((_) {
2139 expect(root.text, 'Hi Fry'); 2300 expect(root.text, 'Hi Fry');
2140 }); 2301 });
2141 }); 2302 });
2142 2303
2143 test('BindShadowDOM Template Ref', () { 2304 test('BindShadowDOM Template Ref', () {
2144 if (!ShadowRoot.supported) return null; 2305 if (!ShadowRoot.supported) return null;
2145 var root = createShadowTestHtml( 2306 var root = createShadowTestHtml(
2146 '<template id=foo>Hi</template><template bind ref=foo></template>'); 2307 '<template id=foo>Hi</template><template bind ref=foo></template>');
2147 recursivelySetTemplateModel(root, toObservable({})); 2308 var template = root.nodes[1];
2148 return new Future(() => expect(root.nodes.length, 3)); 2309 templateBind(template).model = toObservable({});
2310 return new Future(() {
2311 expect(root.nodes.length, 3);
2312 clearAllTemplates(root);
2313 });
2149 }); 2314 });
2150 2315
2151 // https://github.com/Polymer/TemplateBinding/issues/8 2316 // https://github.com/Polymer/TemplateBinding/issues/8
2152 test('UnbindingInNestedBind', () { 2317 test('UnbindingInNestedBind', () {
2153 var div = createTestHtml( 2318 var div = createTestHtml(
2154 '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">' 2319 '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">'
2155 '<template bind="{{inner}}" if="{{inner}}">' 2320 '<template bind="{{inner}}" if="{{inner}}">'
2156 '{{ age }}' 2321 '{{ age }}'
2157 '</template>' 2322 '</template>'
2158 '</template>'); 2323 '</template>');
2159 2324 var template = div.firstChild;
2160 var syntax = new UnbindingInNestedBindSyntax(); 2325 var syntax = new UnbindingInNestedBindSyntax();
2161 var model = toObservable({'outer': {'inner': {'age': 42}}}); 2326 var model = toObservable({'outer': {'inner': {'age': 42}}});
2162 2327
2163 recursivelySetTemplateModel(div, model, syntax); 2328 templateBind(template)..model = model..bindingDelegate = syntax;
2164 2329
2165 return new Future(() { 2330 return new Future(() {
2166 expect(syntax.count, 1); 2331 expect(syntax.count, 1);
2167 2332
2168 var inner = model['outer']['inner']; 2333 var inner = model['outer']['inner'];
2169 model['outer'] = null; 2334 model['outer'] = null;
2170 2335
2171 }).then(endOfMicrotask).then((_) { 2336 }).then(endOfMicrotask).then((_) {
2172 expect(syntax.count, 1); 2337 expect(syntax.count, 1);
2173 2338
2174 model['outer'] = toObservable({'inner': {'age': 2}}); 2339 model['outer'] = toObservable({'inner': {'age': 2}});
2175 syntax.expectedAge = 2; 2340 syntax.expectedAge = 2;
2176 2341
2177 }).then(endOfMicrotask).then((_) { 2342 }).then(endOfMicrotask).then((_) {
2178 expect(syntax.count, 2); 2343 expect(syntax.count, 2);
2179 }); 2344 });
2180 }); 2345 });
2181 2346
2182 // https://github.com/toolkitchen/mdv/issues/8 2347 // https://github.com/toolkitchen/mdv/issues/8
2183 test('DontCreateInstancesForAbandonedIterators', () { 2348 test('DontCreateInstancesForAbandonedIterators', () {
2184 var div = createTestHtml( 2349 var div = createTestHtml(
2185 '<template bind="{{}} {{}}">' 2350 '<template bind="{{}} {{}}">'
2186 '<template bind="{{}}">Foo</template>' 2351 '<template bind="{{}}">Foo</template>'
2187 '</template>'); 2352 '</template>');
2188 recursivelySetTemplateModel(div, null); 2353 var template = div.firstChild;
2354 templateBind(template).model = null;
2189 return nextMicrotask; 2355 return nextMicrotask;
2190 }); 2356 });
2191 2357
2192 test('CreateInstance', () { 2358 test('CreateInstance', () {
2193 var div = createTestHtml( 2359 var div = createTestHtml(
2194 '<template bind="{{a}}">' 2360 '<template bind="{{a}}">'
2195 '<template bind="{{b}}">' 2361 '<template bind="{{b}}">'
2196 '{{ foo }}:{{ replaceme }}' 2362 '{{ foo }}:{{ replaceme }}'
2197 '</template>' 2363 '</template>'
2198 '</template>'); 2364 '</template>');
2199 var outer = templateBind(div.nodes.first); 2365 var outer = templateBind(div.nodes.first);
2200 var model = toObservable({'b': {'foo': 'bar'}}); 2366 var model = toObservable({'b': {'foo': 'bar'}});
2201 2367
2202 var host = new DivElement();
2203 var instance = outer.createInstance(model, new TestBindingSyntax()); 2368 var instance = outer.createInstance(model, new TestBindingSyntax());
2204 expect(outer.content.nodes.first, 2369 expect(instance.firstChild.nextNode.text, 'bar:replaced');
2205 templateBind(instance.nodes.first).ref);
2206 2370
2207 host.append(instance); 2371 clearAllTemplates(instance);
2208 return new Future(() {
2209 expect(host.firstChild.nextNode.text, 'bar:replaced');
2210 });
2211 }); 2372 });
2212 2373
2213 test('CreateInstance - sync error', () { 2374 test('CreateInstance - sync error', () {
2214 var div = createTestHtml('<template>{{foo}}</template>'); 2375 var div = createTestHtml('<template>{{foo}}</template>');
2215 var outer = templateBind(div.nodes.first); 2376 var outer = templateBind(div.nodes.first);
2216 var model = 1; // model is missing 'foo' should throw. 2377 var model = 1; // model is missing 'foo' should throw.
2217 expect(() => outer.createInstance(model, new TestBindingSyntax()), 2378 expect(() => outer.createInstance(model, new TestBindingSyntax()),
2218 throwsA(isNoSuchMethodError)); 2379 throwsA(isNoSuchMethodError));
2219 }); 2380 });
2220 2381
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
2317 return new Future(() { 2478 return new Future(() {
2318 expect(template.nextNode.nextNode.nextNode.text, '2'); 2479 expect(template.nextNode.nextNode.nextNode.text, '2');
2319 model['show'] = false; 2480 model['show'] = false;
2320 }).then(endOfMicrotask).then((_) { 2481 }).then(endOfMicrotask).then((_) {
2321 model['show'] = true; 2482 model['show'] = true;
2322 }).then(endOfMicrotask).then((_) { 2483 }).then(endOfMicrotask).then((_) {
2323 expect(template.nextNode.nextNode.nextNode.text, '2'); 2484 expect(template.nextNode.nextNode.nextNode.text, '2');
2324 }); 2485 });
2325 }); 2486 });
2326 2487
2488 test('Accessor value retrieval count', () {
2489 var div = createTestHtml(
2490 '<template bind>{{ prop }}</template>');
2491
2492 var model = new TestAccessorModel();
2493
2494 templateBind(div.firstChild).model = model;
2495
2496 return new Future(() {
2497 expect(model.count, 1);
2498
2499 model.value++;
2500 // Dart note: we don't handle getters in @observable, so we need to
2501 // notify regardless.
2502 model.notifyPropertyChange(#prop, 1, model.value);
2503
2504 }).then(endOfMicrotask).then((_) {
2505 expect(model.count, 2);
2506 });
2507 });
2508
2327 test('issue-141', () { 2509 test('issue-141', () {
2328 var div = createTestHtml( 2510 var div = createTestHtml(
2329 '<template bind>' 2511 '<template bind>'
2330 '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' 2512 '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>'
2331 '</template>'); 2513 '</template>');
2332 2514
2515 var template = div.firstChild;
2333 var model = toObservable({ 2516 var model = toObservable({
2334 'foo1': 'foo1Value', 2517 'foo1': 'foo1Value',
2335 'foo2': 'foo2Value', 2518 'foo2': 'foo2Value',
2336 'bar': 'barValue' 2519 'bar': 'barValue'
2337 }); 2520 });
2338 2521
2339 recursivelySetTemplateModel(div, model); 2522 templateBind(template).model = model;
2340 return new Future(() { 2523 return new Future(() {
2341 expect(div.lastChild.attributes['bar'], 'barValue'); 2524 expect(div.lastChild.attributes['bar'], 'barValue');
2342 }); 2525 });
2343 }); 2526 });
2344 2527
2345 test('issue-18', () { 2528 test('issue-18', () {
2346 var delegate = new Issue18Syntax(); 2529 var delegate = new Issue18Syntax();
2347 2530
2348 var div = createTestHtml( 2531 var div = createTestHtml(
2349 '<template bind>' 2532 '<template bind>'
2350 '<div class="foo: {{ bar }}"></div>' 2533 '<div class="foo: {{ bar }}"></div>'
2351 '</template>'); 2534 '</template>');
2352 2535
2536 var template = div.firstChild;
2353 var model = toObservable({'bar': 2}); 2537 var model = toObservable({'bar': 2});
2354 2538
2355 recursivelySetTemplateModel(div, model, delegate); 2539 templateBind(template)..model = model..bindingDelegate = delegate;
2356 2540
2357 return new Future(() { 2541 return new Future(() {
2358 expect(div.lastChild.attributes['class'], 'foo: 2'); 2542 expect(div.lastChild.attributes['class'], 'foo: 2');
2359 }); 2543 });
2360 }); 2544 });
2361 2545
2362 test('issue-152', () { 2546 test('issue-152', () {
2363 var div = createTestHtml('<template ref=notThere></template>'); 2547 var div = createTestHtml(
2548 '<template ref=notThere bind>XXX</template>');
2549
2364 var template = div.firstChild; 2550 var template = div.firstChild;
2551 templateBind(template).model = {};
2365 2552
2366 // if a ref cannot be located, a template will continue to use itself 2553 return new Future(() {
2367 // as the source of template instances. 2554 // if a ref cannot be located, a template will continue to use itself
2368 expect(template, templateBind(template).ref); 2555 // as the source of template instances.
2556 expect(div.nodes[1].text, 'XXX');
2557 });
2369 }); 2558 });
2370 } 2559 }
2371 2560
2372 compatTests() { 2561 compatTests() {
2373 test('underbar bindings', () { 2562 test('underbar bindings', () {
2374 var div = createTestHtml( 2563 var div = createTestHtml(
2375 '<template bind>' 2564 '<template bind>'
2376 '<div _style="color: {{ color }};"></div>' 2565 '<div _style="color: {{ color }};"></div>'
2377 '<img _src="{{ url }}">' 2566 '<img _src="{{ url }}">'
2378 '<a _href="{{ url2 }}">Link</a>' 2567 '<a _href="{{ url2 }}">Link</a>'
2379 '<input type="number" _value="{{ number }}">' 2568 '<input type="number" _value="{{ number }}">'
2380 '</template>'); 2569 '</template>');
2381 2570
2571 var template = div.firstChild;
2382 var model = toObservable({ 2572 var model = toObservable({
2383 'color': 'red', 2573 'color': 'red',
2384 'url': 'pic.jpg', 2574 'url': 'pic.jpg',
2385 'url2': 'link.html', 2575 'url2': 'link.html',
2386 'number': 4 2576 'number': 4
2387 }); 2577 });
2388 2578
2389 recursivelySetTemplateModel(div, model); 2579 templateBind(template).model = model;
2390 return new Future(() { 2580 return new Future(() {
2391 var subDiv = div.firstChild.nextNode; 2581 var subDiv = div.firstChild.nextNode;
2392 expect(subDiv.attributes['style'], 'color: red;'); 2582 expect(subDiv.attributes['style'], 'color: red;');
2393 2583
2394 var img = subDiv.nextNode; 2584 var img = subDiv.nextNode;
2395 expect(img.attributes['src'], 'pic.jpg'); 2585 expect(img.attributes['src'], 'pic.jpg');
2396 2586
2397 var a = img.nextNode; 2587 var a = img.nextNode;
2398 expect(a.attributes['href'], 'link.html'); 2588 expect(a.attributes['href'], 'link.html');
2399 2589
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2433 } 2623 }
2434 } 2624 }
2435 2625
2436 class Issue18Syntax extends BindingDelegate { 2626 class Issue18Syntax extends BindingDelegate {
2437 prepareBinding(path, name, node) { 2627 prepareBinding(path, name, node) {
2438 if (name != 'class') return null; 2628 if (name != 'class') return null;
2439 2629
2440 return (model, _, oneTime) => new PathObserver(model, path); 2630 return (model, _, oneTime) => new PathObserver(model, path);
2441 } 2631 }
2442 } 2632 }
2633
2634 class TestAccessorModel extends Observable {
2635 @observable var value = 1;
2636 var count = 0;
2637
2638 @reflectable
2639 get prop {
2640 count++;
2641 return value;
2642 }
2643 }
OLDNEW
« no previous file with comments | « pkg/template_binding/test/node_bind_test.dart ('k') | pkg/template_binding/test/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698