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 custom_element_bindings_test; | 5 library custom_element_bindings_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:html'; | 8 import 'dart:html'; |
9 import 'package:mdv/mdv.dart' as mdv; | 9 import 'package:mdv/mdv.dart' as mdv; |
10 import 'package:observe/observe.dart'; | 10 import 'package:observe/observe.dart'; |
11 import 'package:unittest/html_config.dart'; | 11 import 'package:unittest/html_config.dart'; |
12 import 'package:unittest/unittest.dart'; | 12 import 'package:unittest/unittest.dart'; |
13 import 'observe_utils.dart'; | 13 import 'mdv_test_utils.dart'; |
14 | 14 |
15 main() { | 15 main() { |
16 mdv.initialize(); | 16 mdv.initialize(); |
17 useHtmlConfiguration(); | 17 useHtmlConfiguration(); |
18 group('Custom Element Bindings', customElementBindingsTest); | 18 group('Custom Element Bindings', customElementBindingsTest); |
19 } | 19 } |
20 | 20 |
21 sym(x) => new Symbol(x); | 21 sym(x) => new Symbol(x); |
22 | 22 |
23 customElementBindingsTest() { | 23 customElementBindingsTest() { |
(...skipping 14 matching lines...) Expand all Loading... |
38 testDiv.append(div); | 38 testDiv.append(div); |
39 | 39 |
40 for (var node in div.queryAll('*')) { | 40 for (var node in div.queryAll('*')) { |
41 if (node.isTemplate) TemplateElement.decorate(node); | 41 if (node.isTemplate) TemplateElement.decorate(node); |
42 } | 42 } |
43 | 43 |
44 return div; | 44 return div; |
45 } | 45 } |
46 | 46 |
47 | 47 |
48 test('override bind/unbind/unbindAll', () { | 48 observeTest('override bind/unbind/unbindAll', () { |
49 var element = new MyCustomElement(); | 49 var element = new MyCustomElement(); |
50 var model = toSymbolMap({'a': new Point(123, 444), 'b': new Monster(100)}); | 50 var model = toSymbolMap({'a': new Point(123, 444), 'b': new Monster(100)}); |
51 | 51 |
52 element.bind('my-point', model, 'a'); | 52 element.bind('my-point', model, 'a'); |
53 element.bind('scary-monster', model, 'b'); | 53 element.bind('scary-monster', model, 'b'); |
54 | 54 |
55 expect(element.attributes, isNot(contains('my-point'))); | 55 expect(element.attributes, isNot(contains('my-point'))); |
56 expect(element.attributes, isNot(contains('scary-monster'))); | 56 expect(element.attributes, isNot(contains('scary-monster'))); |
57 | 57 |
58 expect(element.myPoint, model[sym('a')]); | 58 expect(element.myPoint, model[sym('a')]); |
59 expect(element.scaryMonster, model[sym('b')]); | 59 expect(element.scaryMonster, model[sym('b')]); |
60 | 60 |
61 model[sym('a')] = null; | 61 model[sym('a')] = null; |
62 deliverChangeRecords(); | 62 performMicrotaskCheckpoint(); |
63 expect(element.myPoint, null); | 63 expect(element.myPoint, null); |
64 element.unbind('my-point'); | 64 element.unbind('my-point'); |
65 | 65 |
66 model[sym('a')] = new Point(1, 2); | 66 model[sym('a')] = new Point(1, 2); |
67 model[sym('b')] = new Monster(200); | 67 model[sym('b')] = new Monster(200); |
68 deliverChangeRecords(); | 68 performMicrotaskCheckpoint(); |
69 expect(element.scaryMonster, model[sym('b')]); | 69 expect(element.scaryMonster, model[sym('b')]); |
70 expect(element.myPoint, null, reason: 'a was unbound'); | 70 expect(element.myPoint, null, reason: 'a was unbound'); |
71 | 71 |
72 element.unbindAll(); | 72 element.unbindAll(); |
73 model[sym('b')] = null; | 73 model[sym('b')] = null; |
74 deliverChangeRecords(); | 74 performMicrotaskCheckpoint(); |
75 expect(element.scaryMonster.health, 200); | 75 expect(element.scaryMonster.health, 200); |
76 }); | 76 }); |
77 | 77 |
78 test('override attribute setter', () { | 78 observeTest('override attribute setter', () { |
79 var element = new WithAttrsCustomElement().real; | 79 var element = new WithAttrsCustomElement().real; |
80 var model = toSymbolMap({'a': 1, 'b': 2}); | 80 var model = toSymbolMap({'a': 1, 'b': 2}); |
81 element.bind('hidden?', model, 'a'); | 81 element.bind('hidden?', model, 'a'); |
82 element.bind('id', model, 'b'); | 82 element.bind('id', model, 'b'); |
83 | 83 |
84 expect(element.attributes, contains('hidden')); | 84 expect(element.attributes, contains('hidden')); |
85 expect(element.attributes['hidden'], ''); | 85 expect(element.attributes['hidden'], ''); |
86 expect(element.id, '2'); | 86 expect(element.id, '2'); |
87 | 87 |
88 model[sym('a')] = null; | 88 model[sym('a')] = null; |
89 deliverChangeRecords(); | 89 performMicrotaskCheckpoint(); |
90 expect(element.attributes, isNot(contains('hidden')), | 90 expect(element.attributes, isNot(contains('hidden')), |
91 reason: 'null is false-y'); | 91 reason: 'null is false-y'); |
92 | 92 |
93 model[sym('a')] = false; | 93 model[sym('a')] = false; |
94 deliverChangeRecords(); | 94 performMicrotaskCheckpoint(); |
95 expect(element.attributes, isNot(contains('hidden'))); | 95 expect(element.attributes, isNot(contains('hidden'))); |
96 | 96 |
97 model[sym('a')] = 'foo'; | 97 model[sym('a')] = 'foo'; |
| 98 // TODO(jmesserly): this is here to force an ordering between the two |
| 99 // changes. Otherwise the order depends on what order StreamController |
| 100 // chooses to fire the two listeners in. |
| 101 performMicrotaskCheckpoint(); |
| 102 |
98 model[sym('b')] = 'x'; | 103 model[sym('b')] = 'x'; |
99 deliverChangeRecords(); | 104 performMicrotaskCheckpoint(); |
100 expect(element.attributes, contains('hidden')); | 105 expect(element.attributes, contains('hidden')); |
101 expect(element.attributes['hidden'], ''); | 106 expect(element.attributes['hidden'], ''); |
102 expect(element.id, 'x'); | 107 expect(element.id, 'x'); |
103 | 108 |
104 expect(element.xtag.attributes.log, [ | 109 expect(element.xtag.attributes.log, [ |
105 ['remove', 'hidden?'], | 110 ['remove', 'hidden?'], |
106 ['[]=', 'hidden', ''], | 111 ['[]=', 'hidden', ''], |
107 ['remove', 'id'], | 112 ['remove', 'id'], |
108 ['[]=', 'id', '2'], | 113 ['[]=', 'id', '2'], |
109 ['remove', 'hidden'], | 114 ['remove', 'hidden'], |
110 ['remove', 'hidden'], | 115 ['remove', 'hidden'], |
111 ['[]=', 'hidden', ''], | 116 ['[]=', 'hidden', ''], |
112 ['[]=', 'id', 'x'], | 117 ['[]=', 'id', 'x'], |
113 ]); | 118 ]); |
114 }); | 119 }); |
115 | 120 |
116 test('template bind uses overridden custom element bind', () { | 121 observeTest('template bind uses overridden custom element bind', () { |
117 | 122 |
118 var model = toSymbolMap({'a': new Point(123, 444), 'b': new Monster(100)}); | 123 var model = toSymbolMap({'a': new Point(123, 444), 'b': new Monster(100)}); |
119 | 124 |
120 var div = createTestHtml('<template bind>' | 125 var div = createTestHtml('<template bind>' |
121 '<my-custom-element my-point="{{a}}" scary-monster="{{b}}">' | 126 '<my-custom-element my-point="{{a}}" scary-monster="{{b}}">' |
122 '</my-custom-element>' | 127 '</my-custom-element>' |
123 '</template>'); | 128 '</template>'); |
124 | 129 |
125 mdv.instanceCreated.listen((fragment) { | 130 mdv.instanceCreated.listen((fragment) { |
126 for (var e in fragment.queryAll('my-custom-element')) { | 131 for (var e in fragment.queryAll('my-custom-element')) { |
127 new MyCustomElement.attach(e); | 132 new MyCustomElement.attach(e); |
128 } | 133 } |
129 }); | 134 }); |
130 | 135 |
131 div.query('template').model = model; | 136 div.query('template').model = model; |
132 deliverChangeRecords(); | 137 performMicrotaskCheckpoint(); |
133 | 138 |
134 var element = div.nodes[1]; | 139 var element = div.nodes[1]; |
135 | 140 |
136 expect(element.xtag is MyCustomElement, true, | 141 expect(element.xtag is MyCustomElement, true, |
137 reason: '${element.xtag} should be a MyCustomElement'); | 142 reason: '${element.xtag} should be a MyCustomElement'); |
138 | 143 |
139 expect(element.xtag.myPoint, model[sym('a')]); | 144 expect(element.xtag.myPoint, model[sym('a')]); |
140 expect(element.xtag.scaryMonster, model[sym('b')]); | 145 expect(element.xtag.scaryMonster, model[sym('b')]); |
141 | 146 |
142 expect(element.attributes, isNot(contains('my-point'))); | 147 expect(element.attributes, isNot(contains('my-point'))); |
143 expect(element.attributes, isNot(contains('scary-monster'))); | 148 expect(element.attributes, isNot(contains('scary-monster'))); |
144 | 149 |
145 model[sym('a')] = null; | 150 model[sym('a')] = null; |
146 deliverChangeRecords(); | 151 performMicrotaskCheckpoint(); |
147 expect(element.xtag.myPoint, null); | 152 expect(element.xtag.myPoint, null); |
148 | 153 |
149 div.query('template').model = null; | 154 div.query('template').model = null; |
150 deliverChangeRecords(); | 155 performMicrotaskCheckpoint(); |
151 | 156 |
152 expect(element.parentNode, null, reason: 'element was detached'); | 157 expect(element.parentNode, null, reason: 'element was detached'); |
153 | 158 |
154 model[sym('a')] = new Point(1, 2); | 159 model[sym('a')] = new Point(1, 2); |
155 model[sym('b')] = new Monster(200); | 160 model[sym('b')] = new Monster(200); |
156 deliverChangeRecords(); | 161 performMicrotaskCheckpoint(); |
157 | 162 |
158 expect(element.xtag.myPoint, null, reason: 'model was unbound'); | 163 expect(element.xtag.myPoint, null, reason: 'model was unbound'); |
159 expect(element.xtag.scaryMonster.health, 100, reason: 'model was unbound'); | 164 expect(element.xtag.scaryMonster.health, 100, reason: 'model was unbound'); |
160 }); | 165 }); |
161 | 166 |
162 } | 167 } |
163 | 168 |
164 class Monster { | 169 class Monster { |
165 int health; | 170 int health; |
166 Monster(this.health); | 171 Monster(this.health); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 } | 283 } |
279 | 284 |
280 void clear() => _map.clear(); | 285 void clear() => _map.clear(); |
281 void forEach(void f(K key, V value)) => _map.forEach(f); | 286 void forEach(void f(K key, V value)) => _map.forEach(f); |
282 Iterable<K> get keys => _map.keys; | 287 Iterable<K> get keys => _map.keys; |
283 Iterable<V> get values => _map.values; | 288 Iterable<V> get values => _map.values; |
284 int get length => _map.length; | 289 int get length => _map.length; |
285 bool get isEmpty => _map.isEmpty; | 290 bool get isEmpty => _map.isEmpty; |
286 bool get isNotEmpty => _map.isNotEmpty; | 291 bool get isNotEmpty => _map.isNotEmpty; |
287 } | 292 } |
OLD | NEW |