| Index: packages/template_binding/test/template_binding_test.dart | 
| diff --git a/packages/template_binding/test/template_binding_test.dart b/packages/template_binding/test/template_binding_test.dart | 
| deleted file mode 100644 | 
| index 4eae607809e1a6bced8ec3ccfad66ae1d485370d..0000000000000000000000000000000000000000 | 
| --- a/packages/template_binding/test/template_binding_test.dart | 
| +++ /dev/null | 
| @@ -1,2736 +0,0 @@ | 
| -// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
| -// for details. All rights reserved. Use of this source code is governed by a | 
| -// BSD-style license that can be found in the LICENSE file. | 
| - | 
| -library template_binding.test.template_binding_test; | 
| - | 
| -import 'dart:async'; | 
| -import 'dart:html'; | 
| -import 'dart:js' show JsObject; | 
| -import 'dart:math' as math; | 
| -import 'package:observe/observe.dart'; | 
| -import 'package:template_binding/template_binding.dart'; | 
| -import 'package:unittest/html_config.dart'; | 
| -import 'package:unittest/unittest.dart'; | 
| -import 'package:observe/mirrors_used.dart'; // make test smaller | 
| -import 'package:smoke/mirrors.dart' as smoke; | 
| - | 
| -// TODO(jmesserly): merge this file? | 
| -import 'binding_syntax.dart' show syntaxTests; | 
| -import 'utils.dart'; | 
| - | 
| -// Note: this file ported from TemplateBinding's tests/tests.js | 
| - | 
| -// TODO(jmesserly): submit a small cleanup patch to original. I fixed some | 
| -// cases where "div" and "t" were unintentionally using the JS global scope; | 
| -// look for "assertNodesAre". | 
| - | 
| -main() => dirtyCheckZone().run(() { | 
| -  smoke.useMirrors(); | 
| -  useHtmlConfiguration(); | 
| - | 
| -  setUp(() { | 
| -    document.body.append(testDiv = new DivElement()); | 
| -  }); | 
| - | 
| -  tearDown(() { | 
| -    testDiv.remove(); | 
| -    clearAllTemplates(testDiv); | 
| -    testDiv = null; | 
| -  }); | 
| - | 
| -  test('MutationObserver is supported', () { | 
| -    expect(MutationObserver.supported, true, reason: 'polyfill was loaded.'); | 
| -  }); | 
| - | 
| -  group('Template', templateInstantiationTests); | 
| - | 
| -  group('Binding Delegate API', () { | 
| -    group('with Observable', () { | 
| -      syntaxTests(([f, b]) => new FooBarModel(f, b)); | 
| -    }); | 
| - | 
| -    group('with ChangeNotifier', () { | 
| -      syntaxTests(([f, b]) => new FooBarNotifyModel(f, b)); | 
| -    }); | 
| -  }); | 
| - | 
| -  group('Compat', compatTests); | 
| -}); | 
| - | 
| -var expando = new Expando('test'); | 
| -void addExpandos(node) { | 
| -  while (node != null) { | 
| -    expando[node] = node.text; | 
| -    node = node.nextNode; | 
| -  } | 
| -} | 
| - | 
| -void checkExpandos(node) { | 
| -  expect(node, isNotNull); | 
| -  while (node != null) { | 
| -    expect(expando[node], node.text); | 
| -    node = node.nextNode; | 
| -  } | 
| -} | 
| - | 
| -templateInstantiationTests() { | 
| -  // Dart note: renamed some of these tests to have unique names | 
| - | 
| -  test('accessing bindingDelegate getter without Bind', () { | 
| -    var div = createTestHtml('<template>'); | 
| -    var template = div.firstChild; | 
| -    expect(templateBind(template).bindingDelegate, null); | 
| -  }); | 
| - | 
| -  test('Bind - simple', () { | 
| -    var div = createTestHtml('<template bind={{}}>text</template>'); | 
| -    templateBind(div.firstChild).model = {}; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'text'); | 
| - | 
| -      // Dart note: null is used instead of undefined to clear the template. | 
| -      templateBind(div.firstChild).model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -      templateBind(div.firstChild).model = 123; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'text'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('oneTime-Bind', () { | 
| -    var div = createTestHtml('<template bind="[[ bound ]]">text</template>'); | 
| -    var model = toObservable({'bound': 1}); | 
| -    templateBind(div.firstChild).model = model; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'text'); | 
| - | 
| -      model['bound'] = false; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'text'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind - no parent', () { | 
| -    var div = createTestHtml('<template bind>text</template>'); | 
| -    var template = div.firstChild; | 
| -    template.remove(); | 
| - | 
| -    templateBind(template).model = {}; | 
| -    return new Future(() { | 
| -      expect(template.nodes.length, 0); | 
| -      expect(template.nextNode, null); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind - no defaultView', () { | 
| -    var div = createTestHtml('<template bind>text</template>'); | 
| -    var template = div.firstChild; | 
| -    var doc = document.implementation.createHtmlDocument(''); | 
| -    doc.adoptNode(div); | 
| -    templateBind(template).model = {}; | 
| -    return new Future(() => expect(div.nodes.length, 2)); | 
| -  }); | 
| - | 
| -  test('Empty Bind', () { | 
| -    var div = createTestHtml('<template bind>text</template>'); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = {}; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'text'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind If', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ bound }}" if="{{ predicate }}">' | 
| -          'value:{{ value }}' | 
| -        '</template>'); | 
| -    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart. | 
| -    // See https://code.google.com/p/dart/issues/detail?id=11956 | 
| -    // Changed bound from null->1 since null is equivalent to JS undefined, | 
| -    // and would cause the template to not be expanded. | 
| -    var m = toObservable({ 'predicate': null, 'bound': 1 }); | 
| -    var template = div.firstChild; | 
| -    bool errorSeen = false; | 
| -    runZoned(() { | 
| -      templateBind(template).model = m; | 
| -    }, onError: (e, s) { | 
| -      _expectNoSuchMethod(e); | 
| -      errorSeen = true; | 
| -    }); | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['predicate'] = 1; | 
| - | 
| -      expect(errorSeen, isFalse); | 
| -    }).then(nextMicrotask).then((_) { | 
| -      expect(errorSeen, isTrue); | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['bound'] = toObservable({ 'value': 2 }); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:2'); | 
| - | 
| -      m['bound']['value'] = 3; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      templateBind(template).model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind oneTime-If - predicate false', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ bound }}" if="[[ predicate ]]">' | 
| -          'value:{{ value }}' | 
| -        '</template>'); | 
| -    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart. | 
| -    // See https://code.google.com/p/dart/issues/detail?id=11956 | 
| -    // Changed bound from null->1 since null is equivalent to JS undefined, | 
| -    // and would cause the template to not be expanded. | 
| -    var m = toObservable({ 'predicate': null, 'bound': 1 }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['predicate'] = 1; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['bound'] = toObservable({ 'value': 2 }); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['bound']['value'] = 3; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      templateBind(template).model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind oneTime-If - predicate true', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ bound }}" if="[[ predicate ]]">' | 
| -          'value:{{ value }}' | 
| -        '</template>'); | 
| - | 
| -    // Dart note: changed bound from null->1 since null is equivalent to JS | 
| -    // undefined, and would cause the template to not be expanded. | 
| -    var m = toObservable({ 'predicate': 1, 'bound': 1 }); | 
| -    var template = div.firstChild; | 
| -    bool errorSeen = false; | 
| -    runZoned(() { | 
| -      templateBind(template).model = m; | 
| -    }, onError: (e, s) { | 
| -      _expectNoSuchMethod(e); | 
| -      errorSeen = true; | 
| -    }); | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| -      m['bound'] = toObservable({ 'value': 2 }); | 
| -      expect(errorSeen, isTrue); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:2'); | 
| - | 
| -      m['bound']['value'] = 3; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      m['predicate'] = null; // will have no effect | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      templateBind(template).model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('oneTime-Bind If', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="[[ bound ]]" if="{{ predicate }}">' | 
| -          'value:{{ value }}' | 
| -        '</template>'); | 
| - | 
| -    var m = toObservable({'predicate': null, 'bound': {'value': 2}}); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['predicate'] = 1; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:2'); | 
| - | 
| -      m['bound']['value'] = 3; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      m['bound'] = toObservable({'value': 4 }); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      templateBind(template).model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('oneTime-Bind oneTime-If', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="[[ bound ]]" if="[[ predicate ]]">' | 
| -          'value:{{ value }}' | 
| -        '</template>'); | 
| - | 
| -    var m = toObservable({'predicate': 1, 'bound': {'value': 2}}); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:2'); | 
| - | 
| -      m['bound']['value'] = 3; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      m['bound'] = toObservable({'value': 4 }); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      m['predicate'] = false; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      templateBind(template).model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind If, 2', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['bar'] = 1; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'baz'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('If', () { | 
| -    var div = createTestHtml('<template if="{{ foo }}">{{ value }}</template>'); | 
| -    // Dart note: foo changed from 0->null because 0 isn't falsey in Dart. | 
| -    // See https://code.google.com/p/dart/issues/detail?id=11956 | 
| -    var m = toObservable({ 'foo': null, 'value': 'foo' }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['foo'] = 1; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'foo'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind If minimal discardChanges', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{bound}}" if="{{predicate}}">value:{{ value }}' | 
| -        '</template>'); | 
| -    // Dart Note: bound changed from null->{}. | 
| -    var m = toObservable({ 'bound': {}, 'predicate': null }); | 
| -    var template = div.firstChild; | 
| - | 
| -    var discardChangesCalled = { 'bound': 0, 'predicate': 0 }; | 
| -    templateBind(template) | 
| -        ..model = m | 
| -        ..bindingDelegate = | 
| -            new BindIfMinimalDiscardChanges(discardChangesCalled); | 
| - | 
| -    return new Future(() { | 
| -      expect(discardChangesCalled['bound'], 0); | 
| -      expect(discardChangesCalled['predicate'], 0); | 
| -      expect(div.childNodes.length, 1); | 
| -      m['predicate'] = 1; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(discardChangesCalled['bound'], 1); | 
| -      expect(discardChangesCalled['predicate'], 0); | 
| - | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:'); | 
| - | 
| -      m['bound'] = toObservable({'value': 2}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(discardChangesCalled['bound'], 1); | 
| -      expect(discardChangesCalled['predicate'], 1); | 
| - | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:2'); | 
| - | 
| -      m['bound']['value'] = 3; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(discardChangesCalled['bound'], 1); | 
| -      expect(discardChangesCalled['predicate'], 1); | 
| - | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'value:3'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(discardChangesCalled['bound'], 1); | 
| -      expect(discardChangesCalled['predicate'], 1); | 
| - | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| - | 
| -  test('Empty-If', () { | 
| -    var div = createTestHtml('<template if>{{ value }}</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'value': 'foo' }); | 
| -    templateBind(template).model = null; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      templateBind(template).model = m; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'foo'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('OneTime - simple text', () { | 
| -    var div = createTestHtml('<template bind>[[ value ]]</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'value': 'foo' }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'foo'); | 
| - | 
| -      m['value'] = 'bar'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // unchanged. | 
| -      expect(div.lastChild.text, 'foo'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('OneTime - compound text', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>[[ foo ]] bar [[ baz ]]</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'FOO bar BAZ'); | 
| - | 
| -      m['foo'] = 'FI'; | 
| -      m['baz'] = 'BA'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // unchanged. | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'FOO bar BAZ'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('OneTime/Dynamic Mixed - compound text', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>[[ foo ]] bar {{ baz }}</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'FOO bar BAZ'); | 
| - | 
| -      m['foo'] = 'FI'; | 
| -      m['baz'] = 'BA'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // unchanged [[ foo ]]. | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.text, 'FOO bar BA'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('OneTime - simple attribute', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind><div foo="[[ value ]]"></div></template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'value': 'foo' }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.attributes['foo'], 'foo'); | 
| - | 
| -      m['value'] = 'bar'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // unchanged. | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.attributes['foo'], 'foo'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('OneTime - compound attribute', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<div foo="[[ value ]]:[[ otherValue ]]"></div>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.attributes['foo'], 'foo:bar'); | 
| - | 
| -      m['value'] = 'baz'; | 
| -      m['otherValue'] = 'bot'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // unchanged. | 
| -      expect(div.lastChild.attributes['foo'], 'foo:bar'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('OneTime/Dynamic mixed - compound attribute', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<div foo="{{ value }}:[[ otherValue ]]"></div>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.lastChild.attributes['foo'], 'foo:bar'); | 
| - | 
| -      m['value'] = 'baz'; | 
| -      m['otherValue'] = 'bot'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // unchanged [[ otherValue ]]. | 
| -      expect(div.lastChild.attributes['foo'], 'baz:bar'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat If', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{ items }}" if="{{ predicate }}">{{}}</template>'); | 
| -    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart. | 
| -    // See https://code.google.com/p/dart/issues/detail?id=11956 | 
| -    var m = toObservable({ 'predicate': null, 'items': [1] }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['predicate'] = 1; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['items']..add(2)..add(3); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[1].text, '1'); | 
| -      expect(div.nodes[2].text, '2'); | 
| -      expect(div.nodes[3].text, '3'); | 
| - | 
| -      m['items'] = [4]; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '4'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat oneTime-If (predicate false)', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{ items }}" if="[[ predicate ]]">{{}}</template>'); | 
| -    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart. | 
| -    // See https://code.google.com/p/dart/issues/detail?id=11956 | 
| -    var m = toObservable({ 'predicate': null, 'items': [1] }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['predicate'] = 1; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1, reason: 'unchanged'); | 
| - | 
| -      m['items']..add(2)..add(3); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1, reason: 'unchanged'); | 
| - | 
| -      m['items'] = [4]; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1, reason: 'unchanged'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat oneTime-If (predicate true)', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{ items }}" if="[[ predicate ]]">{{}}</template>'); | 
| - | 
| -    var m = toObservable({ 'predicate': true, 'items': [1] }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['items']..add(2)..add(3); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[1].text, '1'); | 
| -      expect(div.nodes[2].text, '2'); | 
| -      expect(div.nodes[3].text, '3'); | 
| - | 
| -      m['items'] = [4]; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '4'); | 
| - | 
| -      m['predicate'] = false; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2, reason: 'unchanged'); | 
| -      expect(div.nodes[1].text, '4', reason: 'unchanged'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('oneTime-Repeat If', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="[[ items ]]" if="{{ predicate }}">{{}}</template>'); | 
| - | 
| -    var m = toObservable({ 'predicate': false, 'items': [1] }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      m['predicate'] = true; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['items']..add(2)..add(3); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['items'] = [4]; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('oneTime-Repeat oneTime-If', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="[[ items ]]" if="[[ predicate ]]">{{}}</template>'); | 
| - | 
| -    var m = toObservable({ 'predicate': true, 'items': [1] }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['items']..add(2)..add(3); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['items'] = [4]; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      m['predicate'] = false; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes[1].text, '1'); | 
| - | 
| -      templateBind(template).model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TextTemplateWithNullStringBinding', () { | 
| -    var div = createTestHtml('<template bind={{}}>a{{b}}c</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'b': 'B'}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'aBc'); | 
| - | 
| -      model['b'] = 'b'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'abc'); | 
| - | 
| -      model['b'] = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'ac'); | 
| - | 
| -      model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      // setting model isn't bindable. | 
| -      expect(div.nodes.last.text, 'ac'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TextTemplateWithBindingPath', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ data }}">a{{b}}c</template>'); | 
| -    var model = toObservable({ 'data': {'b': 'B'} }); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'aBc'); | 
| - | 
| -      model['data']['b'] = 'b'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'abc'); | 
| - | 
| -      model['data'] = toObservable({'b': 'X'}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'aXc'); | 
| - | 
| -      // Dart note: changed from `null` since our null means don't render a model. | 
| -      model['data'] = toObservable({}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'ac'); | 
| - | 
| -      model['data'] = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TextTemplateWithBindingAndConditional', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'b': 'B', 'd': 1}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'aBc'); | 
| - | 
| -      model['b'] = 'b'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'abc'); | 
| - | 
| -      // TODO(jmesserly): MDV set this to empty string and relies on JS conversion | 
| -      // rules. Is that intended? | 
| -      // See https://github.com/Polymer/TemplateBinding/issues/59 | 
| -      model['d'] = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      model['d'] = 'here'; | 
| -      model['b'] = 'd'; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'adc'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateWithTextBinding2', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ b }}">a{{value}}c</template>'); | 
| -    expect(div.nodes.length, 1); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'b': {'value': 'B'}}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.text, 'aBc'); | 
| - | 
| -      model['b'] = toObservable({'value': 'b'}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.text, 'abc'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateWithAttributeBinding', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}">' | 
| -        '<div foo="a{{b}}c"></div>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'b': 'B'}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.attributes['foo'], 'aBc'); | 
| - | 
| -      model['b'] = 'b'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.attributes['foo'], 'abc'); | 
| - | 
| -      model['b'] = 'X'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.attributes['foo'], 'aXc'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateWithConditionalBinding', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}">' | 
| -        '<div foo?="{{b}}"></div>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'b': 'b'}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.attributes['foo'], ''); | 
| -      expect(div.nodes.last.attributes, isNot(contains('foo?'))); | 
| - | 
| -      model['b'] = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.attributes, isNot(contains('foo'))); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{ array }}">{{}},</template>'); | 
| - | 
| -    var model = toObservable({'array': [0, 1, 2]}); | 
| -    var template = templateBind(div.firstChild); | 
| -    template.model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.text, '0,1,2,'); | 
| - | 
| -      model['array'].length = 1; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.text, '0,'); | 
| - | 
| -      model['array'].addAll([3, 4]); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.text, '0,3,4,'); | 
| - | 
| -      model['array'].removeRange(1, 2); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 3); | 
| -      expect(div.text, '0,4,'); | 
| - | 
| -      model['array'].addAll([5, 6]); | 
| -      model['array'] = toObservable(['x', 'y']); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 3); | 
| -      expect(div.text, 'x,y,'); | 
| - | 
| -      template.model = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -      expect(div.text, ''); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat - oneTime', () { | 
| -    var div = createTestHtml('<template repeat="[[]]">text</template>'); | 
| - | 
| -    var model = toObservable([0, 1, 2]); | 
| -    var template = templateBind(div.firstChild); | 
| -    template.model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      model.length = 1; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      model.addAll([3, 4]); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      model.removeRange(1, 2); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      template.model = null; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat - Reuse Instances', () { | 
| -    var div = createTestHtml('<template repeat>{{ val }}</template>'); | 
| - | 
| -    var model = toObservable([ | 
| -      {'val': 10}, | 
| -      {'val': 5}, | 
| -      {'val': 2}, | 
| -      {'val': 8}, | 
| -      {'val': 1} | 
| -    ]); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 6); | 
| - | 
| -      addExpandos(template.nextNode); | 
| -      checkExpandos(template.nextNode); | 
| - | 
| -      model.sort((a, b) => a['val'] - b['val']); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      checkExpandos(template.nextNode); | 
| - | 
| -      model = toObservable(model.reversed); | 
| -      templateBind(template).model = model; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      checkExpandos(template.nextNode); | 
| - | 
| -      for (var item in model) { | 
| -        item['val'] += 1; | 
| -      } | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[1].text, "11"); | 
| -      expect(div.nodes[2].text, "9"); | 
| -      expect(div.nodes[3].text, "6"); | 
| -      expect(div.nodes[4].text, "3"); | 
| -      expect(div.nodes[5].text, "2"); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bind - Reuse Instance', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ foo }}">{{ bar }}</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({ 'foo': { 'bar': 5 }}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| - | 
| -      addExpandos(template.nextNode); | 
| -      checkExpandos(template.nextNode); | 
| - | 
| -      model = toObservable({'foo': model['foo']}); | 
| -      templateBind(template).model = model; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      checkExpandos(template.nextNode); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat-Empty', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat>text</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    var model = toObservable([0, 1, 2]); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      model.length = 1; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 2); | 
| - | 
| -      model.addAll(toObservable([3, 4])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      model.removeRange(1, 2); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 3); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Removal from iteration needs to unbind', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{}}"><a>{{v}}</a></template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, | 
| -        {'v': 4}]); | 
| -    templateBind(template).model = model; | 
| - | 
| -    var nodes, vs; | 
| -    return new Future(() { | 
| - | 
| -      nodes = div.nodes.skip(1).toList(); | 
| -      vs = model.toList(); | 
| - | 
| -      for (var i = 0; i < 5; i++) { | 
| -        expect(nodes[i].text, '$i'); | 
| -      } | 
| - | 
| -      model.length = 3; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      for (var i = 0; i < 5; i++) { | 
| -        expect(nodes[i].text, '$i'); | 
| -      } | 
| - | 
| -      vs[3]['v'] = 33; | 
| -      vs[4]['v'] = 44; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      for (var i = 0; i < 5; i++) { | 
| -        expect(nodes[i].text, '$i'); | 
| -      } | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Template.clear', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat>{{}}</template>'); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = [0, 1, 2]; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[1].text, '0'); | 
| -      expect(div.nodes[2].text, '1'); | 
| -      expect(div.nodes[3].text, '2'); | 
| - | 
| -      // clear() synchronously removes instances and clears the model. | 
| -      templateBind(div.firstChild).clear(); | 
| -      expect(div.nodes.length, 1); | 
| -      expect(templateBind(template).model, null); | 
| - | 
| -      // test that template still works if new model assigned | 
| -      templateBind(template).model = [3, 4]; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 3); | 
| -      expect(div.nodes[1].text, '3'); | 
| -      expect(div.nodes[2].text, '4'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('DOM Stability on Iteration', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{}}">{{}}</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable([1, 2, 3, 4, 5]); | 
| -    templateBind(template).model = model; | 
| - | 
| -    var nodes; | 
| -    return new Future(() { | 
| -      // Note: the node at index 0 is the <template>. | 
| -      nodes = div.nodes.toList(); | 
| -      expect(nodes.length, 6, reason: 'list has 5 items'); | 
| - | 
| -      model.removeAt(0); | 
| -      model.removeLast(); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4, reason: 'list has 3 items'); | 
| -      expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed'); | 
| -      expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed'); | 
| -      expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed'); | 
| - | 
| -      model.insert(0, 5); | 
| -      model[2] = 6; | 
| -      model.add(7); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| - | 
| -      expect(div.nodes.length, 6, reason: 'list has 5 items'); | 
| -      expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node'); | 
| -      expect(identical(div.nodes[2], nodes[2]), true); | 
| -      expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node'); | 
| -      expect(identical(div.nodes[4], nodes[4]), true); | 
| -      expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node'); | 
| - | 
| -      nodes = div.nodes.toList(); | 
| - | 
| -      model.insert(2, 8); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| - | 
| -      expect(div.nodes.length, 7, reason: 'list has 6 items'); | 
| -      expect(identical(div.nodes[1], nodes[1]), true); | 
| -      expect(identical(div.nodes[2], nodes[2]), true); | 
| -      expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node'); | 
| -      expect(identical(div.nodes[4], nodes[3]), true); | 
| -      expect(identical(div.nodes[5], nodes[4]), true); | 
| -      expect(identical(div.nodes[6], nodes[5]), true); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Repeat2', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{}}">{{value}}</template>'); | 
| -    expect(div.nodes.length, 1); | 
| - | 
| -    var template = div.firstChild; | 
| -    var model = toObservable([ | 
| -      {'value': 0}, | 
| -      {'value': 1}, | 
| -      {'value': 2} | 
| -    ]); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[1].text, '0'); | 
| -      expect(div.nodes[2].text, '1'); | 
| -      expect(div.nodes[3].text, '2'); | 
| - | 
| -      model[1]['value'] = 'One'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[1].text, '0'); | 
| -      expect(div.nodes[2].text, 'One'); | 
| -      expect(div.nodes[3].text, '2'); | 
| - | 
| -      model.replaceRange(0, 1, toObservable([{'value': 'Zero'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[1].text, 'Zero'); | 
| -      expect(div.nodes[2].text, 'One'); | 
| -      expect(div.nodes[3].text, '2'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateWithInputValue', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}">' | 
| -        '<input value="{{x}}">' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'x': 'hi'}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 2); | 
| -      expect(div.nodes.last.value, 'hi'); | 
| - | 
| -      model['x'] = 'bye'; | 
| -      expect(div.nodes.last.value, 'hi'); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.value, 'bye'); | 
| - | 
| -      div.nodes.last.value = 'hello'; | 
| -      dispatchEvent('input', div.nodes.last); | 
| -      expect(model['x'], 'hello'); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.last.value, 'hello'); | 
| -    }); | 
| -  }); | 
| - | 
| -////////////////////////////////////////////////////////////////////////////// | 
| - | 
| -  test('Decorated', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{ XX }}" id="t1">' | 
| -          '<p>Crew member: {{name}}, Job title: {{title}}</p>' | 
| -        '</template>' | 
| -        '<template bind="{{ XY }}" id="t2" ref="t1"></template>'); | 
| - | 
| -    var t1 = document.getElementById('t1'); | 
| -    var t2 = document.getElementById('t2'); | 
| -    var model = toObservable({ | 
| -      'XX': {'name': 'Leela', 'title': 'Captain'}, | 
| -      'XY': {'name': 'Fry', 'title': 'Delivery boy'}, | 
| -      'XZ': {'name': 'Zoidberg', 'title': 'Doctor'} | 
| -    }); | 
| -    templateBind(t1).model = model; | 
| -    templateBind(t2).model = model; | 
| - | 
| -    return new Future(() { | 
| -      var instance = t1.nextElementSibling; | 
| -      expect(instance.text, 'Crew member: Leela, Job title: Captain'); | 
| - | 
| -      instance = t2.nextElementSibling; | 
| -      expect(instance.text, 'Crew member: Fry, Job title: Delivery boy'); | 
| - | 
| -      expect(div.children.length, 4); | 
| -      expect(div.nodes.length, 4); | 
| - | 
| -      expect(div.nodes[1].tagName, 'P'); | 
| -      expect(div.nodes[3].tagName, 'P'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('DefaultStyles', () { | 
| -    var t = new Element.tag('template'); | 
| -    TemplateBindExtension.decorate(t); | 
| - | 
| -    document.body.append(t); | 
| -    expect(t.getComputedStyle().display, 'none'); | 
| - | 
| -    t.remove(); | 
| -  }); | 
| - | 
| - | 
| -  test('Bind', () { | 
| -    var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'name': 'Leela'}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); | 
| -  }); | 
| - | 
| -  test('BindPlaceHolderHasNewLine', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}">Hi {{\nname\n}}</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'name': 'Leela'}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); | 
| -  }); | 
| - | 
| -  test('BindWithRef', () { | 
| -    var id = 't${new math.Random().nextInt(100)}'; | 
| -    var div = createTestHtml( | 
| -        '<template id="$id">' | 
| -          'Hi {{ name }}' | 
| -        '</template>' | 
| -        '<template ref="$id" bind="{{}}"></template>'); | 
| - | 
| -    var t1 = div.nodes.first; | 
| -    var t2 = div.nodes[1]; | 
| - | 
| -    var model = toObservable({'name': 'Fry'}); | 
| -    templateBind(t1).model = model; | 
| -    templateBind(t2).model = model; | 
| - | 
| -    return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); | 
| -  }); | 
| - | 
| -  test('Ref at multiple', () { | 
| -    // Note: this test is asserting that template "ref"erences can be located | 
| -    // at various points. In particular: | 
| -    // -in the document (at large) (e.g. ref=doc) | 
| -    // -within template content referenced from sub-content | 
| -    //   -both before and after the reference | 
| -    // The following asserts ensure that all referenced templates content is | 
| -    // found. | 
| -    var div = createTestHtml( | 
| -      '<template bind>' | 
| -        '<template bind ref=doc></template>' | 
| -        '<template id=elRoot>EL_ROOT</template>' | 
| -        '<template bind>' | 
| -          '<template bind ref=elRoot></template>' | 
| -          '<template bind>' | 
| -            '<template bind ref=subA></template>' | 
| -            '<template id=subB>SUB_B</template>' | 
| -            '<template bind>' | 
| -              '<template bind ref=subB></template>' | 
| -            '</template>' | 
| -          '</template>' | 
| -          '<template id=subA>SUB_A</template>' | 
| -        '</template>' | 
| -      '</template>' | 
| -      '<template id=doc>DOC</template>'); | 
| -    var t = div.firstChild; | 
| -    var fragment = templateBind(t).createInstance({}); | 
| -    expect(fragment.nodes.length, 14); | 
| -    expect(fragment.nodes[1].text, 'DOC'); | 
| -    expect(fragment.nodes[5].text, 'EL_ROOT'); | 
| -    expect(fragment.nodes[8].text, 'SUB_A'); | 
| -    expect(fragment.nodes[12].text, 'SUB_B'); | 
| -    div.append(fragment); | 
| -  }); | 
| - | 
| -  test('Update Ref', () { | 
| -    // Updating ref by observing the attribute is dependent on MutationObserver | 
| -    var div = createTestHtml( | 
| -        '<template id=A>Hi, {{}}</template>' | 
| -        '<template id=B>Hola, {{}}</template>' | 
| -        '<template ref=A repeat></template>'); | 
| - | 
| -    var template = div.nodes[2]; | 
| -    var model = new ObservableList.from(['Fry']); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| -      expect('Hi, Fry', div.nodes[3].text); | 
| - | 
| -      // In IE 11, MutationObservers do not fire before setTimeout. | 
| -      // So rather than using "then" to queue up the next test, we use a | 
| -      // MutationObserver here to detect the change to "ref". | 
| -      var done = new Completer(); | 
| -      new MutationObserver((mutations, observer) { | 
| -        expect(div.nodes.length, 5); | 
| - | 
| -        expect('Hola, Fry', div.nodes[3].text); | 
| -        expect('Hola, Leela', div.nodes[4].text); | 
| -        done.complete(); | 
| -      }).observe(template, attributes: true, attributeFilter: ['ref']); | 
| - | 
| -      template.setAttribute('ref', 'B'); | 
| -      model.add('Leela'); | 
| - | 
| -      return done.future; | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bound Ref', () { | 
| -    var div = createTestHtml( | 
| -        '<template id=A>Hi, {{}}</template>' | 
| -        '<template id=B>Hola, {{}}</template>' | 
| -        '<template ref="{{ ref }}" repeat="{{ people }}"></template>'); | 
| - | 
| -    var template = div.nodes[2]; | 
| -    var model = toObservable({'ref': 'A', 'people': ['Fry']}); | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| -      expect('Hi, Fry', div.nodes[3].text); | 
| - | 
| -      model['ref'] = 'B'; | 
| -      model['people'].add('Leela'); | 
| - | 
| -    }).then(endOfMicrotask).then((x) { | 
| -      expect(div.nodes.length, 5); | 
| - | 
| -      expect('Hola, Fry', div.nodes[3].text); | 
| -      expect('Hola, Leela', div.nodes[4].text); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('BindWithDynamicRef', () { | 
| -    var id = 't${new math.Random().nextInt(100)}'; | 
| -    var div = createTestHtml( | 
| -        '<template id="$id">' | 
| -          'Hi {{ name }}' | 
| -        '</template>' | 
| -        '<template ref="{{ id }}" bind="{{}}"></template>'); | 
| - | 
| -    var t1 = div.firstChild; | 
| -    var t2 = div.nodes[1]; | 
| -    var model = toObservable({'name': 'Fry', 'id': id }); | 
| -    templateBind(t1).model = model; | 
| -    templateBind(t2).model = model; | 
| - | 
| -    return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); | 
| -  }); | 
| - | 
| -  assertNodesAre(div, [arguments]) { | 
| -    var expectedLength = arguments.length; | 
| -    expect(div.nodes.length, expectedLength + 1); | 
| - | 
| -    for (var i = 0; i < arguments.length; i++) { | 
| -      var targetNode = div.nodes[i + 1]; | 
| -      expect(targetNode.text, arguments[i]); | 
| -    } | 
| -  } | 
| - | 
| -  test('Repeat3', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{ contacts }}">Hi {{ name }}</template>'); | 
| -    var t = div.nodes.first; | 
| - | 
| -    var m = toObservable({ | 
| -      'contacts': [ | 
| -        {'name': 'Raf'}, | 
| -        {'name': 'Arv'}, | 
| -        {'name': 'Neal'} | 
| -      ] | 
| -    }); | 
| - | 
| -    templateBind(t).model = m; | 
| -    return new Future(() { | 
| - | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 
| - | 
| -      m['contacts'].add(toObservable({'name': 'Alex'})); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); | 
| - | 
| -      m['contacts'].replaceRange(0, 2, | 
| -          toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']); | 
| - | 
| -      m['contacts'].removeRange(1, 3); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Rafael', 'Hi Alex']); | 
| - | 
| -      m['contacts'].insertAll(1, | 
| -          toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']); | 
| - | 
| -      m['contacts'].replaceRange(0, 1, | 
| -          toObservable([{'name': 'Tab'}, {'name': 'Neal'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri', | 
| -          'Hi Alex']); | 
| - | 
| -      m['contacts'] = toObservable([{'name': 'Alex'}]); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Alex']); | 
| - | 
| -      m['contacts'].length = 0; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, []); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('RepeatModelSet', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{ contacts }}">' | 
| -          'Hi {{ name }}' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ | 
| -      'contacts': [ | 
| -        {'name': 'Raf'}, | 
| -        {'name': 'Arv'}, | 
| -        {'name': 'Neal'} | 
| -      ] | 
| -    }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('RepeatEmptyPath', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{}}">Hi {{ name }}</template>'); | 
| -    var t = div.nodes.first; | 
| - | 
| -    var m = toObservable([ | 
| -      {'name': 'Raf'}, | 
| -      {'name': 'Arv'}, | 
| -      {'name': 'Neal'} | 
| -    ]); | 
| -    templateBind(t).model = m; | 
| -    return new Future(() { | 
| - | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 
| - | 
| -      m.add(toObservable({'name': 'Alex'})); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); | 
| - | 
| -      m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']); | 
| - | 
| -      m.removeRange(1, 3); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Rafael', 'Hi Alex']); | 
| - | 
| -      m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']); | 
| - | 
| -      m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri', | 
| -          'Hi Alex']); | 
| - | 
| -      m.length = 0; | 
| -      m.add(toObservable({'name': 'Alex'})); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Alex']); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('RepeatNullModel', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{}}">Hi {{ name }}</template>'); | 
| -    var t = div.nodes.first; | 
| - | 
| -    var m = null; | 
| -    templateBind(t).model = m; | 
| - | 
| -    expect(div.nodes.length, 1); | 
| - | 
| -    t.attributes['iterate'] = ''; | 
| -    m = toObservable({}); | 
| -    templateBind(t).model = m; | 
| -    return new Future(() => expect(div.nodes.length, 1)); | 
| -  }); | 
| - | 
| -  test('RepeatReuse', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat="{{}}">Hi {{ name }}</template>'); | 
| -    var t = div.nodes.first; | 
| - | 
| -    var m = toObservable([ | 
| -      {'name': 'Raf'}, | 
| -      {'name': 'Arv'}, | 
| -      {'name': 'Neal'} | 
| -    ]); | 
| -    templateBind(t).model = m; | 
| - | 
| -    var node1, node2, node3; | 
| -    return new Future(() { | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 
| -      node1 = div.nodes[1]; | 
| -      node2 = div.nodes[2]; | 
| -      node3 = div.nodes[3]; | 
| - | 
| -      m.replaceRange(1, 2, toObservable([{'name': 'Erik'}])); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']); | 
| -      expect(div.nodes[1], node1, | 
| -          reason: 'model[0] did not change so the node should not have changed'); | 
| -      expect(div.nodes[2], isNot(equals(node2)), | 
| -          reason: 'Should not reuse when replacing'); | 
| -      expect(div.nodes[3], node3, | 
| -          reason: 'model[2] did not change so the node should not have changed'); | 
| - | 
| -      node2 = div.nodes[2]; | 
| -      m.insert(0, toObservable({'name': 'Alex'})); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TwoLevelsDeepBug', () { | 
| -    var div = createTestHtml( | 
| -      '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'foo': 'bar'}); | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      expect(div.nodes[1].nodes[0].nodes[0].text, 'bar'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Checked', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<input type="checkbox" checked="{{a}}">' | 
| -        '</template>'); | 
| -    var t = div.nodes.first; | 
| -    templateBind(t).model = toObservable({'a': true }); | 
| - | 
| -    return new Future(() { | 
| - | 
| -      var instanceInput = t.nextNode; | 
| -      expect(instanceInput.checked, true); | 
| - | 
| -      instanceInput.click(); | 
| -      expect(instanceInput.checked, false); | 
| - | 
| -      instanceInput.click(); | 
| -      expect(instanceInput.checked, true); | 
| -    }); | 
| -  }); | 
| - | 
| -  nestedHelper(s, start) { | 
| -    var div = createTestHtml(s); | 
| - | 
| -    var m = toObservable({ | 
| -      'a': { | 
| -        'b': 1, | 
| -        'c': {'d': 2} | 
| -      }, | 
| -    }); | 
| - | 
| -    recursivelySetTemplateModel(div, m); | 
| -    return new Future(() { | 
| - | 
| -      var i = start; | 
| -      expect(div.nodes[i++].text, '1'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, '2'); | 
| - | 
| -      m['a']['b'] = 11; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[start].text, '11'); | 
| - | 
| -      m['a']['c'] = toObservable({'d': 22}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[start + 2].text, '22'); | 
| - | 
| -      //clearAllTemplates(div); | 
| -    }); | 
| -  } | 
| - | 
| -  test('Nested', () => nestedHelper( | 
| -      '<template bind="{{a}}">' | 
| -        '{{b}}' | 
| -        '<template bind="{{c}}">' | 
| -          '{{d}}' | 
| -        '</template>' | 
| -      '</template>', 1)); | 
| - | 
| -  test('NestedWithRef', () => nestedHelper( | 
| -        '<template id="inner">{{d}}</template>' | 
| -        '<template id="outer" bind="{{a}}">' | 
| -          '{{b}}' | 
| -          '<template ref="inner" bind="{{c}}"></template>' | 
| -        '</template>', 2)); | 
| - | 
| -  nestedIterateInstantiateHelper(s, start) { | 
| -    var div = createTestHtml(s); | 
| - | 
| -    var m = toObservable({ | 
| -      'a': [ | 
| -        { | 
| -          'b': 1, | 
| -          'c': {'d': 11} | 
| -        }, | 
| -        { | 
| -          'b': 2, | 
| -          'c': {'d': 22} | 
| -        } | 
| -      ] | 
| -    }); | 
| - | 
| -    recursivelySetTemplateModel(div, m); | 
| -    return new Future(() { | 
| - | 
| -      var i = start; | 
| -      expect(div.nodes[i++].text, '1'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, '11'); | 
| -      expect(div.nodes[i++].text, '2'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, '22'); | 
| - | 
| -      m['a'][1] = toObservable({ | 
| -        'b': 3, | 
| -        'c': {'d': 33} | 
| -      }); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[start + 3].text, '3'); | 
| -      expect(div.nodes[start + 5].text, '33'); | 
| -    }); | 
| -  } | 
| - | 
| -  test('NestedRepeatBind', () => nestedIterateInstantiateHelper( | 
| -      '<template repeat="{{a}}">' | 
| -        '{{b}}' | 
| -        '<template bind="{{c}}">' | 
| -          '{{d}}' | 
| -        '</template>' | 
| -      '</template>', 1)); | 
| - | 
| -  test('NestedRepeatBindWithRef', () => nestedIterateInstantiateHelper( | 
| -      '<template id="inner">' | 
| -        '{{d}}' | 
| -      '</template>' | 
| -      '<template repeat="{{a}}">' | 
| -        '{{b}}' | 
| -        '<template ref="inner" bind="{{c}}"></template>' | 
| -      '</template>', 2)); | 
| - | 
| -  nestedIterateIterateHelper(s, start) { | 
| -    var div = createTestHtml(s); | 
| - | 
| -    var m = toObservable({ | 
| -      'a': [ | 
| -        { | 
| -          'b': 1, | 
| -          'c': [{'d': 11}, {'d': 12}] | 
| -        }, | 
| -        { | 
| -          'b': 2, | 
| -          'c': [{'d': 21}, {'d': 22}] | 
| -        } | 
| -      ] | 
| -    }); | 
| - | 
| -    recursivelySetTemplateModel(div, m); | 
| -    return new Future(() { | 
| - | 
| -      var i = start; | 
| -      expect(div.nodes[i++].text, '1'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, '11'); | 
| -      expect(div.nodes[i++].text, '12'); | 
| -      expect(div.nodes[i++].text, '2'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, '21'); | 
| -      expect(div.nodes[i++].text, '22'); | 
| - | 
| -      m['a'][1] = toObservable({ | 
| -        'b': 3, | 
| -        'c': [{'d': 31}, {'d': 32}, {'d': 33}] | 
| -      }); | 
| - | 
| -      i = start + 4; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[start + 4].text, '3'); | 
| -      expect(div.nodes[start + 6].text, '31'); | 
| -      expect(div.nodes[start + 7].text, '32'); | 
| -      expect(div.nodes[start + 8].text, '33'); | 
| -    }); | 
| -  } | 
| - | 
| -  test('NestedRepeatBind', () => nestedIterateIterateHelper( | 
| -      '<template repeat="{{a}}">' | 
| -        '{{b}}' | 
| -        '<template repeat="{{c}}">' | 
| -          '{{d}}' | 
| -        '</template>' | 
| -      '</template>', 1)); | 
| - | 
| -  test('NestedRepeatRepeatWithRef', () => nestedIterateIterateHelper( | 
| -      '<template id="inner">' | 
| -        '{{d}}' | 
| -      '</template>' | 
| -      '<template repeat="{{a}}">' | 
| -        '{{b}}' | 
| -        '<template ref="inner" repeat="{{c}}"></template>' | 
| -      '</template>', 2)); | 
| - | 
| -  test('NestedRepeatSelfRef', () { | 
| -    var div = createTestHtml( | 
| -        '<template id="t" repeat="{{}}">' | 
| -          '{{name}}' | 
| -          '<template ref="t" repeat="{{items}}"></template>' | 
| -        '</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| - | 
| -    var m = toObservable([ | 
| -      { | 
| -        'name': 'Item 1', | 
| -        'items': [ | 
| -          { | 
| -            'name': 'Item 1.1', | 
| -            'items': [ | 
| -              { | 
| -                 'name': 'Item 1.1.1', | 
| -                 'items': [] | 
| -              } | 
| -            ] | 
| -          }, | 
| -          { | 
| -            'name': 'Item 1.2' | 
| -          } | 
| -        ] | 
| -      }, | 
| -      { | 
| -        'name': 'Item 2', | 
| -        'items': [] | 
| -      }, | 
| -    ]); | 
| - | 
| -    templateBind(template).model = m; | 
| - | 
| -    int i = 1; | 
| -    return new Future(() { | 
| -      expect(div.nodes[i++].text, 'Item 1'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, 'Item 1.1'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, 'Item 1.1.1'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, 'Item 1.2'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, 'Item 2'); | 
| - | 
| -      m[0] = toObservable({'name': 'Item 1 changed'}); | 
| - | 
| -      i = 1; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[i++].text, 'Item 1 changed'); | 
| -      expect(div.nodes[i++].tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[i++].text, 'Item 2'); | 
| -    }); | 
| -  }); | 
| - | 
| -  // Note: we don't need a zone for this test, and we don't want to alter timing | 
| -  // since we're testing a rather subtle relationship between select and option. | 
| -  test('Attribute Template Option/Optgroup', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<select selectedIndex="{{ selected }}">' | 
| -            '<optgroup template repeat="{{ groups }}" label="{{ name }}">' | 
| -              '<option template repeat="{{ items }}">{{ val }}</option>' | 
| -            '</optgroup>' | 
| -          '</select>' | 
| -        '</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ | 
| -      'selected': 1, | 
| -      'groups': [{ | 
| -        'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }] | 
| -      }], | 
| -    }); | 
| - | 
| -    templateBind(template).model = m; | 
| - | 
| -    var completer = new Completer(); | 
| - | 
| -    new MutationObserver((records, observer) { | 
| -      var select = div.nodes[0].nextNode; | 
| -      if (select == null || select.querySelector('option') == null) return; | 
| - | 
| -      observer.disconnect(); | 
| -      new Future(() { | 
| -        expect(select.nodes.length, 2); | 
| - | 
| -        expect(select.selectedIndex, 1, reason: 'selected index should update ' | 
| -            'after template expands.'); | 
| - | 
| -        expect(select.nodes[0].tagName, 'TEMPLATE'); | 
| -        var optgroup = select.nodes[1]; | 
| -        expect(optgroup.nodes[0].tagName, 'TEMPLATE'); | 
| -        expect(optgroup.nodes[1].tagName, 'OPTION'); | 
| -        expect(optgroup.nodes[1].text, '0'); | 
| -        expect(optgroup.nodes[2].tagName, 'OPTION'); | 
| -        expect(optgroup.nodes[2].text, '1'); | 
| - | 
| -        completer.complete(); | 
| -      }); | 
| -    })..observe(div, childList: true, subtree: true); | 
| - | 
| -    Observable.dirtyCheck(); | 
| - | 
| -    return completer.future; | 
| -  }); | 
| - | 
| -  test('NestedIterateTableMixedSemanticNative', () { | 
| -    if (!parserHasNativeTemplate) return null; | 
| - | 
| -    var div = createTestHtml( | 
| -        '<table><tbody>' | 
| -          '<template repeat="{{}}">' | 
| -            '<tr>' | 
| -              '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' | 
| -            '</tr>' | 
| -          '</template>' | 
| -        '</tbody></table>'); | 
| -    var template = div.firstChild.firstChild.firstChild; | 
| - | 
| -    var m = toObservable([ | 
| -      [{ 'val': 0 }, { 'val': 1 }], | 
| -      [{ 'val': 2 }, { 'val': 3 }] | 
| -    ]); | 
| - | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      var tbody = div.nodes[0].nodes[0]; | 
| - | 
| -      // 1 for the <tr template>, 2 * (1 tr) | 
| -      expect(tbody.nodes.length, 3); | 
| - | 
| -      // 1 for the <td template>, 2 * (1 td) | 
| -      expect(tbody.nodes[1].nodes.length, 3); | 
| - | 
| -      expect(tbody.nodes[1].nodes[1].text, '0'); | 
| -      expect(tbody.nodes[1].nodes[2].text, '1'); | 
| - | 
| -      // 1 for the <td template>, 2 * (1 td) | 
| -      expect(tbody.nodes[2].nodes.length, 3); | 
| -      expect(tbody.nodes[2].nodes[1].text, '2'); | 
| -      expect(tbody.nodes[2].nodes[2].text, '3'); | 
| - | 
| -      // Asset the 'class' binding is retained on the semantic template (just | 
| -      // check the last one). | 
| -      expect(tbody.nodes[2].nodes[2].attributes["class"], '3'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('NestedIterateTable', () { | 
| -    var div = createTestHtml( | 
| -        '<table><tbody>' | 
| -          '<tr template repeat="{{}}">' | 
| -            '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' | 
| -          '</tr>' | 
| -        '</tbody></table>'); | 
| -    var template = div.firstChild.firstChild.firstChild; | 
| - | 
| -    var m = toObservable([ | 
| -      [{ 'val': 0 }, { 'val': 1 }], | 
| -      [{ 'val': 2 }, { 'val': 3 }] | 
| -    ]); | 
| - | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| - | 
| -      var i = 1; | 
| -      var tbody = div.nodes[0].nodes[0]; | 
| - | 
| -      // 1 for the <tr template>, 2 * (1 tr) | 
| -      expect(tbody.nodes.length, 3); | 
| - | 
| -      // 1 for the <td template>, 2 * (1 td) | 
| -      expect(tbody.nodes[1].nodes.length, 3); | 
| -      expect(tbody.nodes[1].nodes[1].text, '0'); | 
| -      expect(tbody.nodes[1].nodes[2].text, '1'); | 
| - | 
| -      // 1 for the <td template>, 2 * (1 td) | 
| -      expect(tbody.nodes[2].nodes.length, 3); | 
| -      expect(tbody.nodes[2].nodes[1].text, '2'); | 
| -      expect(tbody.nodes[2].nodes[2].text, '3'); | 
| - | 
| -      // Asset the 'class' binding is retained on the semantic template (just | 
| -      // check the last one). | 
| -      expect(tbody.nodes[2].nodes[2].attributes['class'], '3'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('NestedRepeatDeletionOfMultipleSubTemplates', () { | 
| -    var div = createTestHtml( | 
| -        '<ul>' | 
| -          '<template repeat="{{}}" id=t1>' | 
| -            '<li>{{name}}' | 
| -              '<ul>' | 
| -                '<template ref=t1 repeat="{{items}}"></template>' | 
| -              '</ul>' | 
| -            '</li>' | 
| -          '</template>' | 
| -        '</ul>'); | 
| - | 
| -    var m = toObservable([ | 
| -      { | 
| -        'name': 'Item 1', | 
| -        'items': [ | 
| -          { | 
| -            'name': 'Item 1.1' | 
| -          } | 
| -        ] | 
| -      } | 
| -    ]); | 
| -    var ul = div.firstChild; | 
| -    var t = ul.firstChild; | 
| - | 
| -    templateBind(t).model = m; | 
| -    return new Future(() { | 
| -      expect(ul.nodes.length, 2); | 
| -      var ul2 = ul.nodes[1].nodes[1]; | 
| -      expect(ul2.nodes.length, 2); | 
| -      var ul3 = ul2.nodes[1].nodes[1]; | 
| -      expect(ul3.nodes.length, 1); | 
| - | 
| -      m.removeAt(0); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(ul.nodes.length, 1); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('DeepNested', () { | 
| -    var div = createTestHtml( | 
| -      '<template bind="{{a}}">' | 
| -        '<p>' | 
| -          '<template bind="{{b}}">' | 
| -            '{{ c }}' | 
| -          '</template>' | 
| -        '</p>' | 
| -      '</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ | 
| -      'a': { | 
| -        'b': { | 
| -          'c': 42 | 
| -        } | 
| -      } | 
| -    }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes[1].tagName, 'P'); | 
| -      expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE'); | 
| -      expect(div.nodes[1].nodes[1].text, '42'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateContentRemoved', () { | 
| -    var div = createTestHtml('<template bind="{{}}">{{ }}</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = 42; | 
| - | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      expect(div.nodes[1].text, '42'); | 
| -      expect(div.nodes[0].text, ''); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateContentRemovedEmptyArray', () { | 
| -    var div = createTestHtml('<template iterate>Remove me</template>'); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = []; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 1); | 
| -      expect(div.nodes[0].text, ''); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('TemplateContentRemovedNested', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}">' | 
| -          '{{ a }}' | 
| -          '<template bind="{{}}">' | 
| -            '{{ b }}' | 
| -          '</template>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({ | 
| -      'a': 1, | 
| -      'b': 2 | 
| -    }); | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      expect(div.nodes[0].text, ''); | 
| -      expect(div.nodes[1].text, '1'); | 
| -      expect(div.nodes[2].text, ''); | 
| -      expect(div.nodes[3].text, '2'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('BindWithUndefinedModel', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}" if="{{}}">{{ a }}</template>'); | 
| -    var template = div.firstChild; | 
| - | 
| -    var model = toObservable({'a': 42}); | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      expect(div.nodes[1].text, '42'); | 
| - | 
| -      model = null; | 
| -      templateBind(template).model = model; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 1); | 
| - | 
| -      model = toObservable({'a': 42}); | 
| -      templateBind(template).model = model; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes[1].text, '42'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('BindNested', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}">' | 
| -          'Name: {{ name }}' | 
| -          '<template bind="{{wife}}" if="{{wife}}">' | 
| -            'Wife: {{ name }}' | 
| -          '</template>' | 
| -          '<template bind="{{child}}" if="{{child}}">' | 
| -            'Child: {{ name }}' | 
| -          '</template>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ | 
| -      'name': 'Hermes', | 
| -      'wife': { | 
| -        'name': 'LaBarbara' | 
| -      } | 
| -    }); | 
| -    templateBind(template).model = m; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 5); | 
| -      expect(div.nodes[1].text, 'Name: Hermes'); | 
| -      expect(div.nodes[3].text, 'Wife: LaBarbara'); | 
| - | 
| -      m['child'] = toObservable({'name': 'Dwight'}); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 6); | 
| -      expect(div.nodes[5].text, 'Child: Dwight'); | 
| - | 
| -      m.remove('wife'); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 5); | 
| -      expect(div.nodes[4].text, 'Child: Dwight'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('BindRecursive', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind="{{}}" if="{{}}" id="t">' | 
| -          'Name: {{ name }}' | 
| -          '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| -    var m = toObservable({ | 
| -      'name': 'Fry', | 
| -      'friend': { | 
| -        'name': 'Bender' | 
| -      } | 
| -    }); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 5); | 
| -      expect(div.nodes[1].text, 'Name: Fry'); | 
| -      expect(div.nodes[3].text, 'Name: Bender'); | 
| - | 
| -      m['friend']['friend'] = toObservable({'name': 'Leela'}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 7); | 
| -      expect(div.nodes[5].text, 'Name: Leela'); | 
| - | 
| -      m['friend'] = toObservable({'name': 'Leela'}); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(div.nodes.length, 5); | 
| -      expect(div.nodes[3].text, 'Name: Leela'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Template - Self is terminator', () { | 
| -    var div = createTestHtml( | 
| -        '<template repeat>{{ foo }}' | 
| -          '<template bind></template>' | 
| -        '</template>'); | 
| -    var template = div.firstChild; | 
| - | 
| -    var m = toObservable([{ 'foo': 'bar' }]); | 
| -    templateBind(template).model = m; | 
| -    return new Future(() { | 
| - | 
| -      m.add(toObservable({ 'foo': 'baz' })); | 
| -      templateBind(template).model = m; | 
| -    }).then(endOfMicrotask).then((_) { | 
| - | 
| -      expect(div.nodes.length, 5); | 
| -      expect(div.nodes[1].text, 'bar'); | 
| -      expect(div.nodes[3].text, 'baz'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Template - Same Contents, Different Array has no effect', () { | 
| -    if (!MutationObserver.supported) return null; | 
| - | 
| -    var div = createTestHtml('<template repeat>{{ foo }}</template>'); | 
| -    var template = div.firstChild; | 
| - | 
| -    var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]); | 
| -    templateBind(template).model = m; | 
| -    var observer = new MutationObserver((x, y) {}); | 
| -    return new Future(() { | 
| -      observer.observe(div, childList: true); | 
| - | 
| -      var template = div.firstChild; | 
| -      templateBind(template).model = new ObservableList.from(m); | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      var records = observer.takeRecords(); | 
| -      expect(records.length, 0); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('RecursiveRef', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<template id=src>{{ foo }}</template>' | 
| -          '<template bind ref=src></template>' | 
| -        '</template>'); | 
| - | 
| -    var m = toObservable({'foo': 'bar'}); | 
| -    templateBind(div.firstChild).model = m; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 4); | 
| -      expect(div.nodes[3].text, 'bar'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('baseURI', () { | 
| -    // TODO(jmesserly): Dart's setInnerHtml breaks this test -- the template | 
| -    // URL is created as blank despite the NullTreeSanitizer. | 
| -    // Use JS interop as a workaround. | 
| -    //var div = createTestHtml('<template bind>' | 
| -    //   '<div style="background: url(foo.jpg)"></div></template>'); | 
| -    var div = new DivElement(); | 
| -    new JsObject.fromBrowserObject(div)['innerHTML'] = '<template bind>' | 
| -        '<div style="background: url(foo.jpg)"></div></template>'; | 
| -    testDiv.append(div); | 
| -    TemplateBindExtension.decorate(div.firstChild); | 
| - | 
| -    var local = document.createElement('div'); | 
| -    local.attributes['style'] = 'background: url(foo.jpg)'; | 
| -    div.append(local); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = {}; | 
| -    return new Future(() { | 
| -      expect(div.nodes[1].style.backgroundImage, local.style.backgroundImage); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('ChangeRefId', () { | 
| -    var div = createTestHtml( | 
| -        '<template id="a">a:{{ }}</template>' | 
| -        '<template id="b">b:{{ }}</template>' | 
| -        '<template repeat="{{}}">' | 
| -          '<template ref="a" bind="{{}}"></template>' | 
| -        '</template>'); | 
| -    var template = div.nodes[2]; | 
| -    var model = toObservable([]); | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      expect(div.nodes.length, 3); | 
| - | 
| -      document.getElementById('a').id = 'old-a'; | 
| -      document.getElementById('b').id = 'a'; | 
| - | 
| -      model..add(1)..add(2); | 
| -    }).then(endOfMicrotask).then((_) { | 
| - | 
| -      expect(div.nodes.length, 7); | 
| -      expect(div.nodes[4].text, 'b:1'); | 
| -      expect(div.nodes[6].text, 'b:2'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Content', () { | 
| -    var div = createTestHtml( | 
| -        '<template><a></a></template>' | 
| -        '<template><b></b></template>'); | 
| -    var templateA = div.nodes.first; | 
| -    var templateB = div.nodes.last; | 
| -    var contentA = templateBind(templateA).content; | 
| -    var contentB = templateBind(templateB).content; | 
| -    expect(contentA, isNotNull); | 
| - | 
| -    expect(templateA.ownerDocument, isNot(equals(contentA.ownerDocument))); | 
| -    expect(templateB.ownerDocument, isNot(equals(contentB.ownerDocument))); | 
| - | 
| -    expect(templateB.ownerDocument, templateA.ownerDocument); | 
| -    expect(contentB.ownerDocument, contentA.ownerDocument); | 
| - | 
| -    // NOTE: these tests don't work under ShadowDOM polyfill. | 
| -    // Disabled for now. | 
| -    //expect(templateA.ownerDocument.window, window); | 
| -    //expect(templateB.ownerDocument.window, window); | 
| - | 
| -    expect(contentA.ownerDocument.window, null); | 
| -    expect(contentB.ownerDocument.window, null); | 
| - | 
| -    expect(contentA.nodes.last, contentA.nodes.first); | 
| -    expect(contentA.nodes.first.tagName, 'A'); | 
| - | 
| -    expect(contentB.nodes.last, contentB.nodes.first); | 
| -    expect(contentB.nodes.first.tagName, 'B'); | 
| -  }); | 
| - | 
| -  test('NestedContent', () { | 
| -    var div = createTestHtml( | 
| -        '<template>' | 
| -        '<template></template>' | 
| -        '</template>'); | 
| -    var templateA = div.nodes.first; | 
| -    var templateB = templateBind(templateA).content.nodes.first; | 
| - | 
| -    expect(templateB.ownerDocument, templateBind(templateA) | 
| -        .content.ownerDocument); | 
| -    expect(templateBind(templateB).content.ownerDocument, | 
| -        templateBind(templateA).content.ownerDocument); | 
| -  }); | 
| - | 
| -  test('BindShadowDOM', () { | 
| -    if (!ShadowRoot.supported) return null; | 
| - | 
| -    var root = createShadowTestHtml( | 
| -        '<template bind="{{}}">Hi {{ name }}</template>'); | 
| -    var model = toObservable({'name': 'Leela'}); | 
| -    templateBind(root.firstChild).model = model; | 
| -    return new Future(() => expect(root.nodes[1].text, 'Hi Leela')); | 
| -  }); | 
| - | 
| -  // Dart note: this test seems gone from JS. Keeping for posterity sake. | 
| -  test('BindShadowDOM createInstance', () { | 
| -    if (!ShadowRoot.supported) return null; | 
| - | 
| -    var model = toObservable({'name': 'Leela'}); | 
| -    var template = new Element.html('<template>Hi {{ name }}</template>'); | 
| -    var root = createShadowTestHtml(''); | 
| -    root.nodes.add(templateBind(template).createInstance(model)); | 
| - | 
| -    return new Future(() { | 
| -      expect(root.text, 'Hi Leela'); | 
| - | 
| -      model['name'] = 'Fry'; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(root.text, 'Hi Fry'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('BindShadowDOM Template Ref', () { | 
| -    if (!ShadowRoot.supported) return null; | 
| -    var root = createShadowTestHtml( | 
| -        '<template id=foo>Hi</template><template bind ref=foo></template>'); | 
| -    var template = root.nodes[1]; | 
| -    templateBind(template).model = toObservable({}); | 
| -    return new Future(() { | 
| -      expect(root.nodes.length, 3); | 
| -      clearAllTemplates(root); | 
| -    }); | 
| -  }); | 
| - | 
| -  // https://github.com/Polymer/TemplateBinding/issues/8 | 
| -  test('UnbindingInNestedBind', () { | 
| -    var div = createTestHtml( | 
| -      '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">' | 
| -        '<template bind="{{inner}}" if="{{inner}}">' | 
| -          '{{ age }}' | 
| -        '</template>' | 
| -      '</template>'); | 
| -    var template = div.firstChild; | 
| -    var syntax = new UnbindingInNestedBindSyntax(); | 
| -    var model = toObservable({'outer': {'inner': {'age': 42}}}); | 
| - | 
| -    templateBind(template)..model = model..bindingDelegate = syntax; | 
| - | 
| -    return new Future(() { | 
| -      expect(syntax.count, 1); | 
| - | 
| -      var inner = model['outer']['inner']; | 
| -      model['outer'] = null; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(syntax.count, 1); | 
| - | 
| -      model['outer'] = toObservable({'inner': {'age': 2}}); | 
| -      syntax.expectedAge = 2; | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(syntax.count, 2); | 
| -    }); | 
| -  }); | 
| - | 
| -  // https://github.com/toolkitchen/mdv/issues/8 | 
| -  test('DontCreateInstancesForAbandonedIterators', () { | 
| -    var div = createTestHtml( | 
| -      '<template bind="{{}} {{}}">' | 
| -        '<template bind="{{}}">Foo</template>' | 
| -      '</template>'); | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = null; | 
| -    return nextMicrotask; | 
| -  }); | 
| - | 
| -  test('CreateInstance', () { | 
| -    var div = createTestHtml( | 
| -      '<template bind="{{a}}">' | 
| -        '<template bind="{{b}}">' | 
| -          '{{ foo }}:{{ replaceme }}' | 
| -        '</template>' | 
| -      '</template>'); | 
| -    var outer = templateBind(div.nodes.first); | 
| -    var model = toObservable({'b': {'foo': 'bar'}}); | 
| - | 
| -    var instance = outer.createInstance(model, new TestBindingSyntax()); | 
| -    expect(instance.firstChild.nextNode.text, 'bar:replaced'); | 
| - | 
| -    clearAllTemplates(instance); | 
| -  }); | 
| - | 
| -  test('CreateInstance - sync error', () { | 
| -    var div = createTestHtml('<template>{{foo}}</template>'); | 
| -    var outer = templateBind(div.nodes.first); | 
| -    var model = 1; // model is missing 'foo' should throw. | 
| -    expect(() => outer.createInstance(model, new TestBindingSyntax()), | 
| -        throwsA(_isNoSuchMethodError)); | 
| -  }); | 
| - | 
| -  test('CreateInstance - async error', () { | 
| -    var div = createTestHtml( | 
| -      '<template>' | 
| -        '<template bind="{{b}}">' | 
| -          '{{ foo }}:{{ replaceme }}' | 
| -        '</template>' | 
| -      '</template>'); | 
| -    var outer = templateBind(div.nodes.first); | 
| -    var model = toObservable({'b': 1}); // missing 'foo' should throw. | 
| - | 
| -    bool seen = false; | 
| -    runZoned(() => outer.createInstance(model, new TestBindingSyntax()), | 
| -      onError: (e) { | 
| -        _expectNoSuchMethod(e); | 
| -        seen = true; | 
| -      }); | 
| -    return new Future(() { expect(seen, isTrue); }); | 
| -  }); | 
| - | 
| -  test('Repeat - svg', () { | 
| -    var div = createTestHtml( | 
| -        '<svg width="400" height="110">' | 
| -          '<template repeat>' | 
| -            '<rect width="{{ width }}" height="{{ height }}" />' | 
| -          '</template>' | 
| -        '</svg>'); | 
| - | 
| -    var model = toObservable([{ 'width': 10, 'height': 11 }, | 
| -                              { 'width': 20, 'height': 21 }]); | 
| -    var svg = div.firstChild; | 
| -    var template = svg.firstChild; | 
| -    templateBind(template).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(svg.nodes.length, 3); | 
| -      expect(svg.nodes[1].attributes['width'], '10'); | 
| -      expect(svg.nodes[1].attributes['height'], '11'); | 
| -      expect(svg.nodes[2].attributes['width'], '20'); | 
| -      expect(svg.nodes[2].attributes['height'], '21'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Bootstrap', () { | 
| -    var div = new DivElement(); | 
| -    div.innerHtml = | 
| -      '<template>' | 
| -        '<div></div>' | 
| -        '<template>' | 
| -          'Hello' | 
| -        '</template>' | 
| -      '</template>'; | 
| - | 
| -    TemplateBindExtension.bootstrap(div); | 
| -    var template = templateBind(div.nodes.first); | 
| -    expect(template.content.nodes.length, 2); | 
| -    var template2 = templateBind(template.content.nodes.first.nextNode); | 
| -    expect(template2.content.nodes.length, 1); | 
| -    expect(template2.content.nodes.first.text, 'Hello'); | 
| - | 
| -    template = new Element.tag('template'); | 
| -    template.innerHtml = | 
| -      '<template>' | 
| -        '<div></div>' | 
| -        '<template>' | 
| -          'Hello' | 
| -        '</template>' | 
| -      '</template>'; | 
| - | 
| -    TemplateBindExtension.bootstrap(template); | 
| -    template2 = templateBind(templateBind(template).content.nodes.first); | 
| -    expect(template2.content.nodes.length, 2); | 
| -    var template3 = templateBind(template2.content.nodes.first.nextNode); | 
| -    expect(template3.content.nodes.length, 1); | 
| -    expect(template3.content.nodes.first.text, 'Hello'); | 
| -  }); | 
| - | 
| -  test('issue-285', () { | 
| -    var div = createTestHtml( | 
| -        '<template>' | 
| -          '<template bind if="{{show}}">' | 
| -            '<template id=del repeat="{{items}}">' | 
| -              '{{}}' | 
| -            '</template>' | 
| -          '</template>' | 
| -        '</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| - | 
| -    var model = toObservable({ | 
| -      'show': true, | 
| -      'items': [1] | 
| -    }); | 
| - | 
| -    div.append(templateBind(template).createInstance(model, | 
| -        new Issue285Syntax())); | 
| - | 
| -    return new Future(() { | 
| -      expect(template.nextNode.nextNode.nextNode.text, '2'); | 
| -      model['show'] = false; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      model['show'] = true; | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(template.nextNode.nextNode.nextNode.text, '2'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('Accessor value retrieval count', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>{{ prop }}</template>'); | 
| - | 
| -    var model = new TestAccessorModel(); | 
| - | 
| -    templateBind(div.firstChild).model = model; | 
| - | 
| -    return new Future(() { | 
| -      expect(model.count, 1); | 
| - | 
| -      model.value++; | 
| -      // Dart note: we don't handle getters in @observable, so we need to | 
| -      // notify regardless. | 
| -      model.notifyPropertyChange(#prop, 1, model.value); | 
| - | 
| -    }).then(endOfMicrotask).then((_) { | 
| -      expect(model.count, 2); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('issue-141', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' | 
| -        '</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({ | 
| -      'foo1': 'foo1Value', | 
| -      'foo2': 'foo2Value', | 
| -      'bar': 'barValue' | 
| -    }); | 
| - | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      expect(div.lastChild.attributes['bar'], 'barValue'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('issue-18', () { | 
| -    var delegate = new Issue18Syntax(); | 
| - | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<div class="foo: {{ bar }}"></div>' | 
| -        '</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({'bar': 2}); | 
| - | 
| -    templateBind(template)..model = model..bindingDelegate = delegate; | 
| - | 
| -    return new Future(() { | 
| -      expect(div.lastChild.attributes['class'], 'foo: 2'); | 
| -    }); | 
| -  }); | 
| - | 
| -  test('issue-152', () { | 
| -    var div = createTestHtml( | 
| -        '<template ref=notThere bind>XXX</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    templateBind(template).model = {}; | 
| - | 
| -    return new Future(() { | 
| -      // if a ref cannot be located, a template will continue to use itself | 
| -      // as the source of template instances. | 
| -      expect(div.nodes[1].text, 'XXX'); | 
| -    }); | 
| -  }); | 
| -} | 
| - | 
| -compatTests() { | 
| -  test('underbar bindings', () { | 
| -    var div = createTestHtml( | 
| -        '<template bind>' | 
| -          '<div _style="color: {{ color }};"></div>' | 
| -          '<img _src="{{ url }}">' | 
| -          '<a _href="{{ url2 }}">Link</a>' | 
| -          '<input type="number" _value="{{ number }}">' | 
| -        '</template>'); | 
| - | 
| -    var template = div.firstChild; | 
| -    var model = toObservable({ | 
| -      'color': 'red', | 
| -      'url': 'pic.jpg', | 
| -      'url2': 'link.html', | 
| -      'number': 4 | 
| -    }); | 
| - | 
| -    templateBind(template).model = model; | 
| -    return new Future(() { | 
| -      var subDiv = div.firstChild.nextNode; | 
| -      expect(subDiv.attributes['style'], 'color: red;'); | 
| - | 
| -      var img = subDiv.nextNode; | 
| -      expect(img.attributes['src'], 'pic.jpg'); | 
| - | 
| -      var a = img.nextNode; | 
| -      expect(a.attributes['href'], 'link.html'); | 
| - | 
| -      var input = a.nextNode; | 
| -      expect(input.value, '4'); | 
| -    }); | 
| -  }); | 
| -} | 
| - | 
| -// TODO(jmesserly): ideally we could test the type with isNoSuchMethodError, | 
| -// however dart:js converts the nSM into a String at some point. | 
| -// So for now we do string comparison. | 
| -_isNoSuchMethodError(e) => '$e'.contains('NoSuchMethodError'); | 
| - | 
| -_expectNoSuchMethod(e) { | 
| -  // expect(e, isNoSuchMethodError); | 
| -  expect('$e', contains('NoSuchMethodError')); | 
| -} | 
| - | 
| -class Issue285Syntax extends BindingDelegate { | 
| -  prepareInstanceModel(template) { | 
| -    if (template.id == 'del') return (val) => val * 2; | 
| -  } | 
| -} | 
| - | 
| -class TestBindingSyntax extends BindingDelegate { | 
| -  prepareBinding(String path, name, node) { | 
| -    if (path.trim() == 'replaceme') { | 
| -      return (m, n, oneTime) => new PathObserver('replaced', ''); | 
| -    } | 
| -    return null; | 
| -  } | 
| -} | 
| - | 
| -class UnbindingInNestedBindSyntax extends BindingDelegate { | 
| -  int expectedAge = 42; | 
| -  int count = 0; | 
| - | 
| -  prepareBinding(path, name, node) { | 
| -    if (name != 'text' || path != 'age') return null; | 
| - | 
| -    return (model, _, oneTime) { | 
| -      expect(model['age'], expectedAge); | 
| -      count++; | 
| -      return new PathObserver(model, path); | 
| -    }; | 
| -  } | 
| -} | 
| - | 
| -class Issue18Syntax extends BindingDelegate { | 
| -  prepareBinding(path, name, node) { | 
| -    if (name != 'class') return null; | 
| - | 
| -    return (model, _, oneTime) => new PathObserver(model, path); | 
| -  } | 
| -} | 
| - | 
| -class BindIfMinimalDiscardChanges extends BindingDelegate { | 
| -  Map<String, int> discardChangesCalled; | 
| - | 
| -  BindIfMinimalDiscardChanges(this.discardChangesCalled) : super() {} | 
| - | 
| -  prepareBinding(path, name, node) { | 
| -    return (model, node, oneTime) => | 
| -      new DiscardCountingPathObserver(discardChangesCalled, model, path); | 
| -  } | 
| -} | 
| - | 
| -class DiscardCountingPathObserver extends PathObserver { | 
| -  Map<String, int> discardChangesCalled; | 
| - | 
| -  DiscardCountingPathObserver(this.discardChangesCalled, model, path) | 
| -      : super(model, path) {} | 
| - | 
| -  get value { | 
| -    discardChangesCalled[path.toString()]++; | 
| -    return super.value; | 
| -  } | 
| -} | 
| - | 
| -class TestAccessorModel extends Observable { | 
| -  @observable var value = 1; | 
| -  var count = 0; | 
| - | 
| -  @reflectable | 
| -  get prop { | 
| -    count++; | 
| -    return value; | 
| -  } | 
| -} | 
|  |