OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library binding_syntax_test; | 5 library binding_syntax_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 import 'dart:html'; | 9 import 'dart:html'; |
10 import 'package:mdv/mdv.dart' as mdv; | 10 import 'package:mdv/mdv.dart' as mdv; |
11 import 'package:observe/observe.dart'; | 11 import 'package:observe/observe.dart'; |
12 import 'package:unittest/html_config.dart'; | 12 import 'package:unittest/html_config.dart'; |
13 import 'package:unittest/unittest.dart'; | 13 import 'package:unittest/unittest.dart'; |
14 import 'observe_utils.dart'; | 14 import 'mdv_test_utils.dart'; |
15 | 15 |
16 // Note: this file ported from | 16 // Note: this file ported from |
17 // https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js | 17 // https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js |
18 | 18 |
19 main() { | 19 main() { |
20 mdv.initialize(); | 20 mdv.initialize(); |
21 useHtmlConfiguration(); | 21 useHtmlConfiguration(); |
22 group('Syntax', syntaxTests); | 22 |
| 23 group('Syntax FooBarModel', () { |
| 24 syntaxTests(([f, b]) => new FooBarModel(f, b)); |
| 25 }); |
| 26 group('Syntax FooBarNotifyModel', () { |
| 27 syntaxTests(([f, b]) => new FooBarNotifyModel(f, b)); |
| 28 }); |
23 } | 29 } |
24 | 30 |
25 syntaxTests() { | 31 syntaxTests(FooBarModel fooModel([foo, bar])) { |
26 var testDiv; | 32 var testDiv; |
27 | 33 |
28 setUp(() { | 34 setUp(() { |
29 document.body.append(testDiv = new DivElement()); | 35 document.body.append(testDiv = new DivElement()); |
30 }); | 36 }); |
31 | 37 |
32 tearDown(() { | 38 tearDown(() { |
33 testDiv.remove(); | 39 testDiv.remove(); |
34 testDiv = null; | 40 testDiv = null; |
35 }); | 41 }); |
36 | 42 |
37 createTestHtml(s) { | 43 createTestHtml(s) { |
38 var div = new DivElement(); | 44 var div = new DivElement(); |
39 div.innerHtml = s; | 45 div.innerHtml = s; |
40 testDiv.append(div); | 46 testDiv.append(div); |
41 | 47 |
42 for (var node in div.queryAll('*')) { | 48 for (var node in div.queryAll('*')) { |
43 if (node.isTemplate) TemplateElement.decorate(node); | 49 if (node.isTemplate) TemplateElement.decorate(node); |
44 } | 50 } |
45 | 51 |
46 return div; | 52 return div; |
47 } | 53 } |
48 | 54 |
49 recursivelySetTemplateModel(element, model) { | 55 recursivelySetTemplateModel(element, model) { |
50 for (var node in element.queryAll('*')) { | 56 for (var node in element.queryAll('*')) { |
51 if (node.isTemplate) node.model = model; | 57 if (node.isTemplate) node.model = model; |
52 } | 58 } |
53 } | 59 } |
54 | 60 |
55 test('Registration', () { | 61 observeTest('Registration', () { |
56 var model = toSymbolMap({'foo': 'bar'}); | 62 var model = fooModel('bar'); |
57 | 63 |
58 var testSyntax = new TestBindingSyntax(); | 64 var testSyntax = new TestBindingSyntax(); |
59 TemplateElement.syntax['Test'] = testSyntax; | 65 TemplateElement.syntax['Test'] = testSyntax; |
60 try { | 66 try { |
61 var div = createTestHtml( | 67 var div = createTestHtml( |
62 '<template bind syntax="Test">{{ foo }}' + | 68 '<template bind syntax="Test">{{ foo }}' + |
63 '<template bind>{{ foo }}</template></template>'); | 69 '<template bind>{{ foo }}</template></template>'); |
64 recursivelySetTemplateModel(div, model); | 70 recursivelySetTemplateModel(div, model); |
65 deliverChangeRecords(); | 71 performMicrotaskCheckpoint(); |
66 expect(div.nodes.length, 4); | 72 expect(div.nodes.length, 4); |
67 expect(div.nodes.last.text, 'bar'); | 73 expect(div.nodes.last.text, 'bar'); |
68 expect(div.nodes[2].tagName, 'TEMPLATE'); | 74 expect(div.nodes[2].tagName, 'TEMPLATE'); |
69 expect(div.nodes[2].attributes['syntax'], 'Test'); | 75 expect(div.nodes[2].attributes['syntax'], 'Test'); |
70 | 76 |
71 expect(testSyntax.log, [ | 77 expect(testSyntax.log, [ |
72 [model, '', 'bind', 'TEMPLATE'], | 78 [model, '', 'bind', 'TEMPLATE'], |
73 [model, 'foo', 'text', null], | 79 [model, 'foo', 'text', null], |
74 [model, '', 'bind', 'TEMPLATE'], | 80 [model, '', 'bind', 'TEMPLATE'], |
75 [model, 'foo', 'text', null], | 81 [model, 'foo', 'text', null], |
76 ]); | 82 ]); |
77 } finally { | 83 } finally { |
78 TemplateElement.syntax.remove('Test'); | 84 TemplateElement.syntax.remove('Test'); |
79 } | 85 } |
80 }); | 86 }); |
81 | 87 |
82 test('getInstanceModel', () { | 88 observeTest('getInstanceModel', () { |
83 var model = toObservable([{'foo': 1}, {'foo': 2}, {'foo': 3}] | 89 var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]); |
84 .map(toSymbolMap)); | |
85 | 90 |
86 var testSyntax = new TestModelSyntax(); | 91 var testSyntax = new TestModelSyntax(); |
87 testSyntax.altModels.addAll([{'foo': 'a'}, {'foo': 'b'}, {'foo': 'c'}] | 92 testSyntax.altModels.addAll([fooModel('a'), fooModel('b'), fooModel('c')]); |
88 .map(toSymbolMap)); | |
89 | 93 |
90 TemplateElement.syntax['Test'] = testSyntax; | 94 TemplateElement.syntax['Test'] = testSyntax; |
91 try { | 95 try { |
92 | 96 |
93 var div = createTestHtml( | 97 var div = createTestHtml( |
94 '<template repeat syntax="Test">' + | 98 '<template repeat syntax="Test">' + |
95 '{{ foo }}</template>'); | 99 '{{ foo }}</template>'); |
96 | 100 |
97 var template = div.nodes[0]; | 101 var template = div.nodes[0]; |
98 recursivelySetTemplateModel(div, model); | 102 recursivelySetTemplateModel(div, model); |
99 deliverChangeRecords(); | 103 performMicrotaskCheckpoint(); |
100 | 104 |
101 expect(div.nodes.length, 4); | 105 expect(div.nodes.length, 4); |
102 expect(div.nodes[0].tagName, 'TEMPLATE'); | 106 expect(div.nodes[0].tagName, 'TEMPLATE'); |
103 expect(div.nodes[1].text, 'a'); | 107 expect(div.nodes[1].text, 'a'); |
104 expect(div.nodes[2].text, 'b'); | 108 expect(div.nodes[2].text, 'b'); |
105 expect(div.nodes[3].text, 'c'); | 109 expect(div.nodes[3].text, 'c'); |
106 | 110 |
107 expect(testSyntax.log, [ | 111 expect(testSyntax.log, [ |
108 [template, model[0]], | 112 [template, model[0]], |
109 [template, model[1]], | 113 [template, model[1]], |
110 [template, model[2]], | 114 [template, model[2]], |
111 ]); | 115 ]); |
112 | 116 |
113 } finally { | 117 } finally { |
114 TemplateElement.syntax.remove('Test'); | 118 TemplateElement.syntax.remove('Test'); |
115 } | 119 } |
116 }); | 120 }); |
117 | 121 |
118 test('Basic', () { | 122 observeTest('Basic', () { |
119 var model = toSymbolMap({'foo': 2, 'bar': 4}); | 123 var model = fooModel(2, 4); |
120 | 124 |
121 TemplateElement.syntax['2x'] = new TimesTwoSyntax(); | 125 TemplateElement.syntax['2x'] = new TimesTwoSyntax(); |
122 | 126 |
123 var div = createTestHtml( | 127 var div = createTestHtml( |
124 '<template bind syntax="2x">' | 128 '<template bind syntax="2x">' |
125 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); | 129 '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>'); |
126 recursivelySetTemplateModel(div, model); | 130 recursivelySetTemplateModel(div, model); |
127 deliverChangeRecords(); | 131 performMicrotaskCheckpoint(); |
128 expect(div.nodes.length, 2); | 132 expect(div.nodes.length, 2); |
129 expect(div.nodes.last.text, '2 + 8 + '); | 133 expect(div.nodes.last.text, '2 + 8 + '); |
130 | 134 |
131 model[const Symbol('foo')] = 4; | 135 model.foo = 4; |
132 model[const Symbol('bar')] = 8; | 136 model.bar = 8; |
133 deliverChangeRecords(); | 137 performMicrotaskCheckpoint(); |
134 expect(div.nodes.last.text, '4 + 16 + '); | 138 expect(div.nodes.last.text, '4 + 16 + '); |
135 | 139 |
136 TemplateElement.syntax.remove('2x'); | 140 TemplateElement.syntax.remove('2x'); |
137 }); | 141 }); |
138 | 142 |
139 test('Different Sub-Template Syntax', () { | 143 observeTest('Different Sub-Template Syntax', () { |
140 var model = toSymbolMap({'foo': 'bar'}); | 144 var model = fooModel('bar'); |
141 | 145 |
142 TemplateElement.syntax['Test'] = new TestBindingSyntax(); | 146 TemplateElement.syntax['Test'] = new TestBindingSyntax(); |
143 TemplateElement.syntax['Test2'] = new TestBindingSyntax(); | 147 TemplateElement.syntax['Test2'] = new TestBindingSyntax(); |
144 | 148 |
145 var div = createTestHtml( | 149 var div = createTestHtml( |
146 '<template bind syntax="Test">{{ foo }}' | 150 '<template bind syntax="Test">{{ foo }}' |
147 '<template bind syntax="Test2">{{ foo }}</template></template>'); | 151 '<template bind syntax="Test2">{{ foo }}</template></template>'); |
148 recursivelySetTemplateModel(div, model); | 152 recursivelySetTemplateModel(div, model); |
149 deliverChangeRecords(); | 153 performMicrotaskCheckpoint(); |
150 expect(div.nodes.length, 4); | 154 expect(div.nodes.length, 4); |
151 expect(div.nodes.last.text, 'bar'); | 155 expect(div.nodes.last.text, 'bar'); |
152 expect(div.nodes[2].tagName, 'TEMPLATE'); | 156 expect(div.nodes[2].tagName, 'TEMPLATE'); |
153 expect(div.nodes[2].attributes['syntax'], 'Test2'); | 157 expect(div.nodes[2].attributes['syntax'], 'Test2'); |
154 | 158 |
155 var testLog = TemplateElement.syntax['Test'].log; | 159 var testLog = TemplateElement.syntax['Test'].log; |
156 var test2Log = TemplateElement.syntax['Test2'].log; | 160 var test2Log = TemplateElement.syntax['Test2'].log; |
157 | 161 |
158 expect(testLog, [ | 162 expect(testLog, [ |
159 [model, '', 'bind', 'TEMPLATE'], | 163 [model, '', 'bind', 'TEMPLATE'], |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 } | 217 } |
214 } | 218 } |
215 | 219 |
216 for (var node in toRemove) node.remove(); | 220 for (var node in toRemove) node.remove(); |
217 removed += toRemove.length; | 221 removed += toRemove.length; |
218 | 222 |
219 return instance; | 223 return instance; |
220 } | 224 } |
221 } | 225 } |
222 | 226 |
223 | |
224 class TimesTwoSyntax extends CustomBindingSyntax { | 227 class TimesTwoSyntax extends CustomBindingSyntax { |
225 getBinding(model, path, name, node) { | 228 getBinding(model, path, name, node) { |
226 path = path.trim(); | 229 path = path.trim(); |
227 if (!path.startsWith('2x:')) return null; | 230 if (!path.startsWith('2x:')) return null; |
228 | 231 |
229 path = path.substring(3); | 232 path = path.substring(3); |
230 return new CompoundBinding((values) => values['value'] * 2) | 233 return new CompoundBinding((values) => values['value'] * 2) |
231 ..bind('value', model, path); | 234 ..bind('value', model, path); |
232 } | 235 } |
233 } | 236 } |
OLD | NEW |