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

Side by Side Diff: pkg/mdv/test/custom_element_bindings_test.dart

Issue 19771010: implement dirty checking for @observable objects (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: logging for loops in dirty checking Created 7 years, 5 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 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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698