Chromium Code Reviews| Index: pkg/template_binding/test/template_binding_test.dart |
| diff --git a/pkg/template_binding/test/template_element_test.dart b/pkg/template_binding/test/template_binding_test.dart |
| similarity index 89% |
| rename from pkg/template_binding/test/template_element_test.dart |
| rename to pkg/template_binding/test/template_binding_test.dart |
| index a878090bfacebcad3dc0ce233c9f8d266c2b88bd..056931d652dda07ef8abf956ab0d0f83aaeb4be6 100644 |
| --- a/pkg/template_binding/test/template_element_test.dart |
| +++ b/pkg/template_binding/test/template_binding_test.dart |
| @@ -2,7 +2,7 @@ |
| // 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_element_test; |
| +library template_binding.test.template_binding_test; |
| import 'dart:async'; |
| import 'dart:collection'; |
| @@ -12,20 +12,21 @@ import 'package:observe/observe.dart'; |
| import 'package:template_binding/template_binding.dart'; |
| import 'package:unittest/html_config.dart'; |
| import 'package:unittest/unittest.dart'; |
| + |
| +// TODO(jmesserly): merge this file? |
| +import 'binding_syntax.dart' show syntaxTests; |
| import 'utils.dart'; |
| // Note: this file ported from |
| -// https://github.com/toolkitchen/mdv/blob/master/tests/template_element.js |
| +// https://github.com/Polymer/TemplateBinding/blob/ed3266266e751b5ab1f75f8e0509d0d5f0ef35d8/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() { |
| useHtmlConfiguration(); |
| - group('Template Element', templateElementTests); |
| -} |
| -templateElementTests() { |
| setUp(() { |
| document.body.append(testDiv = new DivElement()); |
| }); |
| @@ -35,36 +36,57 @@ templateElementTests() { |
| testDiv = null; |
| }); |
| - var expando = new Expando('observeTest'); |
| - void addExpandos(node) { |
| - while (node != null) { |
| - expando[node] = node.text; |
| - node = node.nextNode; |
| - } |
| + group('Template Instantiation', 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; |
| - } |
| +void checkExpandos(node) { |
| + expect(node, isNotNull); |
| + while (node != null) { |
| + expect(expando[node], node.text); |
| + node = node.nextNode; |
| } |
| +} |
| + |
| +templateInstantiationTests() { |
| observeTest('Template', () { |
| var div = createTestHtml('<template bind={{}}>text</template>'); |
| - recursivelySetTemplateModel(div, null); |
| + templateBind(div.firstChild).model = {}; |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 2); |
| expect(div.nodes.last.text, 'text'); |
| + |
| + templateBind(div.firstChild).model = null; |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 1); |
| }); |
| observeTest('Template bind, no parent', () { |
| var div = createTestHtml('<template bind>text</template>'); |
| - var template = div.nodes[0]; |
| + var template = div.firstChild; |
| template.remove(); |
| - recursivelySetTemplateModel(template, toObservable({})); |
| + templateBind(template).model = {}; |
| performMicrotaskCheckpoint(); |
| expect(template.nodes.length, 0); |
| expect(template.nextNode, null); |
| @@ -72,17 +94,18 @@ templateElementTests() { |
| observeTest('Template bind, no defaultView', () { |
| var div = createTestHtml('<template bind>text</template>'); |
| - var template = div.nodes[0]; |
| + var template = div.firstChild; |
| var doc = document.implementation.createHtmlDocument(''); |
| doc.adoptNode(div); |
| - recursivelySetTemplateModel(template, toObservable({})); |
| + recursivelySetTemplateModel(template, {}); |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 1); |
| }); |
| observeTest('Template-Empty Bind', () { |
| var div = createTestHtml('<template bind>text</template>'); |
| - recursivelySetTemplateModel(div, null); |
| + var template = div.firstChild; |
| + templateBind(template).model = {}; |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 2); |
| expect(div.nodes.last.text, 'text'); |
| @@ -93,7 +116,8 @@ templateElementTests() { |
| // Note: changed this value from 0->null because zero is not falsey in Dart. |
| // See https://code.google.com/p/dart/issues/detail?id=11956 |
| var m = toObservable({ 'foo': null }); |
| - recursivelySetTemplateModel(div, m); |
| + var template = div.firstChild; |
| + templateBind(template).model = m; |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 1); |
| @@ -101,6 +125,10 @@ templateElementTests() { |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 2); |
| expect(div.lastChild.text, 'text'); |
| + |
| + templateBind(template).model = null; |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 1); |
| }); |
| observeTest('Template Bind If, 2', () { |
| @@ -119,10 +147,11 @@ templateElementTests() { |
| observeTest('Template If', () { |
| var div = createTestHtml('<template if="{{ foo }}">{{ value }}</template>'); |
| - // Note: changed this value from 0->null because zero is not falsey in Dart. |
| - // See https://code.google.com/p/dart/issues/detail?id=11956 |
| + // Note: changed this value from 0->null because zero is not falsey in |
| + // Dart. See https://code.google.com/p/dart/issues/detail?id=11956 |
| var m = toObservable({ 'foo': null, 'value': 'foo' }); |
| - recursivelySetTemplateModel(div, m); |
| + var template = div.firstChild; |
| + templateBind(template).model = m; |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 1); |
| @@ -130,6 +159,23 @@ templateElementTests() { |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 2); |
| expect(div.lastChild.text, 'foo'); |
| + |
| + templateBind(template).model = null; |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 1); |
| + }); |
| + |
| + observeTest('Template Empty-If', () { |
| + var div = createTestHtml('<template if>{{ value }}</template>'); |
| + var m = toObservable({ 'value': 'foo' }); |
| + recursivelySetTemplateModel(div, null); |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 1); |
| + |
| + recursivelySetTemplateModel(div, m); |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 2); |
| + expect(div.lastChild.text, 'foo'); |
| }); |
| observeTest('Template Repeat If', () { |
| @@ -138,7 +184,8 @@ templateElementTests() { |
| // Note: changed this value from 0->null because zero is not falsey in Dart. |
| // See https://code.google.com/p/dart/issues/detail?id=11956 |
| var m = toObservable({ 'bar': null, 'foo': [1, 2, 3] }); |
| - recursivelySetTemplateModel(div, m); |
| + var template = div.firstChild; |
| + templateBind(template).model = m; |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 1); |
| @@ -148,6 +195,10 @@ templateElementTests() { |
| expect(div.nodes[1].text, '1'); |
| expect(div.nodes[2].text, '2'); |
| expect(div.nodes[3].text, '3'); |
| + |
| + templateBind(template).model = null; |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 1); |
| }); |
| observeTest('TextTemplateWithNullStringBinding', () { |
| @@ -177,7 +228,8 @@ templateElementTests() { |
| var div = createTestHtml( |
| '<template bind="{{ data }}">a{{b}}c</template>'); |
| var model = toObservable({ 'data': {'b': 'B'} }); |
| - recursivelySetTemplateModel(div, model); |
| + var template = div.firstChild; |
| + templateBind(template).model = model; |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.length, 2); |
| @@ -191,9 +243,14 @@ templateElementTests() { |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.last.text, 'aXc'); |
| - model['data'] = null; |
| + // Dart note: changed from `null` since our null means don't render a model. |
| + model['data'] = toObservable({}); |
| performMicrotaskCheckpoint(); |
| expect(div.nodes.last.text, 'ac'); |
| + |
| + model['data'] = null; |
| + performMicrotaskCheckpoint(); |
| + expect(div.nodes.length, 1); |
| }); |
| observeTest('TextTemplateWithBindingAndConditional', () { |
| @@ -599,7 +656,7 @@ templateElementTests() { |
| }); |
| observeTest('BindWithRef', () { |
| - var id = 't${new math.Random().nextDouble()}'; |
| + var id = 't${new math.Random().nextInt(100)}'; |
| var div = createTestHtml( |
| '<template id="$id">' |
| 'Hi {{ name }}' |
| @@ -618,6 +675,23 @@ templateElementTests() { |
| expect(t2.nextNode.text, 'Hi Fry'); |
| }); |
| + observeTest('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 }); |
| + recursivelySetTemplateModel(div, model); |
| + |
| + performMicrotaskCheckpoint(); |
| + expect(t2.nextNode.text, 'Hi Fry'); |
| + }); |
| + |
| observeTest('BindChanged', () { |
| var model = toObservable({ |
| 'XX': {'name': 'Leela', 'title': 'Captain'}, |
| @@ -1548,6 +1622,7 @@ templateElementTests() { |
| } |
| }); |
| + // Dart note: this test seems gone from JS. Keeping for posterity sake. |
| observeTest('BindShadowDOM createInstance', () { |
| if (ShadowRoot.supported) { |
| var model = toObservable({'name': 'Leela'}); |
| @@ -1674,11 +1749,100 @@ templateElementTests() { |
| expect(template3.content.nodes.length, 1); |
| expect(template3.content.nodes.first.text, 'Hello'); |
| }); |
| + |
| + observeTest('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())); |
| + |
| + performMicrotaskCheckpoint(); |
| + expect(template.nextNode.nextNode.nextNode.text, '2'); |
| + model['show'] = false; |
| + performMicrotaskCheckpoint(); |
| + model['show'] = true; |
| + performMicrotaskCheckpoint(); |
| + expect(template.nextNode.nextNode.nextNode.text, '2'); |
| + }); |
| + |
| + observeTest('issue-141', () { |
| + var div = createTestHtml( |
| + '<template bind>' + |
| + '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' + |
| + '</template>'); |
| + |
| + var model = toObservable({ |
| + 'foo1': 'foo1Value', |
| + 'foo2': 'foo2Value', |
| + 'bar': 'barValue' |
| + }); |
| + |
| + recursivelySetTemplateModel(div, model); |
| + performMicrotaskCheckpoint(); |
| + |
| + expect(div.lastChild.attributes['bar'], 'barValue'); |
| + }); |
| +} |
| + |
| +compatTests() { |
| + observeTest('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 model = toObservable({ |
| + 'color': 'red', |
| + 'url': 'pic.jpg', |
| + 'url2': 'link.html', |
| + 'number': 4 |
| + }); |
| + |
| + recursivelySetTemplateModel(div, model); |
| + performMicrotaskCheckpoint(); |
| + |
| + 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'); |
| + }); |
| +} |
| + |
| +class Issue285Syntax extends BindingDelegate { |
| + prepareInstanceModel(template) { |
| + if (template.id == 'del') return (val) => val * 2; |
| + } |
| } |
| class TestBindingSyntax extends BindingDelegate { |
| - getBinding(model, String path, name, node) { |
| - if (path.trim() == 'replaceme') return new ObservableBox('replaced'); |
| + prepareBinding(String path, name, node) { |
| + if (path.trim() == 'replaceme') { |
| + return (x, y) => new ObservableBox('replaced'); |
| + } |
| return null; |
| } |
| } |
| @@ -1687,11 +1851,14 @@ class UnbindingInNestedBindSyntax extends BindingDelegate { |
| int expectedAge = 42; |
| int count = 0; |
| - getBinding(model, path, name, node) { |
| + prepareBinding(path, name, node) { |
| if (name != 'text' || path != 'age') |
| return; |
|
Siggi Cherem (dart-lang)
2013/10/29 21:00:07
nit - use 'return null' to be more explicit?
Jennifer Messerly
2013/10/29 23:07:19
Done.
|
| - expect(model['age'], expectedAge); |
| - count++; |
| + return (model, node) { |
| + expect(model['age'], expectedAge); |
| + count++; |
| + return model; |
| + }; |
| } |
| } |