| 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 bindings_test; | 5 library bindings_test; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 | 9 |
| 10 import 'package:observe/observe.dart'; | 10 import 'package:observe/observe.dart'; |
| 11 import 'package:observe/mirrors_used.dart'; // make test smaller. | 11 import 'package:observe/mirrors_used.dart'; // make test smaller. |
| 12 import 'package:observe/src/dirty_check.dart' show dirtyCheckZone; | 12 import 'package:observe/src/dirty_check.dart' show dirtyCheckZone; |
| 13 import 'package:polymer_expressions/polymer_expressions.dart'; | 13 import 'package:polymer_expressions/polymer_expressions.dart'; |
| 14 import 'package:template_binding/template_binding.dart' show templateBind; | 14 import 'package:smoke/mirrors.dart' as smoke; |
| 15 import 'package:template_binding/template_binding.dart' show |
| 16 TemplateBindExtension, templateBind; |
| 15 import 'package:unittest/html_config.dart'; | 17 import 'package:unittest/html_config.dart'; |
| 18 |
| 16 import 'package:unittest/unittest.dart'; | 19 import 'package:unittest/unittest.dart'; |
| 17 | 20 |
| 18 var testDiv; | 21 var testDiv; |
| 19 | 22 |
| 20 main() => dirtyCheckZone().run(() { | 23 main() => dirtyCheckZone().run(() { |
| 21 useHtmlConfiguration(); | 24 useHtmlConfiguration(); |
| 22 | 25 |
| 23 group('bindings', () { | 26 group('bindings', () { |
| 24 var stop = null; | 27 var stop = null; |
| 25 setUp(() { | 28 setUp(() { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 37 .prepareBinding('x', null, null)(model, null, false); | 40 .prepareBinding('x', null, null)(model, null, false); |
| 38 expect(binding.value, isNull); | 41 expect(binding.value, isNull); |
| 39 model.x = "hi"; | 42 model.x = "hi"; |
| 40 return new Future(() { | 43 return new Future(() { |
| 41 expect(binding.value, 'hi'); | 44 expect(binding.value, 'hi'); |
| 42 }); | 45 }); |
| 43 }); | 46 }); |
| 44 | 47 |
| 45 test('should update text content when data changes', () { | 48 test('should update text content when data changes', () { |
| 46 var model = new NotifyModel('abcde'); | 49 var model = new NotifyModel('abcde'); |
| 47 var template = templateBind(new Element.html( | 50 var tag = new Element.html( |
| 48 '<template><span>{{x}}</span></template>')); | 51 '<template><span>{{x}}</span></template>'); |
| 52 TemplateBindExtension.bootstrap(tag); |
| 53 var template = templateBind(tag); |
| 49 testDiv.append(template.createInstance(model, new PolymerExpressions())); | 54 testDiv.append(template.createInstance(model, new PolymerExpressions())); |
| 50 | 55 |
| 51 var el; | 56 var el; |
| 52 return new Future(() { | 57 return new Future(() { |
| 53 el = testDiv.query("span"); | 58 el = testDiv.query("span"); |
| 54 expect(el.text, 'abcde'); | 59 expect(el.text, 'abcde'); |
| 55 expect(model.x, 'abcde'); | 60 expect(model.x, 'abcde'); |
| 56 model.x = '___'; | 61 model.x = '___'; |
| 57 }).then(_nextMicrotask).then((_) { | 62 }).then(_nextMicrotask).then((_) { |
| 58 expect(model.x, '___'); | 63 expect(model.x, '___'); |
| 59 expect(el.text, '___'); | 64 expect(el.text, '___'); |
| 60 }); | 65 }); |
| 61 }); | 66 }); |
| 62 | 67 |
| 63 test('should log eval exceptions', () { | 68 test('should log eval exceptions', () { |
| 64 var model = new NotifyModel('abcde'); | 69 var model = new NotifyModel('abcde'); |
| 65 var completer = new Completer(); | 70 var completer = new Completer(); |
| 66 runZoned(() { | 71 runZoned(() { |
| 67 var template = templateBind(new Element.html( | 72 var tag = new Element.html( |
| 68 '<template><span>{{foo}}</span></template>')); | 73 '<template><span>{{foo}}</span></template>'); |
| 74 TemplateBindExtension.bootstrap(tag); |
| 75 var template = templateBind(tag); |
| 69 testDiv.append(template.createInstance(model, | 76 testDiv.append(template.createInstance(model, |
| 70 new PolymerExpressions())); | 77 new PolymerExpressions())); |
| 71 | 78 |
| 72 return _nextMicrotask(null); | 79 return _nextMicrotask(null); |
| 73 }, onError: (e) { | 80 }, onError: (e) { |
| 74 expect('$e', startsWith("Error evaluating expression 'foo':")); | 81 expect('$e', startsWith("Error evaluating expression 'foo':")); |
| 75 completer.complete(true); | 82 completer.complete(true); |
| 76 }); | 83 }); |
| 77 return completer.future; | 84 return completer.future; |
| 78 }); | 85 }); |
| 79 | 86 |
| 80 test('detects changes to ObservableList', () { | 87 test('detects changes to ObservableList', () { |
| 81 var list = new ObservableList.from([1, 2, 3]); | 88 var list = new ObservableList.from([1, 2, 3]); |
| 82 var template = templateBind(new Element.html( | 89 |
| 83 '<template>{{x[1]}}</template>')); | 90 var tag = new Element.html('<template>{{x[1]}}</template>'); |
| 91 TemplateBindExtension.bootstrap(tag); |
| 92 var template = templateBind(tag); |
| 93 |
| 84 var model = new NotifyModel(list); | 94 var model = new NotifyModel(list); |
| 85 testDiv.append(template.createInstance(model, new PolymerExpressions())); | 95 testDiv.append(template.createInstance(model, new PolymerExpressions())); |
| 86 | 96 |
| 87 return new Future(() { | 97 return new Future(() { |
| 88 expect(testDiv.text, '2'); | 98 expect(testDiv.text, '2'); |
| 89 list[1] = 10; | 99 list[1] = 10; |
| 90 }).then(_nextMicrotask).then((_) { | 100 }).then(_nextMicrotask).then((_) { |
| 91 expect(testDiv.text, '10'); | 101 expect(testDiv.text, '10'); |
| 92 list[1] = 11; | 102 list[1] = 11; |
| 93 }).then(_nextMicrotask).then((_) { | 103 }).then(_nextMicrotask).then((_) { |
| 94 expect(testDiv.text, '11'); | 104 expect(testDiv.text, '11'); |
| 95 list[0] = 9; | 105 list[0] = 9; |
| 96 }).then(_nextMicrotask).then((_) { | 106 }).then(_nextMicrotask).then((_) { |
| 97 expect(testDiv.text, '11'); | 107 expect(testDiv.text, '11'); |
| 98 list.removeAt(0); | 108 list.removeAt(0); |
| 99 }).then(_nextMicrotask).then((_) { | 109 }).then(_nextMicrotask).then((_) { |
| 100 expect(testDiv.text, '3'); | 110 expect(testDiv.text, '3'); |
| 101 list.add(90); | 111 list.add(90); |
| 102 list.removeAt(0); | 112 list.removeAt(0); |
| 103 }).then(_nextMicrotask).then((_) { | 113 }).then(_nextMicrotask).then((_) { |
| 104 expect(testDiv.text, '90'); | 114 expect(testDiv.text, '90'); |
| 105 }); | 115 }); |
| 106 }); | 116 }); |
| 107 | 117 |
| 108 test('detects changes to ObservableMap keys/values', () { | 118 test('detects changes to ObservableMap keys/values', () { |
| 109 var map = new ObservableMap.from({'a': 1, 'b': 2}); | 119 var map = new ObservableMap.from({'a': 1, 'b': 2}); |
| 110 var template = templateBind(new Element.html('<template>' | 120 |
| 121 var tag = new Element.html('<template>' |
| 111 '<template repeat="{{k in x.keys}}">{{k}}:{{x[k]}},</template>' | 122 '<template repeat="{{k in x.keys}}">{{k}}:{{x[k]}},</template>' |
| 112 '</template>')); | 123 '</template>'); |
| 124 TemplateBindExtension.bootstrap(tag); |
| 125 var template = templateBind(tag); |
| 126 |
| 113 var model = new NotifyModel(map); | 127 var model = new NotifyModel(map); |
| 114 testDiv.append(template.createInstance(model, new PolymerExpressions())); | 128 testDiv.append(template.createInstance(model, new PolymerExpressions())); |
| 115 | 129 |
| 116 return new Future(() { | 130 return new Future(() { |
| 117 expect(testDiv.text, 'a:1,b:2,'); | 131 expect(testDiv.text, 'a:1,b:2,'); |
| 118 map.remove('b'); | 132 map.remove('b'); |
| 119 map['c'] = 3; | 133 map['c'] = 3; |
| 120 }).then(_nextMicrotask).then((_) { | 134 }).then(_nextMicrotask).then((_) { |
| 121 expect(testDiv.text, 'a:1,c:3,'); | 135 expect(testDiv.text, 'a:1,c:3,'); |
| 122 map['a'] = 4; | 136 map['a'] = 4; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 147 _initialSelectTest('{{i in y}}', '{{i}}', true); | 161 _initialSelectTest('{{i in y}}', '{{i}}', true); |
| 148 _updateSelectTest('{{i in y}}', '{{i}}', true); | 162 _updateSelectTest('{{i in y}}', '{{i}}', true); |
| 149 }); | 163 }); |
| 150 }); | 164 }); |
| 151 }); | 165 }); |
| 152 | 166 |
| 153 | 167 |
| 154 _cursorPositionTest(bool usePolymer) { | 168 _cursorPositionTest(bool usePolymer) { |
| 155 test('should preserve the cursor position', () { | 169 test('should preserve the cursor position', () { |
| 156 var model = new NotifyModel('abcde'); | 170 var model = new NotifyModel('abcde'); |
| 157 var template = templateBind(new Element.html( | 171 |
| 158 '<template><input id="i1" value={{x}}></template>')); | 172 var tag = new Element.html( |
| 173 '<template><input id="i1" value={{x}}></template>'); |
| 174 TemplateBindExtension.bootstrap(tag); |
| 175 var template = templateBind(tag); |
| 176 |
| 159 var delegate = usePolymer ? new PolymerExpressions() : null; | 177 var delegate = usePolymer ? new PolymerExpressions() : null; |
| 160 testDiv.append(template.createInstance(model, delegate)); | 178 testDiv.append(template.createInstance(model, delegate)); |
| 161 | 179 |
| 162 var el; | 180 var el; |
| 163 return new Future(() { | 181 return new Future(() { |
| 164 el = testDiv.query("#i1"); | 182 el = testDiv.query("#i1"); |
| 165 var subscription = el.onInput.listen(expectAsync((_) {}, count: 1)); | 183 var subscription = el.onInput.listen(expectAsync((_) {}, count: 1)); |
| 166 el.focus(); | 184 el.focus(); |
| 167 | 185 |
| 168 expect(el.value, 'abcde'); | 186 expect(el.value, 'abcde'); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 // ... or later. | 222 // ... or later. |
| 205 expect(el.selectionStart, 4); | 223 expect(el.selectionStart, 4); |
| 206 expect(el.selectionEnd, 4); | 224 expect(el.selectionEnd, 4); |
| 207 }); | 225 }); |
| 208 }); | 226 }); |
| 209 } | 227 } |
| 210 | 228 |
| 211 _initialSelectTest(String repeatExp, String valueExp, bool usePolymer) { | 229 _initialSelectTest(String repeatExp, String valueExp, bool usePolymer) { |
| 212 test('initial select value is set correctly', () { | 230 test('initial select value is set correctly', () { |
| 213 var list = const ['a', 'b']; | 231 var list = const ['a', 'b']; |
| 214 var template = templateBind(new Element.html('<template>' | 232 |
| 233 var tag = new Element.html('<template>' |
| 215 '<select value="{{x}}">' | 234 '<select value="{{x}}">' |
| 216 '<option template repeat="$repeatExp" value="$valueExp">item $valueExp' | 235 '<option template repeat="$repeatExp" value="$valueExp">item $valueExp' |
| 217 '</option></select></template>', | 236 '</option></select></template>', |
| 218 treeSanitizer: _nullTreeSanitizer)); | 237 treeSanitizer: _nullTreeSanitizer); |
| 238 TemplateBindExtension.bootstrap(tag); |
| 239 var template = templateBind(tag); |
| 240 |
| 219 var model = new NotifyModel('b', list); | 241 var model = new NotifyModel('b', list); |
| 220 var delegate = usePolymer ? new PolymerExpressions() : null; | 242 var delegate = usePolymer ? new PolymerExpressions() : null; |
| 221 testDiv.append(template.createInstance(model, delegate)); | 243 testDiv.append(template.createInstance(model, delegate)); |
| 222 | 244 |
| 223 expect(testDiv.querySelector('select').value, 'b'); | 245 expect(testDiv.querySelector('select').value, 'b'); |
| 224 return new Future(() { | 246 return new Future(() { |
| 225 expect(model.x, 'b'); | 247 expect(model.x, 'b'); |
| 226 expect(testDiv.querySelector('select').value, 'b'); | 248 expect(testDiv.querySelector('select').value, 'b'); |
| 227 }); | 249 }); |
| 228 }); | 250 }); |
| 229 } | 251 } |
| 230 | 252 |
| 231 _updateSelectTest(String repeatExp, String valueExp, bool usePolymer) { | 253 _updateSelectTest(String repeatExp, String valueExp, bool usePolymer) { |
| 232 test('updates to select value propagate correctly', () { | 254 test('updates to select value propagate correctly', () { |
| 233 var list = const ['a', 'b']; | 255 var list = const ['a', 'b']; |
| 234 var template = templateBind(new Element.html('<template>' | 256 |
| 257 var tag = new Element.html('<template>' |
| 235 '<select value="{{x}}">' | 258 '<select value="{{x}}">' |
| 236 '<option template repeat="$repeatExp" value="$valueExp">item $valueExp' | 259 '<option template repeat="$repeatExp" value="$valueExp">item $valueExp' |
| 237 '</option></select></template>', | 260 '</option></select></template>', |
| 238 treeSanitizer: _nullTreeSanitizer)); | 261 treeSanitizer: _nullTreeSanitizer); |
| 262 TemplateBindExtension.bootstrap(tag); |
| 263 var template = templateBind(tag); |
| 264 |
| 239 var model = new NotifyModel('a', list); | 265 var model = new NotifyModel('a', list); |
| 240 var delegate = usePolymer ? new PolymerExpressions() : null; | 266 var delegate = usePolymer ? new PolymerExpressions() : null; |
| 241 testDiv.append(template.createInstance(model, delegate)); | 267 testDiv.append(template.createInstance(model, delegate)); |
| 242 | 268 |
| 243 expect(testDiv.querySelector('select').value, 'a'); | 269 expect(testDiv.querySelector('select').value, 'a'); |
| 244 return new Future(() { | 270 return new Future(() { |
| 245 expect(testDiv.querySelector('select').value, 'a'); | 271 expect(testDiv.querySelector('select').value, 'a'); |
| 246 model.x = 'b'; | 272 model.x = 'b'; |
| 247 }).then(_nextMicrotask).then((_) { | 273 }).then(_nextMicrotask).then((_) { |
| 248 expect(testDiv.querySelector('select').value, 'b'); | 274 expect(testDiv.querySelector('select').value, 'b'); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 267 get y => _y; | 293 get y => _y; |
| 268 set y(value) { | 294 set y(value) { |
| 269 _y = notifyPropertyChange(#y, _y, value); | 295 _y = notifyPropertyChange(#y, _y, value); |
| 270 } | 296 } |
| 271 } | 297 } |
| 272 | 298 |
| 273 class _NullTreeSanitizer implements NodeTreeSanitizer { | 299 class _NullTreeSanitizer implements NodeTreeSanitizer { |
| 274 void sanitizeTree(Node node) {} | 300 void sanitizeTree(Node node) {} |
| 275 } | 301 } |
| 276 final _nullTreeSanitizer = new _NullTreeSanitizer(); | 302 final _nullTreeSanitizer = new _NullTreeSanitizer(); |
| OLD | NEW |