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

Side by Side Diff: tests/html/template_element_test.dart

Issue 17552019: Reorganize mdv and observe packages (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merged Created 7 years, 5 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 | « tests/html/node_bindings_test.dart ('k') | tools/create_sdk.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library template_element_test;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:html';
10 import 'dart:math' as math;
11 import 'package:mdv_observe/mdv_observe.dart';
12 import 'package:unittest/html_config.dart';
13 import 'package:unittest/unittest.dart';
14 import 'mdv_observe_utils.dart';
15
16 // Note: this file ported from
17 // https://github.com/toolkitchen/mdv/blob/master/tests/template_element.js
18 // TODO(jmesserly): submit a small cleanup patch to original. I fixed some
19 // cases where "div" and "t" were unintentionally using the JS global scope;
20 // look for "assertNodesAre".
21
22 main() {
23 useHtmlConfiguration();
24 group('Template Element', templateElementTests);
25 }
26
27 templateElementTests() {
28 var testDiv;
29
30 setUp(() {
31 document.body.append(testDiv = new DivElement());
32 });
33
34 tearDown(() {
35 testDiv.remove();
36 testDiv = null;
37 });
38
39 createTestHtml(s) {
40 var div = new DivElement();
41 div.innerHtml = s;
42 testDiv.append(div);
43
44 for (var node in div.queryAll('*')) {
45 if (node.isTemplate) TemplateElement.decorate(node);
46 }
47
48 return div;
49 }
50
51 createShadowTestHtml(s) {
52 var div = new DivElement();
53 var root = div.createShadowRoot();
54 root.innerHtml = s;
55 testDiv.append(div);
56
57 for (var node in root.queryAll('*')) {
58 if (node.isTemplate) TemplateElement.decorate(node);
59 }
60
61 return root;
62 }
63
64 recursivelySetTemplateModel(element, model) {
65 for (var node in element.queryAll('*')) {
66 if (node.isTemplate) node.model = model;
67 }
68 }
69
70 dispatchEvent(type, target) {
71 target.dispatchEvent(new Event(type, cancelable: false));
72 }
73
74 test('Template', () {
75 var div = createTestHtml('<template bind={{}}>text</template>');
76 recursivelySetTemplateModel(div, null);
77 deliverChangeRecords();
78 expect(div.nodes.length, 2);
79 expect(div.nodes.last.text, 'text');
80 });
81
82 test('Template-Empty Bind', () {
83 var div = createTestHtml('<template bind>text</template>');
84 recursivelySetTemplateModel(div, null);
85 deliverChangeRecords();
86 expect(div.nodes.length, 2);
87 expect(div.nodes.last.text, 'text');
88 });
89
90 test('TextTemplateWithNullStringBinding', () {
91 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>');
92 var model = toSymbolMap({'b': 'B'});
93 recursivelySetTemplateModel(div, model);
94
95 deliverChanges(model);
96 expect(div.nodes.length, 2);
97 expect(div.nodes.last.text, 'aBc');
98
99 model[sym('b')] = 'b';
100 deliverChanges(model);
101 expect(div.nodes.last.text, 'abc');
102
103 model[sym('b')] = null;
104 deliverChanges(model);
105 expect(div.nodes.last.text, 'ac');
106
107 model = null;
108 deliverChanges(model);
109 // setting model isn't observable.
110 expect(div.nodes.last.text, 'ac');
111 });
112
113 test('TextTemplateWithBindingPath', () {
114 var div = createTestHtml(
115 '<template bind="{{ data }}">a{{b}}c</template>');
116 var model = toSymbolMap({ 'data': {'b': 'B'} });
117 recursivelySetTemplateModel(div, model);
118
119 deliverChanges(model);
120 expect(div.nodes.length, 2);
121 expect(div.nodes.last.text, 'aBc');
122
123 model[sym('data')][sym('b')] = 'b';
124 deliverChanges(model);
125 expect(div.nodes.last.text, 'abc');
126
127 model[sym('data')] = toSymbols({'b': 'X'});
128 deliverChanges(model);
129 expect(div.nodes.last.text, 'aXc');
130
131 model[sym('data')] = null;
132 deliverChanges(model);
133 expect(div.nodes.last.text, 'ac');
134 });
135
136 test('TextTemplateWithBindingAndConditional', () {
137 var div = createTestHtml(
138 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>');
139 var model = toSymbolMap({'b': 'B', 'd': 1});
140 recursivelySetTemplateModel(div, model);
141
142 deliverChanges(model);
143 expect(div.nodes.length, 2);
144 expect(div.nodes.last.text, 'aBc');
145
146 model[sym('b')] = 'b';
147 deliverChanges(model);
148 expect(div.nodes.last.text, 'abc');
149
150 // TODO(jmesserly): MDV set this to empty string and relies on JS conversion
151 // rules. Is that intended?
152 // See https://github.com/toolkitchen/mdv/issues/59
153 model[sym('d')] = null;
154 deliverChanges(model);
155 expect(div.nodes.length, 1);
156
157 model[sym('d')] = 'here';
158 model[sym('b')] = 'd';
159
160 deliverChanges(model);
161 expect(div.nodes.length, 2);
162 expect(div.nodes.last.text, 'adc');
163 });
164
165 test('TemplateWithTextBinding2', () {
166 var div = createTestHtml(
167 '<template bind="{{ b }}">a{{value}}c</template>');
168 expect(div.nodes.length, 1);
169 var model = toSymbolMap({'b': {'value': 'B'}});
170 recursivelySetTemplateModel(div, model);
171
172 deliverChanges(model);
173 expect(div.nodes.length, 2);
174 expect(div.nodes.last.text, 'aBc');
175
176 model[sym('b')] = toSymbols({'value': 'b'});
177 deliverChanges(model);
178 expect(div.nodes.last.text, 'abc');
179 });
180
181 test('TemplateWithAttributeBinding', () {
182 var div = createTestHtml(
183 '<template bind="{{}}">'
184 '<div foo="a{{b}}c"></div>'
185 '</template>');
186 var model = toSymbolMap({'b': 'B'});
187 recursivelySetTemplateModel(div, model);
188
189 deliverChanges(model);
190 expect(div.nodes.length, 2);
191 expect(div.nodes.last.attributes['foo'], 'aBc');
192
193 model[sym('b')] = 'b';
194 deliverChanges(model);
195 expect(div.nodes.last.attributes['foo'], 'abc');
196
197 model[sym('b')] = 'X';
198 deliverChanges(model);
199 expect(div.nodes.last.attributes['foo'], 'aXc');
200 });
201
202 test('TemplateWithConditionalBinding', () {
203 var div = createTestHtml(
204 '<template bind="{{}}">'
205 '<div foo?="{{b}}"></div>'
206 '</template>');
207 var model = toSymbolMap({'b': 'b'});
208 recursivelySetTemplateModel(div, model);
209
210 deliverChanges(model);
211 expect(div.nodes.length, 2);
212 expect(div.nodes.last.attributes['foo'], '');
213 expect(div.nodes.last.attributes, isNot(contains('foo?')));
214
215 model[sym('b')] = null;
216 deliverChanges(model);
217 expect(div.nodes.last.attributes, isNot(contains('foo')));
218 });
219
220 test('Repeat', () {
221 var div = createTestHtml(
222 '<template repeat="{{}}"">text</template>');
223
224 var model = toSymbols([0, 1, 2]);
225 recursivelySetTemplateModel(div, model);
226
227 deliverChanges(model);
228 expect(div.nodes.length, 4);
229
230 model.length = 1;
231 deliverChanges(model);
232 expect(div.nodes.length, 2);
233
234 model.addAll(toSymbols([3, 4]));
235 deliverChanges(model);
236 expect(div.nodes.length, 4);
237
238 model.removeRange(1, 2);
239 deliverChanges(model);
240 expect(div.nodes.length, 3);
241 });
242
243 test('Repeat-Empty', () {
244 var div = createTestHtml(
245 '<template repeat>text</template>');
246
247 var model = toSymbols([0, 1, 2]);
248 recursivelySetTemplateModel(div, model);
249
250 deliverChanges(model);
251 expect(div.nodes.length, 4);
252
253 model.length = 1;
254 deliverChanges(model);
255 expect(div.nodes.length, 2);
256
257 model.addAll(toSymbols([3, 4]));
258 deliverChanges(model);
259 expect(div.nodes.length, 4);
260
261 model.removeRange(1, 2);
262 deliverChanges(model);
263 expect(div.nodes.length, 3);
264 });
265
266 test('Removal from iteration needs to unbind', () {
267 var div = createTestHtml(
268 '<template repeat="{{}}"><a>{{v}}</a></template>');
269 var model = toSymbols([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, {'v': 4}]);
270 recursivelySetTemplateModel(div, model);
271 deliverChanges(model);
272
273 var nodes = div.nodes.skip(1).toList();
274 var vs = model.toList();
275
276 for (var i = 0; i < 5; i++) {
277 expect(nodes[i].text, '$i');
278 }
279
280 model.length = 3;
281 deliverChanges(model);
282 for (var i = 0; i < 5; i++) {
283 expect(nodes[i].text, '$i');
284 }
285
286 vs[3][sym('v')] = 33;
287 vs[4][sym('v')] = 44;
288 deliverChanges(model);
289 for (var i = 0; i < 5; i++) {
290 expect(nodes[i].text, '$i');
291 }
292 });
293
294 test('DOM Stability on Iteration', () {
295 var div = createTestHtml(
296 '<template repeat="{{}}">{{}}</template>');
297 var model = toSymbols([1, 2, 3, 4, 5]);
298 recursivelySetTemplateModel(div, model);
299
300 deliverChanges(model);
301
302 // Note: the node at index 0 is the <template>.
303 var nodes = div.nodes.toList();
304 expect(nodes.length, 6, reason: 'list has 5 items');
305
306 model.removeAt(0);
307 model.removeLast();
308
309 deliverChanges(model);
310 expect(div.nodes.length, 4, reason: 'list has 3 items');
311 expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed');
312 expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed');
313 expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed');
314
315 model.insert(0, 5);
316 model[2] = 6;
317 model.add(7);
318
319 deliverChanges(model);
320
321 expect(div.nodes.length, 6, reason: 'list has 5 items');
322 expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node');
323 expect(identical(div.nodes[2], nodes[2]), true);
324 expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node');
325 expect(identical(div.nodes[4], nodes[4]), true);
326 expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node');
327
328 nodes = div.nodes.toList();
329
330 model.insert(2, 8);
331
332 deliverChanges(model);
333
334 expect(div.nodes.length, 7, reason: 'list has 6 items');
335 expect(identical(div.nodes[1], nodes[1]), true);
336 expect(identical(div.nodes[2], nodes[2]), true);
337 expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node');
338 expect(identical(div.nodes[4], nodes[3]), true);
339 expect(identical(div.nodes[5], nodes[4]), true);
340 expect(identical(div.nodes[6], nodes[5]), true);
341 });
342
343 test('Repeat2', () {
344 var div = createTestHtml(
345 '<template repeat="{{}}">{{value}}</template>');
346 expect(div.nodes.length, 1);
347
348 var model = toSymbols([
349 {'value': 0},
350 {'value': 1},
351 {'value': 2}
352 ]);
353 recursivelySetTemplateModel(div, model);
354
355 deliverChanges(model);
356 expect(div.nodes.length, 4);
357 expect(div.nodes[1].text, '0');
358 expect(div.nodes[2].text, '1');
359 expect(div.nodes[3].text, '2');
360
361 model[1][sym('value')] = 'One';
362 deliverChanges(model);
363 expect(div.nodes.length, 4);
364 expect(div.nodes[1].text, '0');
365 expect(div.nodes[2].text, 'One');
366 expect(div.nodes[3].text, '2');
367
368 model.replaceRange(0, 1, toSymbols([{'value': 'Zero'}]));
369 deliverChanges(model);
370 expect(div.nodes.length, 4);
371 expect(div.nodes[1].text, 'Zero');
372 expect(div.nodes[2].text, 'One');
373 expect(div.nodes[3].text, '2');
374 });
375
376 test('TemplateWithInputValue', () {
377 var div = createTestHtml(
378 '<template bind="{{}}">'
379 '<input value="{{x}}">'
380 '</template>');
381 var model = toSymbolMap({'x': 'hi'});
382 recursivelySetTemplateModel(div, model);
383
384 deliverChanges(model);
385 expect(div.nodes.length, 2);
386 expect(div.nodes.last.value, 'hi');
387
388 model[sym('x')] = 'bye';
389 expect(div.nodes.last.value, 'hi');
390 deliverChanges(model);
391 expect(div.nodes.last.value, 'bye');
392
393 div.nodes.last.value = 'hello';
394 dispatchEvent('input', div.nodes.last);
395 expect(model[sym('x')], 'hello');
396 deliverChanges(model);
397 expect(div.nodes.last.value, 'hello');
398 });
399
400 //////////////////////////////////////////////////////////////////////////////
401
402 test('Decorated', () {
403 var div = createTestHtml(
404 '<template bind="{{ XX }}" id="t1">'
405 '<p>Crew member: {{name}}, Job title: {{title}}</p>'
406 '</template>'
407 '<template bind="{{ XY }}" id="t2" ref="t1"></template>');
408
409 var model = toSymbolMap({
410 'XX': {'name': 'Leela', 'title': 'Captain'},
411 'XY': {'name': 'Fry', 'title': 'Delivery boy'},
412 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
413 });
414 recursivelySetTemplateModel(div, model);
415
416 deliverChanges(model);
417
418 var t1 = document.getElementById('t1');
419 var instance = t1.nextElementSibling;
420 expect(instance.text, 'Crew member: Leela, Job title: Captain');
421
422 var t2 = document.getElementById('t2');
423 instance = t2.nextElementSibling;
424 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
425
426 expect(div.children.length, 4);
427 expect(div.nodes.length, 4);
428
429 expect(div.nodes[1].tagName, 'P');
430 expect(div.nodes[3].tagName, 'P');
431 });
432
433 test('DefaultStyles', () {
434 var t = new Element.tag('template');
435 TemplateElement.decorate(t);
436
437 document.body.append(t);
438 expect(t.getComputedStyle().display, 'none');
439
440 t.remove();
441 });
442
443
444 test('Bind', () {
445 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>');
446 var model = toSymbolMap({'name': 'Leela'});
447 recursivelySetTemplateModel(div, model);
448
449 deliverChanges(model);
450 expect(div.nodes[1].text, 'Hi Leela');
451 });
452
453 test('BindImperative', () {
454 var div = createTestHtml(
455 '<template>'
456 'Hi {{ name }}'
457 '</template>');
458 var t = div.nodes.first;
459
460 var model = toSymbolMap({'name': 'Leela'});
461 t.bind('bind', model, '');
462
463 deliverChanges(model);
464 expect(div.nodes[1].text, 'Hi Leela');
465 });
466
467 test('BindPlaceHolderHasNewLine', () {
468 var div = createTestHtml('<template bind="{{}}">Hi {{\nname\n}}</template>') ;
469 var model = toSymbolMap({'name': 'Leela'});
470 recursivelySetTemplateModel(div, model);
471
472 deliverChanges(model);
473 expect(div.nodes[1].text, 'Hi Leela');
474 });
475
476 test('BindWithRef', () {
477 var id = 't${new math.Random().nextDouble()}';
478 var div = createTestHtml(
479 '<template id="$id">'
480 'Hi {{ name }}'
481 '</template>'
482 '<template ref="$id" bind="{{}}"></template>');
483
484 var t1 = div.nodes.first;
485 var t2 = div.nodes[1];
486
487 expect(t2.ref, t1);
488
489 var model = toSymbolMap({'name': 'Fry'});
490 recursivelySetTemplateModel(div, model);
491
492 deliverChanges(model);
493 expect(t2.nextNode.text, 'Hi Fry');
494 });
495
496 test('BindChanged', () {
497 var model = toSymbolMap({
498 'XX': {'name': 'Leela', 'title': 'Captain'},
499 'XY': {'name': 'Fry', 'title': 'Delivery boy'},
500 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
501 });
502
503 var div = createTestHtml(
504 '<template bind="{{ XX }}">Hi {{ name }}</template>');
505
506 recursivelySetTemplateModel(div, model);
507
508 var t = div.nodes.first;
509 deliverChanges(model);
510
511 expect(div.nodes.length, 2);
512 expect(t.nextNode.text, 'Hi Leela');
513
514 t.bind('bind', model, 'XZ');
515 deliverChanges(model);
516
517 expect(div.nodes.length, 2);
518 expect(t.nextNode.text, 'Hi Zoidberg');
519 });
520
521 assertNodesAre(div, [arguments]) {
522 var expectedLength = arguments.length;
523 expect(div.nodes.length, expectedLength + 1);
524
525 for (var i = 0; i < arguments.length; i++) {
526 var targetNode = div.nodes[i + 1];
527 expect(targetNode.text, arguments[i]);
528 }
529 }
530
531 test('Repeat3', () {
532 var div = createTestHtml(
533 '<template repeat="{{ contacts }}">Hi {{ name }}</template>');
534 var t = div.nodes.first;
535
536 var m = toSymbols({
537 'contacts': [
538 {'name': 'Raf'},
539 {'name': 'Arv'},
540 {'name': 'Neal'}
541 ]
542 });
543
544 recursivelySetTemplateModel(div, m);
545 deliverChanges(m);
546
547 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
548
549 m[sym('contacts')].add(toSymbols({'name': 'Alex'}));
550 deliverChanges(m);
551 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
552
553 m[sym('contacts')].replaceRange(0, 2,
554 toSymbols([{'name': 'Rafael'}, {'name': 'Erik'}]));
555 deliverChanges(m);
556 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
557
558 m[sym('contacts')].removeRange(1, 3);
559 deliverChanges(m);
560 assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
561
562 m[sym('contacts')].insertAll(1,
563 toSymbols([{'name': 'Erik'}, {'name': 'Dimitri'}]));
564 deliverChanges(m);
565 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
566
567 m[sym('contacts')].replaceRange(0, 1,
568 toSymbols([{'name': 'Tab'}, {'name': 'Neal'}]));
569 deliverChanges(m);
570 assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri', 'Hi Alex' ]);
571
572 m[sym('contacts')] = toSymbols([{'name': 'Alex'}]);
573 deliverChanges(m);
574 assertNodesAre(div, ['Hi Alex']);
575
576 m[sym('contacts')].length = 0;
577 deliverChanges(m);
578 assertNodesAre(div, []);
579 });
580
581 test('RepeatModelSet', () {
582 var div = createTestHtml(
583 '<template repeat="{{ contacts }}">'
584 'Hi {{ name }}'
585 '</template>');
586 var m = toSymbols({
587 'contacts': [
588 {'name': 'Raf'},
589 {'name': 'Arv'},
590 {'name': 'Neal'}
591 ]
592 });
593 recursivelySetTemplateModel(div, m);
594
595 deliverChanges(m);
596 var t = div.nodes.first;
597
598 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
599 });
600
601 test('RepeatEmptyPath', () {
602 var div = createTestHtml('<template repeat="{{}}">Hi {{ name }}</template>') ;
603 var t = div.nodes.first;
604
605 var m = toSymbols([
606 {'name': 'Raf'},
607 {'name': 'Arv'},
608 {'name': 'Neal'}
609 ]);
610 recursivelySetTemplateModel(div, m);
611
612 deliverChanges(m);
613
614 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
615
616 m.add(toSymbols({'name': 'Alex'}));
617 deliverChanges(m);
618 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
619
620 m.replaceRange(0, 2, toSymbols([{'name': 'Rafael'}, {'name': 'Erik'}]));
621 deliverChanges(m);
622 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
623
624 m.removeRange(1, 3);
625 deliverChanges(m);
626 assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
627
628 m.insertAll(1, toSymbols([{'name': 'Erik'}, {'name': 'Dimitri'}]));
629 deliverChanges(m);
630 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
631
632 m.replaceRange(0, 1, toSymbols([{'name': 'Tab'}, {'name': 'Neal'}]));
633 deliverChanges(m);
634 assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri', 'Hi Alex' ]);
635
636 m.length = 0;
637 m.add(toSymbols({'name': 'Alex'}));
638 deliverChanges(m);
639 assertNodesAre(div, ['Hi Alex']);
640 });
641
642 test('RepeatNullModel', () {
643 var div = createTestHtml('<template repeat="{{}}">Hi {{ name }}</template>') ;
644 var t = div.nodes.first;
645
646 var m = null;
647 recursivelySetTemplateModel(div, m);
648
649 expect(div.nodes.length, 1);
650
651 t.attributes['iterate'] = '';
652 m = toSymbols({});
653 recursivelySetTemplateModel(div, m);
654
655 deliverChanges(m);
656 expect(div.nodes.length, 1);
657 });
658
659 test('RepeatReuse', () {
660 var div = createTestHtml('<template repeat="{{}}">Hi {{ name }}</template>') ;
661 var t = div.nodes.first;
662
663 var m = toSymbols([
664 {'name': 'Raf'},
665 {'name': 'Arv'},
666 {'name': 'Neal'}
667 ]);
668 recursivelySetTemplateModel(div, m);
669 deliverChanges(m);
670
671 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
672 var node1 = div.nodes[1];
673 var node2 = div.nodes[2];
674 var node3 = div.nodes[3];
675
676 m.replaceRange(1, 2, toSymbols([{'name': 'Erik'}]));
677 deliverChanges(m);
678 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
679 expect(div.nodes[1], node1,
680 reason: 'model[0] did not change so the node should not have changed');
681 expect(div.nodes[2], isNot(equals(node2)),
682 reason: 'Should not reuse when replacing');
683 expect(div.nodes[3], node3,
684 reason: 'model[2] did not change so the node should not have changed');
685
686 node2 = div.nodes[2];
687 m.insert(0, toSymbols({'name': 'Alex'}));
688 deliverChanges(m);
689 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
690 });
691
692 test('TwoLevelsDeepBug', () {
693 var div = createTestHtml(
694 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>');
695
696 var model = toSymbolMap({'foo': 'bar'});
697 recursivelySetTemplateModel(div, model);
698 deliverChanges(model);
699
700 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
701 });
702
703 test('Checked', () {
704 var div = createTestHtml(
705 '<template>'
706 '<input type="checkbox" checked="{{a}}">'
707 '</template>');
708 var t = div.nodes.first;
709 var m = toSymbols({
710 'a': true
711 });
712 t.bind('bind', m, '');
713 deliverChanges(m);
714
715 var instanceInput = t.nextNode;
716 expect(instanceInput.checked, true);
717
718 instanceInput.click();
719 expect(instanceInput.checked, false);
720
721 instanceInput.click();
722 expect(instanceInput.checked, true);
723 });
724
725 nestedHelper(s, start) {
726 var div = createTestHtml(s);
727
728 var m = toSymbols({
729 'a': {
730 'b': 1,
731 'c': {'d': 2}
732 },
733 });
734
735 recursivelySetTemplateModel(div, m);
736 deliverChanges(m);
737
738 var i = start;
739 expect(div.nodes[i++].text, '1');
740 expect(div.nodes[i++].tagName, 'TEMPLATE');
741 expect(div.nodes[i++].text, '2');
742
743 m[sym('a')][sym('b')] = 11;
744 deliverChanges(m);
745 expect(div.nodes[start].text, '11');
746
747 m[sym('a')][sym('c')] = toSymbols({'d': 22});
748 deliverChanges(m);
749 expect(div.nodes[start + 2].text, '22');
750 }
751
752 test('Nested', () {
753 nestedHelper(
754 '<template bind="{{a}}">'
755 '{{b}}'
756 '<template bind="{{c}}">'
757 '{{d}}'
758 '</template>'
759 '</template>', 1);
760 });
761
762 test('NestedWithRef', () {
763 nestedHelper(
764 '<template id="inner">{{d}}</template>'
765 '<template id="outer" bind="{{a}}">'
766 '{{b}}'
767 '<template ref="inner" bind="{{c}}"></template>'
768 '</template>', 2);
769 });
770
771 nestedIterateInstantiateHelper(s, start) {
772 var div = createTestHtml(s);
773
774 var m = toSymbols({
775 'a': [
776 {
777 'b': 1,
778 'c': {'d': 11}
779 },
780 {
781 'b': 2,
782 'c': {'d': 22}
783 }
784 ]
785 });
786
787 recursivelySetTemplateModel(div, m);
788 deliverChanges(m);
789
790 var i = start;
791 expect(div.nodes[i++].text, '1');
792 expect(div.nodes[i++].tagName, 'TEMPLATE');
793 expect(div.nodes[i++].text, '11');
794 expect(div.nodes[i++].text, '2');
795 expect(div.nodes[i++].tagName, 'TEMPLATE');
796 expect(div.nodes[i++].text, '22');
797
798 m[sym('a')][1] = toSymbols({
799 'b': 3,
800 'c': {'d': 33}
801 });
802
803 deliverChanges(m);
804 expect(div.nodes[start + 3].text, '3');
805 expect(div.nodes[start + 5].text, '33');
806 }
807
808 test('NestedRepeatBind', () {
809 nestedIterateInstantiateHelper(
810 '<template repeat="{{a}}">'
811 '{{b}}'
812 '<template bind="{{c}}">'
813 '{{d}}'
814 '</template>'
815 '</template>', 1);
816 });
817
818 test('NestedRepeatBindWithRef', () {
819 nestedIterateInstantiateHelper(
820 '<template id="inner">'
821 '{{d}}'
822 '</template>'
823 '<template repeat="{{a}}">'
824 '{{b}}'
825 '<template ref="inner" bind="{{c}}"></template>'
826 '</template>', 2);
827 });
828
829 nestedIterateIterateHelper(s, start) {
830 var div = createTestHtml(s);
831
832 var m = toSymbols({
833 'a': [
834 {
835 'b': 1,
836 'c': [{'d': 11}, {'d': 12}]
837 },
838 {
839 'b': 2,
840 'c': [{'d': 21}, {'d': 22}]
841 }
842 ]
843 });
844
845 recursivelySetTemplateModel(div, m);
846 deliverChanges(m);
847
848 var i = start;
849 expect(div.nodes[i++].text, '1');
850 expect(div.nodes[i++].tagName, 'TEMPLATE');
851 expect(div.nodes[i++].text, '11');
852 expect(div.nodes[i++].text, '12');
853 expect(div.nodes[i++].text, '2');
854 expect(div.nodes[i++].tagName, 'TEMPLATE');
855 expect(div.nodes[i++].text, '21');
856 expect(div.nodes[i++].text, '22');
857
858 m[sym('a')][1] = toSymbols({
859 'b': 3,
860 'c': [{'d': 31}, {'d': 32}, {'d': 33}]
861 });
862
863 i = start + 4;
864 deliverChanges(m);
865 expect(div.nodes[start + 4].text, '3');
866 expect(div.nodes[start + 6].text, '31');
867 expect(div.nodes[start + 7].text, '32');
868 expect(div.nodes[start + 8].text, '33');
869 }
870
871 test('NestedRepeatBind', () {
872 nestedIterateIterateHelper(
873 '<template repeat="{{a}}">'
874 '{{b}}'
875 '<template repeat="{{c}}">'
876 '{{d}}'
877 '</template>'
878 '</template>', 1);
879 });
880
881 test('NestedRepeatRepeatWithRef', () {
882 nestedIterateIterateHelper(
883 '<template id="inner">'
884 '{{d}}'
885 '</template>'
886 '<template repeat="{{a}}">'
887 '{{b}}'
888 '<template ref="inner" repeat="{{c}}"></template>'
889 '</template>', 2);
890 });
891
892 test('NestedRepeatSelfRef', () {
893 var div = createTestHtml(
894 '<template id="t" repeat="{{}}">'
895 '{{name}}'
896 '<template ref="t" repeat="{{items}}"></template>'
897 '</template>');
898
899 var m = toSymbols([
900 {
901 'name': 'Item 1',
902 'items': [
903 {
904 'name': 'Item 1.1',
905 'items': [
906 {
907 'name': 'Item 1.1.1',
908 'items': []
909 }
910 ]
911 },
912 {
913 'name': 'Item 1.2'
914 }
915 ]
916 },
917 {
918 'name': 'Item 2',
919 'items': []
920 },
921 ]);
922
923 recursivelySetTemplateModel(div, m);
924 deliverChanges(m);
925
926 var i = 1;
927 expect(div.nodes[i++].text, 'Item 1');
928 expect(div.nodes[i++].tagName, 'TEMPLATE');
929 expect(div.nodes[i++].text, 'Item 1.1');
930 expect(div.nodes[i++].tagName, 'TEMPLATE');
931 expect(div.nodes[i++].text, 'Item 1.1.1');
932 expect(div.nodes[i++].tagName, 'TEMPLATE');
933 expect(div.nodes[i++].text, 'Item 1.2');
934 expect(div.nodes[i++].tagName, 'TEMPLATE');
935 expect(div.nodes[i++].text, 'Item 2');
936
937 m[0] = toSymbols({'name': 'Item 1 changed'});
938
939 i = 1;
940 deliverChanges(m);
941 expect(div.nodes[i++].text, 'Item 1 changed');
942 expect(div.nodes[i++].tagName, 'TEMPLATE');
943 expect(div.nodes[i++].text, 'Item 2');
944 });
945
946 test('NestedIterateTableMixedSemanticNative', () {
947 if (!TemplateElement.supported) return;
948
949 var div = createTestHtml(
950 '<table><tbody>'
951 '<template repeat="{{}}">'
952 '<tr>'
953 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>'
954 '</tr>'
955 '</template>'
956 '</tbody></table>');
957
958 var m = toSymbols([
959 [{ 'val': 0 }, { 'val': 1 }],
960 [{ 'val': 2 }, { 'val': 3 }]
961 ]);
962
963 recursivelySetTemplateModel(div, m);
964 deliverChanges(m);
965
966 var tbody = div.nodes[0].nodes[0];
967
968 // 1 for the <tr template>, 2 * (1 tr)
969 expect(tbody.nodes.length, 3);
970
971 // 1 for the <td template>, 2 * (1 td)
972 expect(tbody.nodes[1].nodes.length, 3);
973
974 expect(tbody.nodes[1].nodes[1].text, '0');
975 expect(tbody.nodes[1].nodes[2].text, '1');
976
977 // 1 for the <td template>, 2 * (1 td)
978 expect(tbody.nodes[2].nodes.length, 3);
979 expect(tbody.nodes[2].nodes[1].text, '2');
980 expect(tbody.nodes[2].nodes[2].text, '3');
981
982 // Asset the 'class' binding is retained on the semantic template (just
983 // check the last one).
984 expect(tbody.nodes[2].nodes[2].attributes["class"], '3');
985 });
986
987 test('NestedIterateTable', () {
988 var div = createTestHtml(
989 '<table><tbody>'
990 '<tr template repeat="{{}}">'
991 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>'
992 '</tr>'
993 '</tbody></table>');
994
995 var m = toSymbols([
996 [{ 'val': 0 }, { 'val': 1 }],
997 [{ 'val': 2 }, { 'val': 3 }]
998 ]);
999
1000 recursivelySetTemplateModel(div, m);
1001 deliverChanges(m);
1002
1003 var i = 1;
1004 var tbody = div.nodes[0].nodes[0];
1005
1006 // 1 for the <tr template>, 2 * (1 tr)
1007 expect(tbody.nodes.length, 3);
1008
1009 // 1 for the <td template>, 2 * (1 td)
1010 expect(tbody.nodes[1].nodes.length, 3);
1011 expect(tbody.nodes[1].nodes[1].text, '0');
1012 expect(tbody.nodes[1].nodes[2].text, '1');
1013
1014 // 1 for the <td template>, 2 * (1 td)
1015 expect(tbody.nodes[2].nodes.length, 3);
1016 expect(tbody.nodes[2].nodes[1].text, '2');
1017 expect(tbody.nodes[2].nodes[2].text, '3');
1018
1019 // Asset the 'class' binding is retained on the semantic template (just chec k
1020 // the last one).
1021 expect(tbody.nodes[2].nodes[2].attributes['class'], '3');
1022 });
1023
1024 test('NestedRepeatDeletionOfMultipleSubTemplates', () {
1025 var div = createTestHtml(
1026 '<ul>'
1027 '<template repeat="{{}}" id=t1>'
1028 '<li>{{name}}'
1029 '<ul>'
1030 '<template ref=t1 repaet="{{items}}"></template>'
1031 '</ul>'
1032 '</li>'
1033 '</template>'
1034 '</ul>');
1035
1036 var m = toSymbols([
1037 {
1038 'name': 'Item 1',
1039 'items': [
1040 {
1041 'name': 'Item 1.1'
1042 }
1043 ]
1044 }
1045 ]);
1046
1047 recursivelySetTemplateModel(div, m);
1048
1049 deliverChanges(m);
1050 m.removeAt(0);
1051 deliverChanges(m);
1052 });
1053
1054 test('DeepNested', () {
1055 var div = createTestHtml(
1056 '<template bind="{{a}}">'
1057 '<p>'
1058 '<template bind="{{b}}">'
1059 '{{ c }}'
1060 '</template>'
1061 '</p>'
1062 '</template>');
1063
1064 var m = toSymbols({
1065 'a': {
1066 'b': {
1067 'c': 42
1068 }
1069 }
1070 });
1071 recursivelySetTemplateModel(div, m);
1072 deliverChanges(m);
1073
1074 expect(div.nodes[1].tagName, 'P');
1075 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
1076 expect(div.nodes[1].nodes[1].text, '42');
1077 });
1078
1079 test('TemplateContentRemoved', () {
1080 var div = createTestHtml('<template bind="{{}}">{{ }}</template>');
1081 var model = 42;
1082
1083 recursivelySetTemplateModel(div, model);
1084 deliverChanges(model);
1085 expect(div.nodes[1].text, '42');
1086 expect(div.nodes[0].text, '');
1087 });
1088
1089 test('TemplateContentRemovedEmptyArray', () {
1090 var div = createTestHtml('<template iterate>Remove me</template>');
1091 var model = toSymbols([]);
1092
1093 recursivelySetTemplateModel(div, model);
1094 deliverChanges(model);
1095 expect(div.nodes.length, 1);
1096 expect(div.nodes[0].text, '');
1097 });
1098
1099 test('TemplateContentRemovedNested', () {
1100 var div = createTestHtml(
1101 '<template bind="{{}}">'
1102 '{{ a }}'
1103 '<template bind="{{}}">'
1104 '{{ b }}'
1105 '</template>'
1106 '</template>');
1107
1108 var model = toSymbolMap({
1109 'a': 1,
1110 'b': 2
1111 });
1112 recursivelySetTemplateModel(div, model);
1113 deliverChanges(model);
1114
1115 expect(div.nodes[0].text, '');
1116 expect(div.nodes[1].text, '1');
1117 expect(div.nodes[2].text, '');
1118 expect(div.nodes[3].text, '2');
1119 });
1120
1121 test('BindWithUndefinedModel', () {
1122 var div = createTestHtml(
1123 '<template bind="{{}}" if="{{}}">{{ a }}</template>');
1124
1125 var model = toSymbolMap({'a': 42});
1126 recursivelySetTemplateModel(div, model);
1127 deliverChanges(model);
1128 expect(div.nodes[1].text, '42');
1129
1130 model = null;
1131 recursivelySetTemplateModel(div, model);
1132 deliverChanges(model);
1133 expect(div.nodes.length, 1);
1134
1135 model = toSymbols({'a': 42});
1136 recursivelySetTemplateModel(div, model);
1137 deliverChanges(model);
1138 expect(div.nodes[1].text, '42');
1139 });
1140
1141 test('BindNested', () {
1142 var div = createTestHtml(
1143 '<template bind="{{}}">'
1144 'Name: {{ name }}'
1145 '<template bind="{{wife}}" if="{{wife}}">'
1146 'Wife: {{ name }}'
1147 '</template>'
1148 '<template bind="{{child}}" if="{{child}}">'
1149 'Child: {{ name }}'
1150 '</template>'
1151 '</template>');
1152
1153 var m = toSymbols({
1154 'name': 'Hermes',
1155 'wife': {
1156 'name': 'LaBarbara'
1157 }
1158 });
1159 recursivelySetTemplateModel(div, m);
1160 deliverChanges(m);
1161
1162 expect(div.nodes.length, 5);
1163 expect(div.nodes[1].text, 'Name: Hermes');
1164 expect(div.nodes[3].text, 'Wife: LaBarbara');
1165
1166 m[sym('child')] = toSymbols({'name': 'Dwight'});
1167 deliverChanges(m);
1168 expect(div.nodes.length, 6);
1169 expect(div.nodes[5].text, 'Child: Dwight');
1170
1171 m.remove(sym('wife'));
1172 deliverChanges(m);
1173 expect(div.nodes.length, 5);
1174 expect(div.nodes[4].text, 'Child: Dwight');
1175 });
1176
1177 test('BindRecursive', () {
1178 var div = createTestHtml(
1179 '<template bind="{{}}" if="{{}}" id="t">'
1180 'Name: {{ name }}'
1181 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>'
1182 '</template>');
1183
1184 var m = toSymbols({
1185 'name': 'Fry',
1186 'friend': {
1187 'name': 'Bender'
1188 }
1189 });
1190 recursivelySetTemplateModel(div, m);
1191 deliverChanges(m);
1192
1193 expect(div.nodes.length, 5);
1194 expect(div.nodes[1].text, 'Name: Fry');
1195 expect(div.nodes[3].text, 'Name: Bender');
1196
1197 m[sym('friend')][sym('friend')] = toSymbols({'name': 'Leela'});
1198 deliverChanges(m);
1199 expect(div.nodes.length, 7);
1200 expect(div.nodes[5].text, 'Name: Leela');
1201
1202 m[sym('friend')] = toSymbols({'name': 'Leela'});
1203 deliverChanges(m);
1204 expect(div.nodes.length, 5);
1205 expect(div.nodes[3].text, 'Name: Leela');
1206 });
1207
1208 test('ChangeFromBindToRepeat', () {
1209 var div = createTestHtml(
1210 '<template bind="{{a}}">'
1211 '{{ length }}'
1212 '</template>');
1213 var template = div.nodes.first;
1214
1215 var m = toSymbols({
1216 'a': [
1217 {'length': 0},
1218 {
1219 'length': 1,
1220 'b': {'length': 4}
1221 },
1222 {'length': 2}
1223 ]
1224 });
1225 recursivelySetTemplateModel(div, m);
1226 deliverChanges(m);
1227
1228 expect(div.nodes.length, 2);
1229 expect(div.nodes[1].text, '3');
1230
1231 template.unbind('bind');
1232 template.bind('repeat', m, 'a');
1233 deliverChanges(m);
1234 expect(div.nodes.length, 4);
1235 expect(div.nodes[1].text, '0');
1236 expect(div.nodes[2].text, '1');
1237 expect(div.nodes[3].text, '2');
1238
1239 template.unbind('repeat');
1240 template.bind('bind', m, 'a.1.b');
1241
1242 deliverChanges(m);
1243 expect(div.nodes.length, 2);
1244 expect(div.nodes[1].text, '4');
1245 });
1246
1247 test('ChangeRefId', () {
1248 var div = createTestHtml(
1249 '<template id="a">a:{{ }}</template>'
1250 '<template id="b">b:{{ }}</template>'
1251 '<template repeat="{{}}">'
1252 '<template ref="a" bind="{{}}"></template>'
1253 '</template>');
1254 var model = toSymbols([]);
1255 recursivelySetTemplateModel(div, model);
1256 deliverChanges(model);
1257
1258 expect(div.nodes.length, 3);
1259
1260 document.getElementById('a').id = 'old-a';
1261 document.getElementById('b').id = 'a';
1262
1263 model..add(1)..add(2);
1264 deliverChanges(model);
1265
1266 expect(div.nodes.length, 7);
1267 expect(div.nodes[4].text, 'b:1');
1268 expect(div.nodes[6].text, 'b:2');
1269 });
1270
1271 test('Content', () {
1272 var div = createTestHtml(
1273 '<template><a></a></template>'
1274 '<template><b></b></template>');
1275 var templateA = div.nodes.first;
1276 var templateB = div.nodes.last;
1277 var contentA = templateA.content;
1278 var contentB = templateB.content;
1279 expect(contentA, isNotNull);
1280
1281 expect(templateA.document, isNot(equals(contentA.document)));
1282 expect(templateB.document, isNot(equals(contentB.document)));
1283
1284 expect(templateB.document, templateA.document);
1285 expect(contentB.document, contentA.document);
1286
1287 expect(templateA.document.window, window);
1288 expect(templateB.document.window, window);
1289
1290 expect(contentA.document.window, null);
1291 expect(contentB.document.window, null);
1292
1293 expect(contentA.nodes.last, contentA.nodes.first);
1294 expect(contentA.nodes.first.tagName, 'A');
1295
1296 expect(contentB.nodes.last, contentB.nodes.first);
1297 expect(contentB.nodes.first.tagName, 'B');
1298 });
1299
1300 test('NestedContent', () {
1301 var div = createTestHtml(
1302 '<template>'
1303 '<template></template>'
1304 '</template>');
1305 var templateA = div.nodes.first;
1306 var templateB = templateA.content.nodes.first;
1307
1308 expect(templateB.document, templateA.content.document);
1309 expect(templateB.content.document, templateA.content.document);
1310 });
1311
1312 test('BindShadowDOM', () {
1313 if (ShadowRoot.supported) {
1314 var root = createShadowTestHtml(
1315 '<template bind="{{}}">Hi {{ name }}</template>');
1316 var model = toSymbolMap({'name': 'Leela'});
1317 recursivelySetTemplateModel(root, model);
1318 deliverChanges(model);
1319 expect(root.nodes[1].text, 'Hi Leela');
1320 }
1321 });
1322
1323 test('BindShadowDOM bindModel', () {
1324 if (ShadowRoot.supported) {
1325 var root = createShadowTestHtml('Hi {{ name }}');
1326 var model = toSymbolMap({'name': 'Leela'});
1327 TemplateElement.bindModel(root, model);
1328 deliverChangeRecords();
1329 expect(root.text, 'Hi Leela');
1330 }
1331 });
1332
1333 test('bindModel to polyfilled shadow root', () {
1334 var root = createTestHtml('Hi {{ name }}');
1335 var model = toSymbolMap({'name': 'Leela'});
1336 TemplateElement.bindModel(root, model);
1337 deliverChangeRecords();
1338 expect(root.text, 'Hi Leela');
1339 });
1340
1341 // https://github.com/toolkitchen/mdv/issues/8
1342 test('UnbindingInNestedBind', () {
1343 var div = createTestHtml(
1344 '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">'
1345 '<template bind="{{inner}}" if="{{inner}}">'
1346 '{{ age }}'
1347 '</template>'
1348 '</template>');
1349
1350 var syntax = new UnbindingInNestedBindSyntax();
1351 TemplateElement.syntax['testHelper'] = syntax;
1352 try {
1353 var model = toSymbolMap({
1354 'outer': {
1355 'inner': {
1356 'age': 42
1357 }
1358 }
1359 });
1360
1361 recursivelySetTemplateModel(div, model);
1362
1363 deliverChanges(model);
1364 expect(syntax.count, 1);
1365
1366 var inner = model[sym('outer')][sym('inner')];
1367 model[sym('outer')] = null;
1368
1369 deliverChanges(model);
1370 expect(syntax.count, 1);
1371
1372 model[sym('outer')] = toSymbols({'inner': {'age': 2}});
1373 syntax.expectedAge = 2;
1374
1375 deliverChanges(model);
1376 expect(syntax.count, 2);
1377 } finally {
1378 TemplateElement.syntax.remove('testHelper');
1379 }
1380 });
1381
1382 // https://github.com/toolkitchen/mdv/issues/8
1383 test('DontCreateInstancesForAbandonedIterators', () {
1384 var div = createTestHtml(
1385 '<template bind="{{}} {{}}">'
1386 '<template bind="{{}}">Foo'
1387 '</template>'
1388 '</template>');
1389 recursivelySetTemplateModel(div, null);
1390 // TODO(jmesserly): how to fix this test?
1391 // Perhaps revive the original?
1392 // https://github.com/toolkitchen/mdv/commit/8bc1e3466aeb6930150c0d3148f0e83 0184bf599#L3R1278
1393 //expect(!!ChangeSummary._errorThrownDuringCallback, false);
1394 });
1395
1396 test('CreateInstance', () {
1397 var div = createTestHtml(
1398 '<template bind="{{a}}">'
1399 '<template bind="{{b}}">'
1400 '{{text}}'
1401 '</template>'
1402 '</template>');
1403 var outer = div.nodes.first;
1404
1405 var instance = outer.createInstance();
1406 expect(outer.content.nodes.first, instance.nodes.first.ref);
1407
1408 var instance2 = outer.createInstance();
1409 expect(instance2.nodes.first.ref, instance.nodes.first.ref);
1410 });
1411
1412 test('Bootstrap', () {
1413 var div = new DivElement();
1414 div.innerHtml =
1415 '<template>'
1416 '<div></div>'
1417 '<template>'
1418 'Hello'
1419 '</template>'
1420 '</template>';
1421
1422 TemplateElement.bootstrap(div);
1423 var template = div.nodes.first;
1424 expect(template.content.nodes.length, 2);
1425 var template2 = template.content.nodes.first.nextNode;
1426 expect(template2.content.nodes.length, 1);
1427 expect(template2.content.nodes.first.text, 'Hello');
1428
1429 template = new Element.tag('template');
1430 template.innerHtml =
1431 '<template>'
1432 '<div></div>'
1433 '<template>'
1434 'Hello'
1435 '</template>'
1436 '</template>';
1437
1438 TemplateElement.bootstrap(template);
1439 template2 = template.content.nodes.first;
1440 expect(template2.content.nodes.length, 2);
1441 var template3 = template2.content.nodes.first.nextNode;
1442 expect(template3.content.nodes.length, 1);
1443 expect(template3.content.nodes.first.text, 'Hello');
1444 });
1445
1446 test('instanceCreated hack', () {
1447 var called = false;
1448 var sub = TemplateElement.instanceCreated.listen((node) {
1449 called = true;
1450 expect(node.nodeType, Node.DOCUMENT_FRAGMENT_NODE);
1451 });
1452
1453 var div = createTestHtml('<template bind="{{}}">Foo</template>');
1454 expect(called, false);
1455
1456 recursivelySetTemplateModel(div, null);
1457 deliverChangeRecords();
1458 expect(called, true);
1459
1460 sub.cancel();
1461 });
1462 }
1463
1464 class UnbindingInNestedBindSyntax extends CustomBindingSyntax {
1465 int expectedAge = 42;
1466 int count = 0;
1467
1468 getBinding(model, path, name, node) {
1469 if (name != 'text' || path != 'age')
1470 return;
1471
1472 expect(model[sym('age')], expectedAge);
1473 count++;
1474 }
1475 }
1476
1477 /** Verifies that the model is Observable, then calls [deliverChangeRecords]. */
1478 void deliverChanges(model) {
1479 expectObservable(model);
1480 deliverChangeRecords();
1481 }
1482
1483 void expectObservable(model) {
1484 if (model is! Observable) {
1485 // This is here to eagerly catch a bug in the test; it means the test
1486 // forgot a toSymbols somewhere.
1487 expect(identical(toSymbols(model), model), true,
1488 reason: 'model type "${model.runtimeType}" should be observable');
1489 return;
1490 }
1491 if (model is ObservableList) {
1492 for (var item in model) {
1493 expectObservable(item);
1494 }
1495 } else if (model is ObservableMap) {
1496 model.forEach((k, v) {
1497 expectObservable(k);
1498 expectObservable(v);
1499 });
1500 }
1501 }
1502
1503 toSymbols(obj) => toObservable(_deepToSymbol(obj));
1504
1505 sym(x) => new Symbol(x);
1506
1507 _deepToSymbol(value) {
1508 if (value is Map) {
1509 var result = new LinkedHashMap();
1510 value.forEach((k, v) {
1511 k = k is String ? sym(k) : _deepToSymbol(k);
1512 result[k] = _deepToSymbol(v);
1513 });
1514 return result;
1515 }
1516 if (value is Iterable) {
1517 return value.map(_deepToSymbol).toList();
1518 }
1519 return value;
1520 }
1521
OLDNEW
« no previous file with comments | « tests/html/node_bindings_test.dart ('k') | tools/create_sdk.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698