Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(572)

Side by Side Diff: pkg/polymer_expressions/test/syntax_test.dart

Issue 141703024: Refactor of PolymerExpressions. Adds "as" expressions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Reviewable state. More readable tests. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:html'; 6 import 'dart:html';
7 7
8 import 'package:logging/logging.dart'; 8 import 'package:logging/logging.dart';
9 import 'package:observe/observe.dart'; 9 import 'package:observe/observe.dart';
10 import 'package:polymer_expressions/polymer_expressions.dart'; 10 import 'package:polymer_expressions/polymer_expressions.dart';
11 import 'package:template_binding/template_binding.dart'; 11 import 'package:template_binding/template_binding.dart';
12 import 'package:unittest/html_enhanced_config.dart'; 12 import 'package:unittest/html_enhanced_config.dart';
13 import 'package:unittest/unittest.dart'; 13 import 'package:unittest/unittest.dart';
14 14
15 main() { 15 main() {
16 useHtmlEnhancedConfiguration(); 16 useHtmlEnhancedConfiguration();
17 17
18 group('PolymerExpressions', () { 18 group('PolymerExpressions', () {
19 var testDiv; 19 DivElement testDiv;
20 20
21 setUp(() { 21 setUp(() {
22 document.body.append(testDiv = new DivElement()); 22 document.body.append(testDiv = new DivElement());
23 }); 23 });
24 24
25 tearDown(() { 25 tearDown(() {
26 testDiv.firstChild.remove(); 26 testDiv.children.clear();
27 testDiv = null; 27 testDiv = null;
28 }); 28 });
29 29
30 test('should make two-way bindings to inputs', () { 30 Future<Element> setUpTest(String html, {model: null, Map globals: null}) {
Jennifer Messerly 2014/01/31 02:48:50 : null is not needed
justinfagnani 2014/03/12 23:21:30 Done.
31 testDiv.nodes.add(new Element.html(''' 31 testDiv.innerHtml = html;
32 <template id="test" bind> 32 templateBind(querySelector('#test'))
33 <input id="input" value="{{ firstName }}"> 33 ..bindingDelegate = new PolymerExpressions(globals: globals)
34 </template>''')); 34 ..model = model;
35 var person = new Person('John', 'Messerly', ['A', 'B', 'C']); 35 return waitForChange(testDiv);
36 templateBind(query('#test')) 36 }
37 ..bindingDelegate = new PolymerExpressions() 37
38 ..model = person; 38 group('with template bind', () {
39 return new Future.delayed(new Duration()).then((_) { 39
40 InputElement input = query('#input'); 40 test('should show a simple binding', () =>
41 expect(input.value, 'John'); 41 setUpTest('''
42 input.focus(); 42 <template id="test" bind>
43 input.value = 'Justin'; 43 <div>{{ data + 'b' }}</div>
44 input.blur(); 44 </template>''',
45 var event = new Event('change'); 45 model: new Model('a'))
46 // TODO(justin): figure out how to trigger keyboard events to test 46 .then((_) {
47 // two-way bindings 47 expect(testDiv.children.length, 2);
48 }); 48 expect(testDiv.children[1].text, 'ab');
49 }); 49 }));
50 50
51 test('should handle null collections in "in" expressions', () { 51 test('should handle an expression in the bind attribute', () =>
52 testDiv.nodes.add(new Element.html(''' 52 setUpTest('''
53 <template id="test" bind> 53 <template id="test" bind="{{ data }}">
54 <template repeat="{{ item in items }}"> 54 <div>{{ this }}</div>
55 {{ item }} 55 </template>''',
56 </template> 56 model: new Model('a'))
57 </template>''')); 57 .then((_) {
58 templateBind(query('#test')).bindingDelegate = 58 expect(testDiv.children.length, 2);
59 new PolymerExpressions(globals: {'items': null}); 59 expect(testDiv.children[1].text, 'a');
60 // the template should be the only node 60 }));
61 expect(testDiv.nodes.length, 1); 61
62 expect(testDiv.nodes[0].id, 'test'); 62 test('should handle an "as" expression in the bind attribute', () =>
63 }); 63 setUpTest('''
64 64 <template id="test" bind="{{ data as a }}">
65 test('should silently handle bad variable names', () { 65 <div>{{ data }}</div>
66 var logger = new Logger('polymer_expressions'); 66 <div>{{ a }}</div>
67 var logFuture = logger.onRecord.toList(); 67 </template>''',
68 testDiv.nodes.add(new Element.html(''' 68 model: new Model('a'))
69 <template id="test" bind>{{ foo }}</template>''')); 69 .then((_) {
70 templateBind(query('#test')).bindingDelegate = new PolymerExpressions(); 70 expect(testDiv.children.length, 3);
71 return new Future(() { 71 expect(testDiv.children[1].text, 'a');
72 logger.clearListeners(); 72 expect(testDiv.children[2].text, 'a');
73 return logFuture.then((records) { 73 }));
74 expect(records.length, 1); 74
75 expect(records.first.message, 75 /**
76 contains('Error evaluating expression')); 76 * This test fails in dart2js because we appear to be tickling a bug in
77 expect(records.first.message, contains('foo')); 77 * mirrors via _TemplateIterator.
78 */
79 skip_test('should resolve names in the outer template from within a nested '
80 'template', () =>
81 setUpTest('''
82 <template id="test" bind>
83 <div>{{ a }}</div>
84 <div>{{ b }}</div>
85 <template bind="{{ b }}">
86 <div>{{ a }}</div>
87 <div>{{ b }}</div>
88 <div>{{ }}</div>
89 </template>
90 </template>''',
91 globals: {'a': 'aaa', 'b': 'bbb'})
92 .then((_) {
93 print("A");
94 expect(testDiv.children.map((c) => c.text),
95 ['', 'aaa', 'bbb', '', 'aaa', 'bbb', 'bbb']);
96 }));
97
98 test('should shadow names in the outer template from within a nested '
99 'template', () =>
100 setUpTest('''
101 <template id="test" bind>
102 <div>{{ a }}</div>
103 <div>{{ b }}</div>
104 <template bind="{{ b as a}}">
105 <div>{{ a }}</div>
106 <div>{{ b }}</div>
107 </template>
108 </template>''',
109 globals: {'a': 'aaa', 'b': 'bbb'})
110 .then((_) {
111 expect(testDiv.children.map((c) => c.text),
112 ['', 'aaa', 'bbb', '', 'bbb', 'bbb']);
113 }));
114
115 });
116
117 group('with template repeat', () {
118
119 test('should handle "in" expressions', () =>
120 setUpTest('''
121 <template id="test" bind>
122 <div>{{ data }}</div>
123 <template repeat="{{ item in items }}">
124 <div>{{ item }}{{ data }}</div>
125 </template>
126 </template>''',
127 globals: {'items': [1, 2, 3]},
128 model: new Model('a'))
129 .then((_) {
130 // expect 6 children: two templates, a div and three instances
131 expect(testDiv.children.map((c) => c.text),
132 ['', 'a', '', '1a', '2a', '3a']);
133 }));
134
135 });
136
137 group('with template if', () {
138
139 Future doTest(value, bool shouldRender) =>
140 setUpTest('''
141 <template id="test" bind>
142 <div>{{ data }}</div>
143 <template if="{{ show }}">
144 <div>{{ data }}</div>
145 </template>
146 </template>''',
147 globals: {'show': value},
148 model: new Model('a'))
149 .then((_) {
150 if (shouldRender) {
151 expect(testDiv.children.length, 4);
152 expect(testDiv.children[1].text, 'a');
153 expect(testDiv.children[3].text, 'a');
154 } else {
155 expect(testDiv.children.length, 3);
156 expect(testDiv.children[1].text, 'a');
157 }
158 });
159
160 test('should render for a true expression',
161 () => doTest(true, true));
162
163 test('should treat a non-null expression as truthy',
164 () => doTest('a', true));
165
166 test('should treat an empty list as truthy',
167 () => doTest([], true));
168
169 test('should handle a false expression',
170 () => doTest(false, false));
171
172 test('should treat null as falsey',
173 () => doTest(null, false));
174 });
175
176 group('error handling', () {
177
178 test('should handle and log bad variable names', () {
179 var logger = new Logger('polymer_expressions');
180 var logFuture = logger.onRecord.toList();
181 return setUpTest('''
182 <template id="test" bind>
183 <span>A</span>
184 <span>{{ foo }}</span>
185 <span>B</span>
186 </template>''')
187 .then((_) {
188 expect(testDiv.children.length, 4);
189 expect(testDiv.children.skip(1).map((c) => c.text), ['A', '', 'B']);
190 logger.clearListeners();
191 return logFuture.then((records) {
192 expect(records.length, 1);
193 expect(records.first.message,
194 contains('Error evaluating expression'));
195 expect(records.first.message, contains('foo'));
196 });
78 }); 197 });
79 }); 198 });
199
200 test('should handle null collections in "in" expressions', () =>
201 setUpTest('''
202 <template id="test" bind>
203 <template repeat="{{ item in items }}">
204 {{ item }}
205 </template>
206 </template>''',
207 globals: {'items': null})
208 .then((_) {
209 expect(testDiv.children.length, 2);
210 expect(testDiv.children[0].id, 'test');
211 }));
212
80 }); 213 });
81 }); 214 });
82 } 215 }
83 216
217 Future<Element> waitForChange(Element e) {
218 var completer = new Completer<Element>();
219 new MutationObserver((mutations, observer) {
220 observer.disconnect();
221 completer.complete(e);
222 }).observe(e, childList: true);
223 return completer.future;
224 }
225
84 @reflectable 226 @reflectable
85 class Person extends ChangeNotifier { 227 class Model extends ChangeNotifier {
86 String _firstName; 228 String _data;
87 String _lastName; 229
88 List<String> _items; 230 Model(this._data);
89 231
90 Person(this._firstName, this._lastName, this._items); 232 String get data => _data;
91 233
92 String get firstName => _firstName; 234 void set data(String value) {
93 235 _data = notifyPropertyChange(#data, _data, value);
94 void set firstName(String value) {
95 _firstName = notifyPropertyChange(#firstName, _firstName, value);
96 } 236 }
97 237
98 String get lastName => _lastName; 238 String toString() => "Model(data: $_data)";
99
100 void set lastName(String value) {
101 _lastName = notifyPropertyChange(#lastName, _lastName, value);
102 }
103
104 String getFullName() => '$_firstName $_lastName';
105
106 List<String> get items => _items;
107
108 void set items(List<String> value) {
109 _items = notifyPropertyChange(#items, _items, value);
110 }
111
112 String toString() => "Person(firstName: $_firstName, lastName: $_lastName)";
113 } 239 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698