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

Side by Side Diff: packages/polymer_expressions/test/bindings_test.dart

Issue 2312183003: Removed Polymer from Observatory deps (Closed)
Patch Set: Created 4 years, 3 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
OLDNEW
(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 bindings_test;
6
7 import 'dart:async';
8 import 'dart:html';
9
10 import 'package:observe/observe.dart';
11 import 'package:observe/mirrors_used.dart'; // make test smaller.
12 import 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
13 import 'package:polymer_expressions/polymer_expressions.dart';
14 import 'package:smoke/mirrors.dart' as smoke;
15 import 'package:template_binding/template_binding.dart' show
16 TemplateBindExtension, templateBind;
17 import 'package:unittest/html_config.dart';
18
19 import 'package:unittest/unittest.dart';
20
21 var testDiv;
22
23 main() => dirtyCheckZone().run(() {
24 useHtmlConfiguration();
25 smoke.useMirrors();
26
27 group('bindings', () {
28 var stop = null;
29 setUp(() {
30 document.body.append(testDiv = new DivElement());
31 });
32
33 tearDown(() {
34 testDiv.remove();
35 testDiv = null;
36 });
37
38 test('should update binding when data changes', () {
39 var model = new NotifyModel();
40 var binding = new PolymerExpressions()
41 .prepareBinding('x', null, null)(model, null, false);
42 expect(binding.value, isNull);
43 model.x = "hi";
44 return new Future(() {
45 expect(binding.value, 'hi');
46 });
47 });
48
49 // regression test for issue 19296
50 test('should not throw when data changes', () {
51 var model = new NotifyModel();
52 testDiv.append(_createTemplateInstance(
53 '<template repeat="{{ i in x }}">{{ i }}</template>', model));
54
55 return new Future(() {
56 model.x = [1, 2, 3];
57 }).then(_nextMicrotask).then((_) {
58 expect(testDiv.text,'123');
59 });
60 });
61
62
63 test('should update text content when data changes', () {
64 var model = new NotifyModel('abcde');
65 testDiv.append(_createTemplateInstance('<span>{{x}}</span>', model));
66
67 var el;
68 return new Future(() {
69 el = testDiv.query("span");
70 expect(el.text, 'abcde');
71 expect(model.x, 'abcde');
72 model.x = '___';
73 }).then(_nextMicrotask).then((_) {
74 expect(model.x, '___');
75 expect(el.text, '___');
76 });
77 });
78
79 test('should log eval exceptions', () {
80 var model = new NotifyModel('abcde');
81 var completer = new Completer();
82 runZoned(() {
83 testDiv.append(_createTemplateInstance('<span>{{foo}}</span>', model));
84 return _nextMicrotask(null);
85 }, onError: (e) {
86 expect('$e', startsWith("Error evaluating expression 'foo':"));
87 completer.complete(true);
88 });
89 return completer.future;
90 });
91
92 test('detects changes to ObservableList', () {
93 var list = new ObservableList.from([1, 2, 3]);
94 var model = new NotifyModel(list);
95 testDiv.append(_createTemplateInstance('{{x[1]}}', model));
96
97 return new Future(() {
98 expect(testDiv.text, '2');
99 list[1] = 10;
100 }).then(_nextMicrotask).then((_) {
101 expect(testDiv.text, '10');
102 list[1] = 11;
103 }).then(_nextMicrotask).then((_) {
104 expect(testDiv.text, '11');
105 list[0] = 9;
106 }).then(_nextMicrotask).then((_) {
107 expect(testDiv.text, '11');
108 list.removeAt(0);
109 }).then(_nextMicrotask).then((_) {
110 expect(testDiv.text, '3');
111 list.add(90);
112 list.removeAt(0);
113 }).then(_nextMicrotask).then((_) {
114 expect(testDiv.text, '90');
115 });
116 });
117
118 // Regression tests for issue 18792.
119 for (var usePolymer in [true, false]) {
120 // We run these tests both with PolymerExpressions and with the default
121 // delegate to ensure the results are consistent. When possible, the
122 // expressions on these tests use syntax common to both delegates.
123 var name = usePolymer ? 'polymer-expressions' : 'default';
124 group('$name delegate', () {
125 // Use <option template repeat="{{y}}" value="{{}}">item {{}}
126 _initialSelectTest('{{y}}', '{{}}', usePolymer);
127 _updateSelectTest('{{y}}', '{{}}', usePolymer);
128 _detectKeyValueChanges(usePolymer);
129 if (usePolymer) _detectKeyValueChangesPolymerSyntax();
130 _cursorPositionTest(usePolymer);
131 });
132 }
133
134 group('polymer-expressions delegate, polymer syntax', () {
135 // Use <option template repeat="{{i in y}}" value="{{i}}">item {{i}}
136 _initialSelectTest('{{i in y}}', '{{i}}', true);
137 _updateSelectTest('{{i in y}}', '{{i}}', true);
138 });
139 });
140 });
141
142
143 _cursorPositionTest(bool usePolymer) {
144 test('should preserve the cursor position', () {
145 var model = new NotifyModel('abcde');
146 testDiv.append(_createTemplateInstance(
147 '<input id="i1" value={{x}}>', model, usePolymer: usePolymer));
148 var el;
149 return new Future(() {
150 el = testDiv.query("#i1");
151 var subscription = el.onInput.listen(expectAsync((_) {}, count: 1));
152 el.focus();
153
154 expect(el.value, 'abcde');
155 expect(model.x, 'abcde');
156
157 el.selectionStart = 3;
158 el.selectionEnd = 3;
159 expect(el.selectionStart, 3);
160 expect(el.selectionEnd, 3);
161
162 el.value = 'abc de';
163 // Updating the input value programmatically (even to the same value in
164 // Chrome) loses the selection position.
165 expect(el.selectionStart, 6);
166 expect(el.selectionEnd, 6);
167
168 el.selectionStart = 4;
169 el.selectionEnd = 4;
170
171 expect(model.x, 'abcde');
172 el.dispatchEvent(new Event('input'));
173 expect(model.x, 'abc de');
174 expect(el.value, 'abc de');
175
176 // But propagating observable values through reassign the value and
177 // selection will be preserved.
178 expect(el.selectionStart, 4);
179 expect(el.selectionEnd, 4);
180 subscription.cancel();
181 }).then(_nextMicrotask).then((_) {
182 // Nothing changes on the next micro task.
183 expect(el.selectionStart, 4);
184 expect(el.selectionEnd, 4);
185 }).then((_) => window.animationFrame).then((_) {
186 // ... or on the next animation frame.
187 expect(el.selectionStart, 4);
188 expect(el.selectionEnd, 4);
189 }).then(_afterTimeout).then((_) {
190 // ... or later.
191 expect(el.selectionStart, 4);
192 expect(el.selectionEnd, 4);
193 });
194 });
195 }
196
197 _initialSelectTest(String repeatExp, String valueExp, bool usePolymer) {
198 test('initial select value is set correctly', () {
199 var list = const ['a', 'b'];
200 var model = new NotifyModel('b', list);
201 testDiv.append(_createTemplateInstance('<select value="{{x}}">'
202 '<option template repeat="$repeatExp" value="$valueExp">item $valueExp'
203 '</option></select>',
204 model, usePolymer: usePolymer));
205
206 expect(testDiv.querySelector('select').value, 'b');
207 return new Future(() {
208 expect(model.x, 'b');
209 expect(testDiv.querySelector('select').value, 'b');
210 });
211 });
212 }
213
214 _updateSelectTest(String repeatExp, String valueExp, bool usePolymer) {
215 test('updates to select value propagate correctly', () {
216 var list = const ['a', 'b'];
217 var model = new NotifyModel('a', list);
218
219 testDiv.append(_createTemplateInstance('<select value="{{x}}">'
220 '<option template repeat="$repeatExp" value="$valueExp">item $valueExp'
221 '</option></select></template>', model, usePolymer: usePolymer));
222
223 expect(testDiv.querySelector('select').value, 'a');
224 return new Future(() {
225 expect(testDiv.querySelector('select').value, 'a');
226 model.x = 'b';
227 }).then(_nextMicrotask).then((_) {
228 expect(testDiv.querySelector('select').value, 'b');
229 });
230 });
231 }
232
233 _detectKeyValueChanges(bool usePolymer) {
234 test('detects changes to ObservableMap keys', () {
235 var map = new ObservableMap.from({'a': 1, 'b': 2});
236 var model = new NotifyModel(map);
237 testDiv.append(_createTemplateInstance(
238 '<template repeat="{{x.keys}}">{{}},</template>',
239 model, usePolymer: usePolymer));
240
241 return new Future(() {
242 expect(testDiv.text, 'a,b,');
243 map.remove('b');
244 map['c'] = 3;
245 }).then(_nextMicrotask).then((_) {
246 expect(testDiv.text, 'a,c,');
247 map['a'] = 4;
248 }).then(_nextMicrotask).then((_) {
249 expect(testDiv.text, 'a,c,');
250 });
251 });
252 }
253
254 // This test uses 'in', which is a polymer_expressions only feature.
255 _detectKeyValueChangesPolymerSyntax() {
256 test('detects changes to ObservableMap values', () {
257 var map = new ObservableMap.from({'a': 1, 'b': 2});
258 var model = new NotifyModel(map);
259 testDiv.append(_createTemplateInstance(
260 '<template repeat="{{k in x.keys}}">{{x[k]}},</template>', model));
261
262 return new Future(() {
263 expect(testDiv.text, '1,2,');
264 map.remove('b');
265 map['c'] = 3;
266 }).then(_nextMicrotask).then((_) {
267 expect(testDiv.text, '1,3,');
268 map['a'] = 4;
269 }).then(_nextMicrotask).then((_) {
270 expect(testDiv.text, '4,3,');
271 });
272 });
273 }
274
275 _createTemplateInstance(String templateBody, model, {bool usePolymer: true}) {
276 var tag = new Element.html('<template>$templateBody</template>',
277 treeSanitizer: _nullTreeSanitizer);
278 TemplateBindExtension.bootstrap(tag);
279 var template = templateBind(tag);
280 var delegate = usePolymer ? new PolymerExpressions() : null;
281 return template.createInstance(model, delegate);
282 }
283
284 _nextMicrotask(_) => new Future(() {});
285 _afterTimeout(_) => new Future.delayed(new Duration(milliseconds: 30), () {});
286
287 @reflectable
288 class NotifyModel extends ChangeNotifier {
289 var _x;
290 var _y;
291 NotifyModel([this._x, this._y]);
292
293 get x => _x;
294 set x(value) {
295 _x = notifyPropertyChange(#x, _x, value);
296 }
297
298 get y => _y;
299 set y(value) {
300 _y = notifyPropertyChange(#y, _y, value);
301 }
302 }
303
304 class _NullTreeSanitizer implements NodeTreeSanitizer {
305 void sanitizeTree(Node node) {}
306 }
307 final _nullTreeSanitizer = new _NullTreeSanitizer();
OLDNEW
« no previous file with comments | « packages/polymer_expressions/test/all_tests.dart ('k') | packages/polymer_expressions/test/bindings_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698