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..2e5c3279952d9bfd48f4ea8b15890ec045070457 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,13 @@ class UnbindingInNestedBindSyntax extends BindingDelegate { |
int expectedAge = 42; |
int count = 0; |
- getBinding(model, path, name, node) { |
- if (name != 'text' || path != 'age') |
- return; |
+ prepareBinding(path, name, node) { |
+ if (name != 'text' || path != 'age') return null; |
- expect(model['age'], expectedAge); |
- count++; |
+ return (model, node) { |
+ expect(model['age'], expectedAge); |
+ count++; |
+ return model; |
+ }; |
} |
} |