OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library template_binding.test.binding_syntax_test; | |
6 | |
7 import 'dart:collection'; | |
8 import 'dart:html'; | |
9 import 'package:template_binding/template_binding.dart'; | |
10 import 'package:observe/observe.dart'; | |
11 import 'package:unittest/html_config.dart'; | |
12 import 'package:unittest/unittest.dart'; | |
13 import 'utils.dart'; | |
14 | |
15 // Note: this file ported from | |
16 // https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js | |
17 | |
18 main() { | |
19 useHtmlConfiguration(); | |
20 | |
21 group('Syntax FooBarModel', () { | |
22 syntaxTests(([f, b]) => new FooBarModel(f, b)); | |
23 }); | |
24 group('Syntax FooBarNotifyModel', () { | |
25 syntaxTests(([f, b]) => new FooBarNotifyModel(f, b)); | |
26 }); | |
27 } | |
28 | |
29 syntaxTests(FooBarModel fooModel([foo, bar])) { | |
30 setUp(() { | |
31 document.body.append(testDiv = new DivElement()); | |
32 }); | |
33 | |
34 tearDown(() { | |
35 testDiv.remove(); | |
36 testDiv = null; | |
37 }); | |
38 | |
39 observeTest('Registration', () { | |
40 var model = fooModel('bar'); | |
41 var testSyntax = new TestBindingSyntax(); | |
42 var div = createTestHtml('<template bind>{{ foo }}' | |
43 '<template bind>{{ foo }}</template></template>'); | |
44 recursivelySetTemplateModel(div, model, testSyntax); | |
45 performMicrotaskCheckpoint(); | |
46 expect(div.nodes.length, 4); | |
47 expect(div.nodes.last.text, 'bar'); | |
48 expect(div.nodes[2].tagName, 'TEMPLATE'); | |
49 expect(testSyntax.log, [ | |
50 [model, '', 'bind', 'TEMPLATE'], | |
51 [model, 'foo', 'text', null], | |
52 [model, '', 'bind', 'TEMPLATE'], | |
53 [model, 'foo', 'text', null], | |
54 ]); | |
55 }); | |
56 | |
57 observeTest('getInstanceModel', () { | |
58 var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]); | |
59 | |
60 var testSyntax = new TestModelSyntax(); | |
61 testSyntax.altModels.addAll([fooModel('a'), fooModel('b'), fooModel('c')]); | |
62 | |
63 var div = createTestHtml('<template repeat>{{ foo }}</template>'); | |
64 | |
65 var template = div.nodes[0]; | |
66 recursivelySetTemplateModel(div, model, testSyntax); | |
67 performMicrotaskCheckpoint(); | |
68 | |
69 expect(div.nodes.length, 4); | |
70 expect(div.nodes[0].tagName, 'TEMPLATE'); | |
71 expect(div.nodes[1].text, 'a'); | |
72 expect(div.nodes[2].text, 'b'); | |
73 expect(div.nodes[3].text, 'c'); | |
74 | |
75 expect(testSyntax.log, [ | |
76 [template, model[0]], | |
77 [template, model[1]], | |
78 [template, model[2]], | |
79 ]); | |
80 }); | |
81 | |
82 observeTest('getInstanceModel - reorder instances', () { | |
83 var model = toObservable([0, 1, 2]); | |
84 | |
85 var div = createTestHtml('<template repeat syntax="Test">{{}}</template>'); | |
86 var template = div.firstChild; | |
87 var delegate = new TestInstanceModelSyntax(); | |
88 | |
89 recursivelySetTemplateModel(div, model, delegate); | |
90 performMicrotaskCheckpoint(); | |
91 expect(delegate.count, 3); | |
92 | |
93 // Note: intentionally mutate in place. | |
94 model.replaceRange(0, model.length, model.reversed.toList()); | |
95 performMicrotaskCheckpoint(); | |
96 expect(delegate.count, 3); | |
97 }); | |
98 | |
99 observeTest('Basic', () { | |
100 var model = fooModel(2, 4); | |
101 var div = createTestHtml( | |
102 '<template bind syntax="2x">' | |
103 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); | |
104 recursivelySetTemplateModel(div, model, new TimesTwoSyntax()); | |
105 performMicrotaskCheckpoint(); | |
106 expect(div.nodes.length, 2); | |
107 expect(div.nodes.last.text, '2 + 8 + '); | |
108 | |
109 model.foo = 4; | |
110 model.bar = 8; | |
111 performMicrotaskCheckpoint(); | |
112 expect(div.nodes.last.text, '4 + 16 + '); | |
113 }); | |
114 } | |
115 | |
116 // TODO(jmesserly): mocks would be cleaner here. | |
117 | |
118 class TestBindingSyntax extends BindingDelegate { | |
119 var log = []; | |
120 | |
121 getBinding(model, String path, String name, node) { | |
122 log.add([model, path, name, node is Element ? node.tagName : null]); | |
123 } | |
124 } | |
125 | |
126 class TestModelSyntax extends BindingDelegate { | |
127 var log = []; | |
128 var altModels = new ListQueue(); | |
129 | |
130 getInstanceModel(template, model) { | |
131 log.add([template, model]); | |
132 return altModels.removeFirst(); | |
133 } | |
134 } | |
135 | |
136 class TestInstanceModelSyntax extends BindingDelegate { | |
137 int count = 0; | |
138 getInstanceModel(template, model) { | |
139 count++; | |
140 return model; | |
141 } | |
142 } | |
143 | |
144 // Note: this isn't a very smart whitespace handler. A smarter one would only | |
145 // trim indentation, not all whitespace. | |
146 // See "trimOrCompact" in the web_ui Pub package. | |
147 class WhitespaceRemover extends BindingDelegate { | |
148 int trimmed = 0; | |
149 int removed = 0; | |
150 | |
151 DocumentFragment getInstanceFragment(Element template) { | |
152 var instance = templateBind(template).createInstance(); | |
153 var walker = new TreeWalker(instance, NodeFilter.SHOW_TEXT); | |
154 | |
155 var toRemove = []; | |
156 while (walker.nextNode() != null) { | |
157 var node = walker.currentNode; | |
158 var text = node.text.replaceAll('\n', '').trim(); | |
159 if (text.length != node.text.length) { | |
160 if (text.length == 0) { | |
161 toRemove.add(node); | |
162 } else { | |
163 trimmed++; | |
164 node.text = text; | |
165 } | |
166 } | |
167 } | |
168 | |
169 for (var node in toRemove) node.remove(); | |
170 removed += toRemove.length; | |
171 | |
172 return instance; | |
173 } | |
174 } | |
175 | |
176 class TimesTwoSyntax extends BindingDelegate { | |
177 getBinding(model, path, name, node) { | |
178 path = path.trim(); | |
179 if (!path.startsWith('2x:')) return null; | |
180 | |
181 path = path.substring(3); | |
182 return new CompoundBinding((values) => values['value'] * 2) | |
183 ..bind('value', model, path); | |
184 } | |
185 } | |
OLD | NEW |