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

Side by Side Diff: pkg/template_binding/test/template_element_test.dart

Issue 42433002: port Node.bind to bd0a0591920da9091b326627a46a104a92c7efe7 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 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 template_binding.test.template_element_test; 5 library template_binding.test.template_element_test;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:html'; 9 import 'dart:html';
10 import 'dart:math' as math; 10 import 'dart:math' as math;
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 expect(div.nodes[1].text, '1'); 148 expect(div.nodes[1].text, '1');
149 expect(div.nodes[2].text, '2'); 149 expect(div.nodes[2].text, '2');
150 expect(div.nodes[3].text, '3'); 150 expect(div.nodes[3].text, '3');
151 }); 151 });
152 152
153 observeTest('TextTemplateWithNullStringBinding', () { 153 observeTest('TextTemplateWithNullStringBinding', () {
154 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>'); 154 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>');
155 var model = toObservable({'b': 'B'}); 155 var model = toObservable({'b': 'B'});
156 recursivelySetTemplateModel(div, model); 156 recursivelySetTemplateModel(div, model);
157 157
158 deliverChanges(model); 158 performMicrotaskCheckpoint();
159 expect(div.nodes.length, 2); 159 expect(div.nodes.length, 2);
160 expect(div.nodes.last.text, 'aBc'); 160 expect(div.nodes.last.text, 'aBc');
161 161
162 model['b'] = 'b'; 162 model['b'] = 'b';
163 deliverChanges(model); 163 performMicrotaskCheckpoint();
164 expect(div.nodes.last.text, 'abc'); 164 expect(div.nodes.last.text, 'abc');
165 165
166 model['b'] = null; 166 model['b'] = null;
167 deliverChanges(model); 167 performMicrotaskCheckpoint();
168 expect(div.nodes.last.text, 'ac'); 168 expect(div.nodes.last.text, 'ac');
169 169
170 model = null; 170 model = null;
171 deliverChanges(model); 171 performMicrotaskCheckpoint();
172 // setting model isn't observable. 172 // setting model isn't observable.
173 expect(div.nodes.last.text, 'ac'); 173 expect(div.nodes.last.text, 'ac');
174 }); 174 });
175 175
176 observeTest('TextTemplateWithBindingPath', () { 176 observeTest('TextTemplateWithBindingPath', () {
177 var div = createTestHtml( 177 var div = createTestHtml(
178 '<template bind="{{ data }}">a{{b}}c</template>'); 178 '<template bind="{{ data }}">a{{b}}c</template>');
179 var model = toObservable({ 'data': {'b': 'B'} }); 179 var model = toObservable({ 'data': {'b': 'B'} });
180 recursivelySetTemplateModel(div, model); 180 recursivelySetTemplateModel(div, model);
181 181
182 deliverChanges(model); 182 performMicrotaskCheckpoint();
183 expect(div.nodes.length, 2); 183 expect(div.nodes.length, 2);
184 expect(div.nodes.last.text, 'aBc'); 184 expect(div.nodes.last.text, 'aBc');
185 185
186 model['data']['b'] = 'b'; 186 model['data']['b'] = 'b';
187 deliverChanges(model); 187 performMicrotaskCheckpoint();
188 expect(div.nodes.last.text, 'abc'); 188 expect(div.nodes.last.text, 'abc');
189 189
190 model['data'] = toObservable({'b': 'X'}); 190 model['data'] = toObservable({'b': 'X'});
191 deliverChanges(model); 191 performMicrotaskCheckpoint();
192 expect(div.nodes.last.text, 'aXc'); 192 expect(div.nodes.last.text, 'aXc');
193 193
194 model['data'] = null; 194 model['data'] = null;
195 deliverChanges(model); 195 performMicrotaskCheckpoint();
196 expect(div.nodes.last.text, 'ac'); 196 expect(div.nodes.last.text, 'ac');
197 }); 197 });
198 198
199 observeTest('TextTemplateWithBindingAndConditional', () { 199 observeTest('TextTemplateWithBindingAndConditional', () {
200 var div = createTestHtml( 200 var div = createTestHtml(
201 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>'); 201 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>');
202 var model = toObservable({'b': 'B', 'd': 1}); 202 var model = toObservable({'b': 'B', 'd': 1});
203 recursivelySetTemplateModel(div, model); 203 recursivelySetTemplateModel(div, model);
204 204
205 deliverChanges(model); 205 performMicrotaskCheckpoint();
206 expect(div.nodes.length, 2); 206 expect(div.nodes.length, 2);
207 expect(div.nodes.last.text, 'aBc'); 207 expect(div.nodes.last.text, 'aBc');
208 208
209 model['b'] = 'b'; 209 model['b'] = 'b';
210 deliverChanges(model); 210 performMicrotaskCheckpoint();
211 expect(div.nodes.last.text, 'abc'); 211 expect(div.nodes.last.text, 'abc');
212 212
213 // TODO(jmesserly): MDV set this to empty string and relies on JS conversion 213 // TODO(jmesserly): MDV set this to empty string and relies on JS conversion
214 // rules. Is that intended? 214 // rules. Is that intended?
215 // See https://github.com/toolkitchen/mdv/issues/59 215 // See https://github.com/toolkitchen/mdv/issues/59
216 model['d'] = null; 216 model['d'] = null;
217 deliverChanges(model); 217 performMicrotaskCheckpoint();
218 expect(div.nodes.length, 1); 218 expect(div.nodes.length, 1);
219 219
220 model['d'] = 'here'; 220 model['d'] = 'here';
221 model['b'] = 'd'; 221 model['b'] = 'd';
222 222
223 deliverChanges(model); 223 performMicrotaskCheckpoint();
224 expect(div.nodes.length, 2); 224 expect(div.nodes.length, 2);
225 expect(div.nodes.last.text, 'adc'); 225 expect(div.nodes.last.text, 'adc');
226 }); 226 });
227 227
228 observeTest('TemplateWithTextBinding2', () { 228 observeTest('TemplateWithTextBinding2', () {
229 var div = createTestHtml( 229 var div = createTestHtml(
230 '<template bind="{{ b }}">a{{value}}c</template>'); 230 '<template bind="{{ b }}">a{{value}}c</template>');
231 expect(div.nodes.length, 1); 231 expect(div.nodes.length, 1);
232 var model = toObservable({'b': {'value': 'B'}}); 232 var model = toObservable({'b': {'value': 'B'}});
233 recursivelySetTemplateModel(div, model); 233 recursivelySetTemplateModel(div, model);
234 234
235 deliverChanges(model); 235 performMicrotaskCheckpoint();
236 expect(div.nodes.length, 2); 236 expect(div.nodes.length, 2);
237 expect(div.nodes.last.text, 'aBc'); 237 expect(div.nodes.last.text, 'aBc');
238 238
239 model['b'] = toObservable({'value': 'b'}); 239 model['b'] = toObservable({'value': 'b'});
240 deliverChanges(model); 240 performMicrotaskCheckpoint();
241 expect(div.nodes.last.text, 'abc'); 241 expect(div.nodes.last.text, 'abc');
242 }); 242 });
243 243
244 observeTest('TemplateWithAttributeBinding', () { 244 observeTest('TemplateWithAttributeBinding', () {
245 var div = createTestHtml( 245 var div = createTestHtml(
246 '<template bind="{{}}">' 246 '<template bind="{{}}">'
247 '<div foo="a{{b}}c"></div>' 247 '<div foo="a{{b}}c"></div>'
248 '</template>'); 248 '</template>');
249 var model = toObservable({'b': 'B'}); 249 var model = toObservable({'b': 'B'});
250 recursivelySetTemplateModel(div, model); 250 recursivelySetTemplateModel(div, model);
251 251
252 deliverChanges(model); 252 performMicrotaskCheckpoint();
253 expect(div.nodes.length, 2); 253 expect(div.nodes.length, 2);
254 expect(div.nodes.last.attributes['foo'], 'aBc'); 254 expect(div.nodes.last.attributes['foo'], 'aBc');
255 255
256 model['b'] = 'b'; 256 model['b'] = 'b';
257 deliverChanges(model); 257 performMicrotaskCheckpoint();
258 expect(div.nodes.last.attributes['foo'], 'abc'); 258 expect(div.nodes.last.attributes['foo'], 'abc');
259 259
260 model['b'] = 'X'; 260 model['b'] = 'X';
261 deliverChanges(model); 261 performMicrotaskCheckpoint();
262 expect(div.nodes.last.attributes['foo'], 'aXc'); 262 expect(div.nodes.last.attributes['foo'], 'aXc');
263 }); 263 });
264 264
265 observeTest('TemplateWithConditionalBinding', () { 265 observeTest('TemplateWithConditionalBinding', () {
266 var div = createTestHtml( 266 var div = createTestHtml(
267 '<template bind="{{}}">' 267 '<template bind="{{}}">'
268 '<div foo?="{{b}}"></div>' 268 '<div foo?="{{b}}"></div>'
269 '</template>'); 269 '</template>');
270 var model = toObservable({'b': 'b'}); 270 var model = toObservable({'b': 'b'});
271 recursivelySetTemplateModel(div, model); 271 recursivelySetTemplateModel(div, model);
272 272
273 deliverChanges(model); 273 performMicrotaskCheckpoint();
274 expect(div.nodes.length, 2); 274 expect(div.nodes.length, 2);
275 expect(div.nodes.last.attributes['foo'], ''); 275 expect(div.nodes.last.attributes['foo'], '');
276 expect(div.nodes.last.attributes, isNot(contains('foo?'))); 276 expect(div.nodes.last.attributes, isNot(contains('foo?')));
277 277
278 model['b'] = null; 278 model['b'] = null;
279 deliverChanges(model); 279 performMicrotaskCheckpoint();
280 expect(div.nodes.last.attributes, isNot(contains('foo'))); 280 expect(div.nodes.last.attributes, isNot(contains('foo')));
281 }); 281 });
282 282
283 observeTest('Repeat', () { 283 observeTest('Repeat', () {
284 var div = createTestHtml( 284 var div = createTestHtml(
285 '<template repeat="{{}}"">text</template>'); 285 '<template repeat="{{}}"">text</template>');
286 286
287 var model = toObservable([0, 1, 2]); 287 var model = toObservable([0, 1, 2]);
288 recursivelySetTemplateModel(div, model); 288 recursivelySetTemplateModel(div, model);
289 289
290 deliverChanges(model); 290 performMicrotaskCheckpoint();
291 expect(div.nodes.length, 4); 291 expect(div.nodes.length, 4);
292 292
293 model.length = 1; 293 model.length = 1;
294 deliverChanges(model); 294 performMicrotaskCheckpoint();
295 expect(div.nodes.length, 2); 295 expect(div.nodes.length, 2);
296 296
297 model.addAll(toObservable([3, 4])); 297 model.addAll(toObservable([3, 4]));
298 deliverChanges(model); 298 performMicrotaskCheckpoint();
299 expect(div.nodes.length, 4); 299 expect(div.nodes.length, 4);
300 300
301 model.removeRange(1, 2); 301 model.removeRange(1, 2);
302 deliverChanges(model); 302 performMicrotaskCheckpoint();
303 expect(div.nodes.length, 3); 303 expect(div.nodes.length, 3);
304 }); 304 });
305 305
306 observeTest('Repeat - Reuse Instances', () { 306 observeTest('Repeat - Reuse Instances', () {
307 var div = createTestHtml('<template repeat>{{ val }}</template>'); 307 var div = createTestHtml('<template repeat>{{ val }}</template>');
308 308
309 var model = toObservable([ 309 var model = toObservable([
310 {'val': 10}, 310 {'val': 10},
311 {'val': 5}, 311 {'val': 5},
312 {'val': 2}, 312 {'val': 2},
313 {'val': 8}, 313 {'val': 8},
314 {'val': 1} 314 {'val': 1}
315 ]); 315 ]);
316 recursivelySetTemplateModel(div, model); 316 recursivelySetTemplateModel(div, model);
317 317
318 deliverChanges(model); 318 performMicrotaskCheckpoint();
319 expect(div.nodes.length, 6); 319 expect(div.nodes.length, 6);
320 var template = div.firstChild; 320 var template = div.firstChild;
321 321
322 addExpandos(template.nextNode); 322 addExpandos(template.nextNode);
323 checkExpandos(template.nextNode); 323 checkExpandos(template.nextNode);
324 324
325 model.sort((a, b) => a['val'] - b['val']); 325 model.sort((a, b) => a['val'] - b['val']);
326 deliverChanges(model); 326 performMicrotaskCheckpoint();
327 checkExpandos(template.nextNode); 327 checkExpandos(template.nextNode);
328 328
329 model = toObservable(model.reversed); 329 model = toObservable(model.reversed);
330 recursivelySetTemplateModel(div, model); 330 recursivelySetTemplateModel(div, model);
331 deliverChanges(model); 331 performMicrotaskCheckpoint();
332 checkExpandos(template.nextNode); 332 checkExpandos(template.nextNode);
333 333
334 for (var item in model) { 334 for (var item in model) {
335 item['val'] += 1; 335 item['val'] += 1;
336 } 336 }
337 337
338 deliverChanges(model); 338 performMicrotaskCheckpoint();
339 expect(div.nodes[1].text, "11"); 339 expect(div.nodes[1].text, "11");
340 expect(div.nodes[2].text, "9"); 340 expect(div.nodes[2].text, "9");
341 expect(div.nodes[3].text, "6"); 341 expect(div.nodes[3].text, "6");
342 expect(div.nodes[4].text, "3"); 342 expect(div.nodes[4].text, "3");
343 expect(div.nodes[5].text, "2"); 343 expect(div.nodes[5].text, "2");
344 }); 344 });
345 345
346 observeTest('Bind - Reuse Instance', () { 346 observeTest('Bind - Reuse Instance', () {
347 var div = createTestHtml( 347 var div = createTestHtml(
348 '<template bind="{{ foo }}">{{ bar }}</template>'); 348 '<template bind="{{ foo }}">{{ bar }}</template>');
349 349
350 var model = toObservable({ 'foo': { 'bar': 5 }}); 350 var model = toObservable({ 'foo': { 'bar': 5 }});
351 recursivelySetTemplateModel(div, model); 351 recursivelySetTemplateModel(div, model);
352 352
353 deliverChanges(model); 353 performMicrotaskCheckpoint();
354 expect(div.nodes.length, 2); 354 expect(div.nodes.length, 2);
355 var template = div.firstChild; 355 var template = div.firstChild;
356 356
357 addExpandos(template.nextNode); 357 addExpandos(template.nextNode);
358 checkExpandos(template.nextNode); 358 checkExpandos(template.nextNode);
359 359
360 model = toObservable({'foo': model['foo']}); 360 model = toObservable({'foo': model['foo']});
361 recursivelySetTemplateModel(div, model); 361 recursivelySetTemplateModel(div, model);
362 deliverChanges(model); 362 performMicrotaskCheckpoint();
363 checkExpandos(template.nextNode); 363 checkExpandos(template.nextNode);
364 }); 364 });
365 365
366 observeTest('Repeat-Empty', () { 366 observeTest('Repeat-Empty', () {
367 var div = createTestHtml( 367 var div = createTestHtml(
368 '<template repeat>text</template>'); 368 '<template repeat>text</template>');
369 369
370 var model = toObservable([0, 1, 2]); 370 var model = toObservable([0, 1, 2]);
371 recursivelySetTemplateModel(div, model); 371 recursivelySetTemplateModel(div, model);
372 372
373 deliverChanges(model); 373 performMicrotaskCheckpoint();
374 expect(div.nodes.length, 4); 374 expect(div.nodes.length, 4);
375 375
376 model.length = 1; 376 model.length = 1;
377 deliverChanges(model); 377 performMicrotaskCheckpoint();
378 expect(div.nodes.length, 2); 378 expect(div.nodes.length, 2);
379 379
380 model.addAll(toObservable([3, 4])); 380 model.addAll(toObservable([3, 4]));
381 deliverChanges(model); 381 performMicrotaskCheckpoint();
382 expect(div.nodes.length, 4); 382 expect(div.nodes.length, 4);
383 383
384 model.removeRange(1, 2); 384 model.removeRange(1, 2);
385 deliverChanges(model); 385 performMicrotaskCheckpoint();
386 expect(div.nodes.length, 3); 386 expect(div.nodes.length, 3);
387 }); 387 });
388 388
389 observeTest('Removal from iteration needs to unbind', () { 389 observeTest('Removal from iteration needs to unbind', () {
390 var div = createTestHtml( 390 var div = createTestHtml(
391 '<template repeat="{{}}"><a>{{v}}</a></template>'); 391 '<template repeat="{{}}"><a>{{v}}</a></template>');
392 var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, 392 var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3},
393 {'v': 4}]); 393 {'v': 4}]);
394 recursivelySetTemplateModel(div, model); 394 recursivelySetTemplateModel(div, model);
395 deliverChanges(model); 395 performMicrotaskCheckpoint();
396 396
397 var nodes = div.nodes.skip(1).toList(); 397 var nodes = div.nodes.skip(1).toList();
398 var vs = model.toList(); 398 var vs = model.toList();
399 399
400 for (var i = 0; i < 5; i++) { 400 for (var i = 0; i < 5; i++) {
401 expect(nodes[i].text, '$i'); 401 expect(nodes[i].text, '$i');
402 } 402 }
403 403
404 model.length = 3; 404 model.length = 3;
405 deliverChanges(model); 405 performMicrotaskCheckpoint();
406 for (var i = 0; i < 5; i++) { 406 for (var i = 0; i < 5; i++) {
407 expect(nodes[i].text, '$i'); 407 expect(nodes[i].text, '$i');
408 } 408 }
409 409
410 vs[3]['v'] = 33; 410 vs[3]['v'] = 33;
411 vs[4]['v'] = 44; 411 vs[4]['v'] = 44;
412 deliverChanges(model); 412 performMicrotaskCheckpoint();
413 for (var i = 0; i < 5; i++) { 413 for (var i = 0; i < 5; i++) {
414 expect(nodes[i].text, '$i'); 414 expect(nodes[i].text, '$i');
415 } 415 }
416 }); 416 });
417 417
418 observeTest('DOM Stability on Iteration', () { 418 observeTest('DOM Stability on Iteration', () {
419 var div = createTestHtml( 419 var div = createTestHtml(
420 '<template repeat="{{}}">{{}}</template>'); 420 '<template repeat="{{}}">{{}}</template>');
421 var model = toObservable([1, 2, 3, 4, 5]); 421 var model = toObservable([1, 2, 3, 4, 5]);
422 recursivelySetTemplateModel(div, model); 422 recursivelySetTemplateModel(div, model);
423 423
424 deliverChanges(model); 424 performMicrotaskCheckpoint();
425 425
426 // Note: the node at index 0 is the <template>. 426 // Note: the node at index 0 is the <template>.
427 var nodes = div.nodes.toList(); 427 var nodes = div.nodes.toList();
428 expect(nodes.length, 6, reason: 'list has 5 items'); 428 expect(nodes.length, 6, reason: 'list has 5 items');
429 429
430 model.removeAt(0); 430 model.removeAt(0);
431 model.removeLast(); 431 model.removeLast();
432 432
433 deliverChanges(model); 433 performMicrotaskCheckpoint();
434 expect(div.nodes.length, 4, reason: 'list has 3 items'); 434 expect(div.nodes.length, 4, reason: 'list has 3 items');
435 expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed'); 435 expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed');
436 expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed'); 436 expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed');
437 expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed'); 437 expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed');
438 438
439 model.insert(0, 5); 439 model.insert(0, 5);
440 model[2] = 6; 440 model[2] = 6;
441 model.add(7); 441 model.add(7);
442 442
443 deliverChanges(model); 443 performMicrotaskCheckpoint();
444 444
445 expect(div.nodes.length, 6, reason: 'list has 5 items'); 445 expect(div.nodes.length, 6, reason: 'list has 5 items');
446 expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node'); 446 expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node');
447 expect(identical(div.nodes[2], nodes[2]), true); 447 expect(identical(div.nodes[2], nodes[2]), true);
448 expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node'); 448 expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node');
449 expect(identical(div.nodes[4], nodes[4]), true); 449 expect(identical(div.nodes[4], nodes[4]), true);
450 expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node'); 450 expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node');
451 451
452 nodes = div.nodes.toList(); 452 nodes = div.nodes.toList();
453 453
454 model.insert(2, 8); 454 model.insert(2, 8);
455 455
456 deliverChanges(model); 456 performMicrotaskCheckpoint();
457 457
458 expect(div.nodes.length, 7, reason: 'list has 6 items'); 458 expect(div.nodes.length, 7, reason: 'list has 6 items');
459 expect(identical(div.nodes[1], nodes[1]), true); 459 expect(identical(div.nodes[1], nodes[1]), true);
460 expect(identical(div.nodes[2], nodes[2]), true); 460 expect(identical(div.nodes[2], nodes[2]), true);
461 expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node'); 461 expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node');
462 expect(identical(div.nodes[4], nodes[3]), true); 462 expect(identical(div.nodes[4], nodes[3]), true);
463 expect(identical(div.nodes[5], nodes[4]), true); 463 expect(identical(div.nodes[5], nodes[4]), true);
464 expect(identical(div.nodes[6], nodes[5]), true); 464 expect(identical(div.nodes[6], nodes[5]), true);
465 }); 465 });
466 466
467 observeTest('Repeat2', () { 467 observeTest('Repeat2', () {
468 var div = createTestHtml( 468 var div = createTestHtml(
469 '<template repeat="{{}}">{{value}}</template>'); 469 '<template repeat="{{}}">{{value}}</template>');
470 expect(div.nodes.length, 1); 470 expect(div.nodes.length, 1);
471 471
472 var model = toObservable([ 472 var model = toObservable([
473 {'value': 0}, 473 {'value': 0},
474 {'value': 1}, 474 {'value': 1},
475 {'value': 2} 475 {'value': 2}
476 ]); 476 ]);
477 recursivelySetTemplateModel(div, model); 477 recursivelySetTemplateModel(div, model);
478 478
479 deliverChanges(model); 479 performMicrotaskCheckpoint();
480 expect(div.nodes.length, 4); 480 expect(div.nodes.length, 4);
481 expect(div.nodes[1].text, '0'); 481 expect(div.nodes[1].text, '0');
482 expect(div.nodes[2].text, '1'); 482 expect(div.nodes[2].text, '1');
483 expect(div.nodes[3].text, '2'); 483 expect(div.nodes[3].text, '2');
484 484
485 model[1]['value'] = 'One'; 485 model[1]['value'] = 'One';
486 deliverChanges(model); 486 performMicrotaskCheckpoint();
487 expect(div.nodes.length, 4); 487 expect(div.nodes.length, 4);
488 expect(div.nodes[1].text, '0'); 488 expect(div.nodes[1].text, '0');
489 expect(div.nodes[2].text, 'One'); 489 expect(div.nodes[2].text, 'One');
490 expect(div.nodes[3].text, '2'); 490 expect(div.nodes[3].text, '2');
491 491
492 model.replaceRange(0, 1, toObservable([{'value': 'Zero'}])); 492 model.replaceRange(0, 1, toObservable([{'value': 'Zero'}]));
493 deliverChanges(model); 493 performMicrotaskCheckpoint();
494 expect(div.nodes.length, 4); 494 expect(div.nodes.length, 4);
495 expect(div.nodes[1].text, 'Zero'); 495 expect(div.nodes[1].text, 'Zero');
496 expect(div.nodes[2].text, 'One'); 496 expect(div.nodes[2].text, 'One');
497 expect(div.nodes[3].text, '2'); 497 expect(div.nodes[3].text, '2');
498 }); 498 });
499 499
500 observeTest('TemplateWithInputValue', () { 500 observeTest('TemplateWithInputValue', () {
501 var div = createTestHtml( 501 var div = createTestHtml(
502 '<template bind="{{}}">' 502 '<template bind="{{}}">'
503 '<input value="{{x}}">' 503 '<input value="{{x}}">'
504 '</template>'); 504 '</template>');
505 var model = toObservable({'x': 'hi'}); 505 var model = toObservable({'x': 'hi'});
506 recursivelySetTemplateModel(div, model); 506 recursivelySetTemplateModel(div, model);
507 507
508 deliverChanges(model); 508 performMicrotaskCheckpoint();
509 expect(div.nodes.length, 2); 509 expect(div.nodes.length, 2);
510 expect(div.nodes.last.value, 'hi'); 510 expect(div.nodes.last.value, 'hi');
511 511
512 model['x'] = 'bye'; 512 model['x'] = 'bye';
513 expect(div.nodes.last.value, 'hi'); 513 expect(div.nodes.last.value, 'hi');
514 deliverChanges(model); 514 performMicrotaskCheckpoint();
515 expect(div.nodes.last.value, 'bye'); 515 expect(div.nodes.last.value, 'bye');
516 516
517 div.nodes.last.value = 'hello'; 517 div.nodes.last.value = 'hello';
518 dispatchEvent('input', div.nodes.last); 518 dispatchEvent('input', div.nodes.last);
519 expect(model['x'], 'hello'); 519 expect(model['x'], 'hello');
520 deliverChanges(model); 520 performMicrotaskCheckpoint();
521 expect(div.nodes.last.value, 'hello'); 521 expect(div.nodes.last.value, 'hello');
522 }); 522 });
523 523
524 ////////////////////////////////////////////////////////////////////////////// 524 //////////////////////////////////////////////////////////////////////////////
525 525
526 observeTest('Decorated', () { 526 observeTest('Decorated', () {
527 var div = createTestHtml( 527 var div = createTestHtml(
528 '<template bind="{{ XX }}" id="t1">' 528 '<template bind="{{ XX }}" id="t1">'
529 '<p>Crew member: {{name}}, Job title: {{title}}</p>' 529 '<p>Crew member: {{name}}, Job title: {{title}}</p>'
530 '</template>' 530 '</template>'
531 '<template bind="{{ XY }}" id="t2" ref="t1"></template>'); 531 '<template bind="{{ XY }}" id="t2" ref="t1"></template>');
532 532
533 var model = toObservable({ 533 var model = toObservable({
534 'XX': {'name': 'Leela', 'title': 'Captain'}, 534 'XX': {'name': 'Leela', 'title': 'Captain'},
535 'XY': {'name': 'Fry', 'title': 'Delivery boy'}, 535 'XY': {'name': 'Fry', 'title': 'Delivery boy'},
536 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'} 536 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
537 }); 537 });
538 recursivelySetTemplateModel(div, model); 538 recursivelySetTemplateModel(div, model);
539 539
540 deliverChanges(model); 540 performMicrotaskCheckpoint();
541 541
542 var t1 = document.getElementById('t1'); 542 var t1 = document.getElementById('t1');
543 var instance = t1.nextElementSibling; 543 var instance = t1.nextElementSibling;
544 expect(instance.text, 'Crew member: Leela, Job title: Captain'); 544 expect(instance.text, 'Crew member: Leela, Job title: Captain');
545 545
546 var t2 = document.getElementById('t2'); 546 var t2 = document.getElementById('t2');
547 instance = t2.nextElementSibling; 547 instance = t2.nextElementSibling;
548 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy'); 548 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
549 549
550 expect(div.children.length, 4); 550 expect(div.children.length, 4);
(...skipping 12 matching lines...) Expand all
563 563
564 t.remove(); 564 t.remove();
565 }); 565 });
566 566
567 567
568 observeTest('Bind', () { 568 observeTest('Bind', () {
569 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>'); 569 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>');
570 var model = toObservable({'name': 'Leela'}); 570 var model = toObservable({'name': 'Leela'});
571 recursivelySetTemplateModel(div, model); 571 recursivelySetTemplateModel(div, model);
572 572
573 deliverChanges(model); 573 performMicrotaskCheckpoint();
574 expect(div.nodes[1].text, 'Hi Leela'); 574 expect(div.nodes[1].text, 'Hi Leela');
575 }); 575 });
576 576
577 observeTest('BindImperative', () { 577 observeTest('BindImperative', () {
578 var div = createTestHtml( 578 var div = createTestHtml(
579 '<template>' 579 '<template>'
580 'Hi {{ name }}' 580 'Hi {{ name }}'
581 '</template>'); 581 '</template>');
582 var t = div.nodes.first; 582 var t = div.nodes.first;
583 583
584 var model = toObservable({'name': 'Leela'}); 584 var model = toObservable({'name': 'Leela'});
585 nodeBind(t).bind('bind', model, ''); 585 nodeBind(t).bind('bind', model, '');
586 586
587 deliverChanges(model); 587 performMicrotaskCheckpoint();
588 expect(div.nodes[1].text, 'Hi Leela'); 588 expect(div.nodes[1].text, 'Hi Leela');
589 }); 589 });
590 590
591 observeTest('BindPlaceHolderHasNewLine', () { 591 observeTest('BindPlaceHolderHasNewLine', () {
592 var div = createTestHtml( 592 var div = createTestHtml(
593 '<template bind="{{}}">Hi {{\nname\n}}</template>'); 593 '<template bind="{{}}">Hi {{\nname\n}}</template>');
594 var model = toObservable({'name': 'Leela'}); 594 var model = toObservable({'name': 'Leela'});
595 recursivelySetTemplateModel(div, model); 595 recursivelySetTemplateModel(div, model);
596 596
597 deliverChanges(model); 597 performMicrotaskCheckpoint();
598 expect(div.nodes[1].text, 'Hi Leela'); 598 expect(div.nodes[1].text, 'Hi Leela');
599 }); 599 });
600 600
601 observeTest('BindWithRef', () { 601 observeTest('BindWithRef', () {
602 var id = 't${new math.Random().nextDouble()}'; 602 var id = 't${new math.Random().nextDouble()}';
603 var div = createTestHtml( 603 var div = createTestHtml(
604 '<template id="$id">' 604 '<template id="$id">'
605 'Hi {{ name }}' 605 'Hi {{ name }}'
606 '</template>' 606 '</template>'
607 '<template ref="$id" bind="{{}}"></template>'); 607 '<template ref="$id" bind="{{}}"></template>');
608 608
609 var t1 = div.nodes.first; 609 var t1 = div.nodes.first;
610 var t2 = div.nodes[1]; 610 var t2 = div.nodes[1];
611 611
612 expect(templateBind(t2).ref, t1); 612 expect(templateBind(t2).ref, t1);
613 613
614 var model = toObservable({'name': 'Fry'}); 614 var model = toObservable({'name': 'Fry'});
615 recursivelySetTemplateModel(div, model); 615 recursivelySetTemplateModel(div, model);
616 616
617 deliverChanges(model); 617 performMicrotaskCheckpoint();
618 expect(t2.nextNode.text, 'Hi Fry'); 618 expect(t2.nextNode.text, 'Hi Fry');
619 }); 619 });
620 620
621 observeTest('BindChanged', () { 621 observeTest('BindChanged', () {
622 var model = toObservable({ 622 var model = toObservable({
623 'XX': {'name': 'Leela', 'title': 'Captain'}, 623 'XX': {'name': 'Leela', 'title': 'Captain'},
624 'XY': {'name': 'Fry', 'title': 'Delivery boy'}, 624 'XY': {'name': 'Fry', 'title': 'Delivery boy'},
625 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'} 625 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
626 }); 626 });
627 627
628 var div = createTestHtml( 628 var div = createTestHtml(
629 '<template bind="{{ XX }}">Hi {{ name }}</template>'); 629 '<template bind="{{ XX }}">Hi {{ name }}</template>');
630 630
631 recursivelySetTemplateModel(div, model); 631 recursivelySetTemplateModel(div, model);
632 632
633 var t = div.nodes.first; 633 var t = div.nodes.first;
634 deliverChanges(model); 634 performMicrotaskCheckpoint();
635 635
636 expect(div.nodes.length, 2); 636 expect(div.nodes.length, 2);
637 expect(t.nextNode.text, 'Hi Leela'); 637 expect(t.nextNode.text, 'Hi Leela');
638 638
639 nodeBind(t).bind('bind', model, 'XZ'); 639 nodeBind(t).bind('bind', model, 'XZ');
640 deliverChanges(model); 640 performMicrotaskCheckpoint();
641 641
642 expect(div.nodes.length, 2); 642 expect(div.nodes.length, 2);
643 expect(t.nextNode.text, 'Hi Zoidberg'); 643 expect(t.nextNode.text, 'Hi Zoidberg');
644 }); 644 });
645 645
646 assertNodesAre(div, [arguments]) { 646 assertNodesAre(div, [arguments]) {
647 var expectedLength = arguments.length; 647 var expectedLength = arguments.length;
648 expect(div.nodes.length, expectedLength + 1); 648 expect(div.nodes.length, expectedLength + 1);
649 649
650 for (var i = 0; i < arguments.length; i++) { 650 for (var i = 0; i < arguments.length; i++) {
651 var targetNode = div.nodes[i + 1]; 651 var targetNode = div.nodes[i + 1];
652 expect(targetNode.text, arguments[i]); 652 expect(targetNode.text, arguments[i]);
653 } 653 }
654 } 654 }
655 655
656 observeTest('Repeat3', () { 656 observeTest('Repeat3', () {
657 var div = createTestHtml( 657 var div = createTestHtml(
658 '<template repeat="{{ contacts }}">Hi {{ name }}</template>'); 658 '<template repeat="{{ contacts }}">Hi {{ name }}</template>');
659 var t = div.nodes.first; 659 var t = div.nodes.first;
660 660
661 var m = toObservable({ 661 var m = toObservable({
662 'contacts': [ 662 'contacts': [
663 {'name': 'Raf'}, 663 {'name': 'Raf'},
664 {'name': 'Arv'}, 664 {'name': 'Arv'},
665 {'name': 'Neal'} 665 {'name': 'Neal'}
666 ] 666 ]
667 }); 667 });
668 668
669 recursivelySetTemplateModel(div, m); 669 recursivelySetTemplateModel(div, m);
670 deliverChanges(m); 670 performMicrotaskCheckpoint();
671 671
672 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 672 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
673 673
674 m['contacts'].add(toObservable({'name': 'Alex'})); 674 m['contacts'].add(toObservable({'name': 'Alex'}));
675 deliverChanges(m); 675 performMicrotaskCheckpoint();
676 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); 676 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
677 677
678 m['contacts'].replaceRange(0, 2, 678 m['contacts'].replaceRange(0, 2,
679 toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); 679 toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
680 deliverChanges(m); 680 performMicrotaskCheckpoint();
681 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']); 681 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
682 682
683 m['contacts'].removeRange(1, 3); 683 m['contacts'].removeRange(1, 3);
684 deliverChanges(m); 684 performMicrotaskCheckpoint();
685 assertNodesAre(div, ['Hi Rafael', 'Hi Alex']); 685 assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
686 686
687 m['contacts'].insertAll(1, 687 m['contacts'].insertAll(1,
688 toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}])); 688 toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
689 deliverChanges(m); 689 performMicrotaskCheckpoint();
690 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']); 690 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
691 691
692 m['contacts'].replaceRange(0, 1, 692 m['contacts'].replaceRange(0, 1,
693 toObservable([{'name': 'Tab'}, {'name': 'Neal'}])); 693 toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
694 deliverChanges(m); 694 performMicrotaskCheckpoint();
695 assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri', 695 assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
696 'Hi Alex']); 696 'Hi Alex']);
697 697
698 m['contacts'] = toObservable([{'name': 'Alex'}]); 698 m['contacts'] = toObservable([{'name': 'Alex'}]);
699 deliverChanges(m); 699 performMicrotaskCheckpoint();
700 assertNodesAre(div, ['Hi Alex']); 700 assertNodesAre(div, ['Hi Alex']);
701 701
702 m['contacts'].length = 0; 702 m['contacts'].length = 0;
703 deliverChanges(m); 703 performMicrotaskCheckpoint();
704 assertNodesAre(div, []); 704 assertNodesAre(div, []);
705 }); 705 });
706 706
707 observeTest('RepeatModelSet', () { 707 observeTest('RepeatModelSet', () {
708 var div = createTestHtml( 708 var div = createTestHtml(
709 '<template repeat="{{ contacts }}">' 709 '<template repeat="{{ contacts }}">'
710 'Hi {{ name }}' 710 'Hi {{ name }}'
711 '</template>'); 711 '</template>');
712 var m = toObservable({ 712 var m = toObservable({
713 'contacts': [ 713 'contacts': [
714 {'name': 'Raf'}, 714 {'name': 'Raf'},
715 {'name': 'Arv'}, 715 {'name': 'Arv'},
716 {'name': 'Neal'} 716 {'name': 'Neal'}
717 ] 717 ]
718 }); 718 });
719 recursivelySetTemplateModel(div, m); 719 recursivelySetTemplateModel(div, m);
720 720
721 deliverChanges(m); 721 performMicrotaskCheckpoint();
722 var t = div.nodes.first; 722 var t = div.nodes.first;
723 723
724 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 724 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
725 }); 725 });
726 726
727 observeTest('RepeatEmptyPath', () { 727 observeTest('RepeatEmptyPath', () {
728 var div = createTestHtml( 728 var div = createTestHtml(
729 '<template repeat="{{}}">Hi {{ name }}</template>'); 729 '<template repeat="{{}}">Hi {{ name }}</template>');
730 var t = div.nodes.first; 730 var t = div.nodes.first;
731 731
732 var m = toObservable([ 732 var m = toObservable([
733 {'name': 'Raf'}, 733 {'name': 'Raf'},
734 {'name': 'Arv'}, 734 {'name': 'Arv'},
735 {'name': 'Neal'} 735 {'name': 'Neal'}
736 ]); 736 ]);
737 recursivelySetTemplateModel(div, m); 737 recursivelySetTemplateModel(div, m);
738 738
739 deliverChanges(m); 739 performMicrotaskCheckpoint();
740 740
741 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 741 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
742 742
743 m.add(toObservable({'name': 'Alex'})); 743 m.add(toObservable({'name': 'Alex'}));
744 deliverChanges(m); 744 performMicrotaskCheckpoint();
745 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); 745 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
746 746
747 m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); 747 m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
748 deliverChanges(m); 748 performMicrotaskCheckpoint();
749 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']); 749 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
750 750
751 m.removeRange(1, 3); 751 m.removeRange(1, 3);
752 deliverChanges(m); 752 performMicrotaskCheckpoint();
753 assertNodesAre(div, ['Hi Rafael', 'Hi Alex']); 753 assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
754 754
755 m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}])); 755 m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
756 deliverChanges(m); 756 performMicrotaskCheckpoint();
757 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']); 757 assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
758 758
759 m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}])); 759 m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
760 deliverChanges(m); 760 performMicrotaskCheckpoint();
761 assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri', 761 assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
762 'Hi Alex']); 762 'Hi Alex']);
763 763
764 m.length = 0; 764 m.length = 0;
765 m.add(toObservable({'name': 'Alex'})); 765 m.add(toObservable({'name': 'Alex'}));
766 deliverChanges(m); 766 performMicrotaskCheckpoint();
767 assertNodesAre(div, ['Hi Alex']); 767 assertNodesAre(div, ['Hi Alex']);
768 }); 768 });
769 769
770 observeTest('RepeatNullModel', () { 770 observeTest('RepeatNullModel', () {
771 var div = createTestHtml( 771 var div = createTestHtml(
772 '<template repeat="{{}}">Hi {{ name }}</template>'); 772 '<template repeat="{{}}">Hi {{ name }}</template>');
773 var t = div.nodes.first; 773 var t = div.nodes.first;
774 774
775 var m = null; 775 var m = null;
776 recursivelySetTemplateModel(div, m); 776 recursivelySetTemplateModel(div, m);
777 777
778 expect(div.nodes.length, 1); 778 expect(div.nodes.length, 1);
779 779
780 t.attributes['iterate'] = ''; 780 t.attributes['iterate'] = '';
781 m = toObservable({}); 781 m = toObservable({});
782 recursivelySetTemplateModel(div, m); 782 recursivelySetTemplateModel(div, m);
783 783
784 deliverChanges(m); 784 performMicrotaskCheckpoint();
785 expect(div.nodes.length, 1); 785 expect(div.nodes.length, 1);
786 }); 786 });
787 787
788 observeTest('RepeatReuse', () { 788 observeTest('RepeatReuse', () {
789 var div = createTestHtml( 789 var div = createTestHtml(
790 '<template repeat="{{}}">Hi {{ name }}</template>'); 790 '<template repeat="{{}}">Hi {{ name }}</template>');
791 var t = div.nodes.first; 791 var t = div.nodes.first;
792 792
793 var m = toObservable([ 793 var m = toObservable([
794 {'name': 'Raf'}, 794 {'name': 'Raf'},
795 {'name': 'Arv'}, 795 {'name': 'Arv'},
796 {'name': 'Neal'} 796 {'name': 'Neal'}
797 ]); 797 ]);
798 recursivelySetTemplateModel(div, m); 798 recursivelySetTemplateModel(div, m);
799 deliverChanges(m); 799 performMicrotaskCheckpoint();
800 800
801 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); 801 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
802 var node1 = div.nodes[1]; 802 var node1 = div.nodes[1];
803 var node2 = div.nodes[2]; 803 var node2 = div.nodes[2];
804 var node3 = div.nodes[3]; 804 var node3 = div.nodes[3];
805 805
806 m.replaceRange(1, 2, toObservable([{'name': 'Erik'}])); 806 m.replaceRange(1, 2, toObservable([{'name': 'Erik'}]));
807 deliverChanges(m); 807 performMicrotaskCheckpoint();
808 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']); 808 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
809 expect(div.nodes[1], node1, 809 expect(div.nodes[1], node1,
810 reason: 'model[0] did not change so the node should not have changed'); 810 reason: 'model[0] did not change so the node should not have changed');
811 expect(div.nodes[2], isNot(equals(node2)), 811 expect(div.nodes[2], isNot(equals(node2)),
812 reason: 'Should not reuse when replacing'); 812 reason: 'Should not reuse when replacing');
813 expect(div.nodes[3], node3, 813 expect(div.nodes[3], node3,
814 reason: 'model[2] did not change so the node should not have changed'); 814 reason: 'model[2] did not change so the node should not have changed');
815 815
816 node2 = div.nodes[2]; 816 node2 = div.nodes[2];
817 m.insert(0, toObservable({'name': 'Alex'})); 817 m.insert(0, toObservable({'name': 'Alex'}));
818 deliverChanges(m); 818 performMicrotaskCheckpoint();
819 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']); 819 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
820 }); 820 });
821 821
822 observeTest('TwoLevelsDeepBug', () { 822 observeTest('TwoLevelsDeepBug', () {
823 var div = createTestHtml( 823 var div = createTestHtml(
824 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>'); 824 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>');
825 825
826 var model = toObservable({'foo': 'bar'}); 826 var model = toObservable({'foo': 'bar'});
827 recursivelySetTemplateModel(div, model); 827 recursivelySetTemplateModel(div, model);
828 deliverChanges(model); 828 performMicrotaskCheckpoint();
829 829
830 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar'); 830 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
831 }); 831 });
832 832
833 observeTest('Checked', () { 833 observeTest('Checked', () {
834 var div = createTestHtml( 834 var div = createTestHtml(
835 '<template>' 835 '<template>'
836 '<input type="checkbox" checked="{{a}}">' 836 '<input type="checkbox" checked="{{a}}">'
837 '</template>'); 837 '</template>');
838 var t = div.nodes.first; 838 var t = div.nodes.first;
839 var m = toObservable({ 839 var m = toObservable({
840 'a': true 840 'a': true
841 }); 841 });
842 nodeBind(t).bind('bind', m, ''); 842 nodeBind(t).bind('bind', m, '');
843 deliverChanges(m); 843 performMicrotaskCheckpoint();
844 844
845 var instanceInput = t.nextNode; 845 var instanceInput = t.nextNode;
846 expect(instanceInput.checked, true); 846 expect(instanceInput.checked, true);
847 847
848 instanceInput.click(); 848 instanceInput.click();
849 expect(instanceInput.checked, false); 849 expect(instanceInput.checked, false);
850 850
851 instanceInput.click(); 851 instanceInput.click();
852 expect(instanceInput.checked, true); 852 expect(instanceInput.checked, true);
853 }); 853 });
854 854
855 nestedHelper(s, start) { 855 nestedHelper(s, start) {
856 var div = createTestHtml(s); 856 var div = createTestHtml(s);
857 857
858 var m = toObservable({ 858 var m = toObservable({
859 'a': { 859 'a': {
860 'b': 1, 860 'b': 1,
861 'c': {'d': 2} 861 'c': {'d': 2}
862 }, 862 },
863 }); 863 });
864 864
865 recursivelySetTemplateModel(div, m); 865 recursivelySetTemplateModel(div, m);
866 deliverChanges(m); 866 performMicrotaskCheckpoint();
867 867
868 var i = start; 868 var i = start;
869 expect(div.nodes[i++].text, '1'); 869 expect(div.nodes[i++].text, '1');
870 expect(div.nodes[i++].tagName, 'TEMPLATE'); 870 expect(div.nodes[i++].tagName, 'TEMPLATE');
871 expect(div.nodes[i++].text, '2'); 871 expect(div.nodes[i++].text, '2');
872 872
873 m['a']['b'] = 11; 873 m['a']['b'] = 11;
874 deliverChanges(m); 874 performMicrotaskCheckpoint();
875 expect(div.nodes[start].text, '11'); 875 expect(div.nodes[start].text, '11');
876 876
877 m['a']['c'] = toObservable({'d': 22}); 877 m['a']['c'] = toObservable({'d': 22});
878 deliverChanges(m); 878 performMicrotaskCheckpoint();
879 expect(div.nodes[start + 2].text, '22'); 879 expect(div.nodes[start + 2].text, '22');
880 } 880 }
881 881
882 observeTest('Nested', () { 882 observeTest('Nested', () {
883 nestedHelper( 883 nestedHelper(
884 '<template bind="{{a}}">' 884 '<template bind="{{a}}">'
885 '{{b}}' 885 '{{b}}'
886 '<template bind="{{c}}">' 886 '<template bind="{{c}}">'
887 '{{d}}' 887 '{{d}}'
888 '</template>' 888 '</template>'
(...skipping 19 matching lines...) Expand all
908 'c': {'d': 11} 908 'c': {'d': 11}
909 }, 909 },
910 { 910 {
911 'b': 2, 911 'b': 2,
912 'c': {'d': 22} 912 'c': {'d': 22}
913 } 913 }
914 ] 914 ]
915 }); 915 });
916 916
917 recursivelySetTemplateModel(div, m); 917 recursivelySetTemplateModel(div, m);
918 deliverChanges(m); 918 performMicrotaskCheckpoint();
919 919
920 var i = start; 920 var i = start;
921 expect(div.nodes[i++].text, '1'); 921 expect(div.nodes[i++].text, '1');
922 expect(div.nodes[i++].tagName, 'TEMPLATE'); 922 expect(div.nodes[i++].tagName, 'TEMPLATE');
923 expect(div.nodes[i++].text, '11'); 923 expect(div.nodes[i++].text, '11');
924 expect(div.nodes[i++].text, '2'); 924 expect(div.nodes[i++].text, '2');
925 expect(div.nodes[i++].tagName, 'TEMPLATE'); 925 expect(div.nodes[i++].tagName, 'TEMPLATE');
926 expect(div.nodes[i++].text, '22'); 926 expect(div.nodes[i++].text, '22');
927 927
928 m['a'][1] = toObservable({ 928 m['a'][1] = toObservable({
929 'b': 3, 929 'b': 3,
930 'c': {'d': 33} 930 'c': {'d': 33}
931 }); 931 });
932 932
933 deliverChanges(m); 933 performMicrotaskCheckpoint();
934 expect(div.nodes[start + 3].text, '3'); 934 expect(div.nodes[start + 3].text, '3');
935 expect(div.nodes[start + 5].text, '33'); 935 expect(div.nodes[start + 5].text, '33');
936 } 936 }
937 937
938 observeTest('NestedRepeatBind', () { 938 observeTest('NestedRepeatBind', () {
939 nestedIterateInstantiateHelper( 939 nestedIterateInstantiateHelper(
940 '<template repeat="{{a}}">' 940 '<template repeat="{{a}}">'
941 '{{b}}' 941 '{{b}}'
942 '<template bind="{{c}}">' 942 '<template bind="{{c}}">'
943 '{{d}}' 943 '{{d}}'
(...skipping 22 matching lines...) Expand all
966 'c': [{'d': 11}, {'d': 12}] 966 'c': [{'d': 11}, {'d': 12}]
967 }, 967 },
968 { 968 {
969 'b': 2, 969 'b': 2,
970 'c': [{'d': 21}, {'d': 22}] 970 'c': [{'d': 21}, {'d': 22}]
971 } 971 }
972 ] 972 ]
973 }); 973 });
974 974
975 recursivelySetTemplateModel(div, m); 975 recursivelySetTemplateModel(div, m);
976 deliverChanges(m); 976 performMicrotaskCheckpoint();
977 977
978 var i = start; 978 var i = start;
979 expect(div.nodes[i++].text, '1'); 979 expect(div.nodes[i++].text, '1');
980 expect(div.nodes[i++].tagName, 'TEMPLATE'); 980 expect(div.nodes[i++].tagName, 'TEMPLATE');
981 expect(div.nodes[i++].text, '11'); 981 expect(div.nodes[i++].text, '11');
982 expect(div.nodes[i++].text, '12'); 982 expect(div.nodes[i++].text, '12');
983 expect(div.nodes[i++].text, '2'); 983 expect(div.nodes[i++].text, '2');
984 expect(div.nodes[i++].tagName, 'TEMPLATE'); 984 expect(div.nodes[i++].tagName, 'TEMPLATE');
985 expect(div.nodes[i++].text, '21'); 985 expect(div.nodes[i++].text, '21');
986 expect(div.nodes[i++].text, '22'); 986 expect(div.nodes[i++].text, '22');
987 987
988 m['a'][1] = toObservable({ 988 m['a'][1] = toObservable({
989 'b': 3, 989 'b': 3,
990 'c': [{'d': 31}, {'d': 32}, {'d': 33}] 990 'c': [{'d': 31}, {'d': 32}, {'d': 33}]
991 }); 991 });
992 992
993 i = start + 4; 993 i = start + 4;
994 deliverChanges(m); 994 performMicrotaskCheckpoint();
995 expect(div.nodes[start + 4].text, '3'); 995 expect(div.nodes[start + 4].text, '3');
996 expect(div.nodes[start + 6].text, '31'); 996 expect(div.nodes[start + 6].text, '31');
997 expect(div.nodes[start + 7].text, '32'); 997 expect(div.nodes[start + 7].text, '32');
998 expect(div.nodes[start + 8].text, '33'); 998 expect(div.nodes[start + 8].text, '33');
999 } 999 }
1000 1000
1001 observeTest('NestedRepeatBind', () { 1001 observeTest('NestedRepeatBind', () {
1002 nestedIterateIterateHelper( 1002 nestedIterateIterateHelper(
1003 '<template repeat="{{a}}">' 1003 '<template repeat="{{a}}">'
1004 '{{b}}' 1004 '{{b}}'
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1044 } 1044 }
1045 ] 1045 ]
1046 }, 1046 },
1047 { 1047 {
1048 'name': 'Item 2', 1048 'name': 'Item 2',
1049 'items': [] 1049 'items': []
1050 }, 1050 },
1051 ]); 1051 ]);
1052 1052
1053 recursivelySetTemplateModel(div, m); 1053 recursivelySetTemplateModel(div, m);
1054 deliverChanges(m); 1054 performMicrotaskCheckpoint();
1055 1055
1056 var i = 1; 1056 var i = 1;
1057 expect(div.nodes[i++].text, 'Item 1'); 1057 expect(div.nodes[i++].text, 'Item 1');
1058 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1058 expect(div.nodes[i++].tagName, 'TEMPLATE');
1059 expect(div.nodes[i++].text, 'Item 1.1'); 1059 expect(div.nodes[i++].text, 'Item 1.1');
1060 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1060 expect(div.nodes[i++].tagName, 'TEMPLATE');
1061 expect(div.nodes[i++].text, 'Item 1.1.1'); 1061 expect(div.nodes[i++].text, 'Item 1.1.1');
1062 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1062 expect(div.nodes[i++].tagName, 'TEMPLATE');
1063 expect(div.nodes[i++].text, 'Item 1.2'); 1063 expect(div.nodes[i++].text, 'Item 1.2');
1064 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1064 expect(div.nodes[i++].tagName, 'TEMPLATE');
1065 expect(div.nodes[i++].text, 'Item 2'); 1065 expect(div.nodes[i++].text, 'Item 2');
1066 1066
1067 m[0] = toObservable({'name': 'Item 1 changed'}); 1067 m[0] = toObservable({'name': 'Item 1 changed'});
1068 1068
1069 i = 1; 1069 i = 1;
1070 deliverChanges(m); 1070 performMicrotaskCheckpoint();
1071 expect(div.nodes[i++].text, 'Item 1 changed'); 1071 expect(div.nodes[i++].text, 'Item 1 changed');
1072 expect(div.nodes[i++].tagName, 'TEMPLATE'); 1072 expect(div.nodes[i++].tagName, 'TEMPLATE');
1073 expect(div.nodes[i++].text, 'Item 2'); 1073 expect(div.nodes[i++].text, 'Item 2');
1074 }); 1074 });
1075 1075
1076 observeTest('Attribute Template Option/Optgroup', () { 1076 observeTest('Attribute Template Option/Optgroup', () {
1077 var div = createTestHtml( 1077 var div = createTestHtml(
1078 '<template bind>' 1078 '<template bind>'
1079 '<select selectedIndex="{{ selected }}">' 1079 '<select selectedIndex="{{ selected }}">'
1080 '<optgroup template repeat="{{ groups }}" label="{{ name }}">' 1080 '<optgroup template repeat="{{ groups }}" label="{{ name }}">'
1081 '<option template repeat="{{ items }}">{{ val }}</option>' 1081 '<option template repeat="{{ items }}">{{ val }}</option>'
1082 '</optgroup>' 1082 '</optgroup>'
1083 '</select>' 1083 '</select>'
1084 '</template>'); 1084 '</template>');
1085 1085
1086 var m = toObservable({ 1086 var m = toObservable({
1087 'selected': 1, 1087 'selected': 1,
1088 'groups': [{ 1088 'groups': [{
1089 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }] 1089 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }]
1090 }], 1090 }],
1091 }); 1091 });
1092 1092
1093 recursivelySetTemplateModel(div, m); 1093 recursivelySetTemplateModel(div, m);
1094 deliverChanges(m); 1094 performMicrotaskCheckpoint();
1095 1095
1096 var select = div.nodes[0].nextNode; 1096 var select = div.nodes[0].nextNode;
1097 expect(select.nodes.length, 2); 1097 expect(select.nodes.length, 2);
1098 1098
1099 scheduleMicrotask(expectAsync0(() { 1099 scheduleMicrotask(expectAsync0(() {
1100 scheduleMicrotask(expectAsync0(() { 1100 scheduleMicrotask(expectAsync0(() {
1101 // TODO(jmesserly): this should be called sooner. 1101 // TODO(jmesserly): this should be called sooner.
1102 expect(select.selectedIndex, 1); 1102 expect(select.selectedIndex, 1);
1103 })); 1103 }));
1104 })); 1104 }));
(...skipping 20 matching lines...) Expand all
1125 '</tr>' 1125 '</tr>'
1126 '</template>' 1126 '</template>'
1127 '</tbody></table>'); 1127 '</tbody></table>');
1128 1128
1129 var m = toObservable([ 1129 var m = toObservable([
1130 [{ 'val': 0 }, { 'val': 1 }], 1130 [{ 'val': 0 }, { 'val': 1 }],
1131 [{ 'val': 2 }, { 'val': 3 }] 1131 [{ 'val': 2 }, { 'val': 3 }]
1132 ]); 1132 ]);
1133 1133
1134 recursivelySetTemplateModel(div, m); 1134 recursivelySetTemplateModel(div, m);
1135 deliverChanges(m); 1135 performMicrotaskCheckpoint();
1136 1136
1137 var tbody = div.nodes[0].nodes[0]; 1137 var tbody = div.nodes[0].nodes[0];
1138 1138
1139 // 1 for the <tr template>, 2 * (1 tr) 1139 // 1 for the <tr template>, 2 * (1 tr)
1140 expect(tbody.nodes.length, 3); 1140 expect(tbody.nodes.length, 3);
1141 1141
1142 // 1 for the <td template>, 2 * (1 td) 1142 // 1 for the <td template>, 2 * (1 td)
1143 expect(tbody.nodes[1].nodes.length, 3); 1143 expect(tbody.nodes[1].nodes.length, 3);
1144 1144
1145 expect(tbody.nodes[1].nodes[1].text, '0'); 1145 expect(tbody.nodes[1].nodes[1].text, '0');
(...skipping 16 matching lines...) Expand all
1162 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' 1162 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>'
1163 '</tr>' 1163 '</tr>'
1164 '</tbody></table>'); 1164 '</tbody></table>');
1165 1165
1166 var m = toObservable([ 1166 var m = toObservable([
1167 [{ 'val': 0 }, { 'val': 1 }], 1167 [{ 'val': 0 }, { 'val': 1 }],
1168 [{ 'val': 2 }, { 'val': 3 }] 1168 [{ 'val': 2 }, { 'val': 3 }]
1169 ]); 1169 ]);
1170 1170
1171 recursivelySetTemplateModel(div, m); 1171 recursivelySetTemplateModel(div, m);
1172 deliverChanges(m); 1172 performMicrotaskCheckpoint();
1173 1173
1174 var i = 1; 1174 var i = 1;
1175 var tbody = div.nodes[0].nodes[0]; 1175 var tbody = div.nodes[0].nodes[0];
1176 1176
1177 // 1 for the <tr template>, 2 * (1 tr) 1177 // 1 for the <tr template>, 2 * (1 tr)
1178 expect(tbody.nodes.length, 3); 1178 expect(tbody.nodes.length, 3);
1179 1179
1180 // 1 for the <td template>, 2 * (1 td) 1180 // 1 for the <td template>, 2 * (1 td)
1181 expect(tbody.nodes[1].nodes.length, 3); 1181 expect(tbody.nodes[1].nodes.length, 3);
1182 expect(tbody.nodes[1].nodes[1].text, '0'); 1182 expect(tbody.nodes[1].nodes[1].text, '0');
(...skipping 27 matching lines...) Expand all
1210 'items': [ 1210 'items': [
1211 { 1211 {
1212 'name': 'Item 1.1' 1212 'name': 'Item 1.1'
1213 } 1213 }
1214 ] 1214 ]
1215 } 1215 }
1216 ]); 1216 ]);
1217 1217
1218 recursivelySetTemplateModel(div, m); 1218 recursivelySetTemplateModel(div, m);
1219 1219
1220 deliverChanges(m); 1220 performMicrotaskCheckpoint();
1221 m.removeAt(0); 1221 m.removeAt(0);
1222 deliverChanges(m); 1222 performMicrotaskCheckpoint();
1223 }); 1223 });
1224 1224
1225 observeTest('DeepNested', () { 1225 observeTest('DeepNested', () {
1226 var div = createTestHtml( 1226 var div = createTestHtml(
1227 '<template bind="{{a}}">' 1227 '<template bind="{{a}}">'
1228 '<p>' 1228 '<p>'
1229 '<template bind="{{b}}">' 1229 '<template bind="{{b}}">'
1230 '{{ c }}' 1230 '{{ c }}'
1231 '</template>' 1231 '</template>'
1232 '</p>' 1232 '</p>'
1233 '</template>'); 1233 '</template>');
1234 1234
1235 var m = toObservable({ 1235 var m = toObservable({
1236 'a': { 1236 'a': {
1237 'b': { 1237 'b': {
1238 'c': 42 1238 'c': 42
1239 } 1239 }
1240 } 1240 }
1241 }); 1241 });
1242 recursivelySetTemplateModel(div, m); 1242 recursivelySetTemplateModel(div, m);
1243 deliverChanges(m); 1243 performMicrotaskCheckpoint();
1244 1244
1245 expect(div.nodes[1].tagName, 'P'); 1245 expect(div.nodes[1].tagName, 'P');
1246 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE'); 1246 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
1247 expect(div.nodes[1].nodes[1].text, '42'); 1247 expect(div.nodes[1].nodes[1].text, '42');
1248 }); 1248 });
1249 1249
1250 observeTest('TemplateContentRemoved', () { 1250 observeTest('TemplateContentRemoved', () {
1251 var div = createTestHtml('<template bind="{{}}">{{ }}</template>'); 1251 var div = createTestHtml('<template bind="{{}}">{{ }}</template>');
1252 var model = 42; 1252 var model = 42;
1253 1253
1254 recursivelySetTemplateModel(div, model); 1254 recursivelySetTemplateModel(div, model);
1255 deliverChanges(model); 1255 performMicrotaskCheckpoint();
1256 expect(div.nodes[1].text, '42'); 1256 expect(div.nodes[1].text, '42');
1257 expect(div.nodes[0].text, ''); 1257 expect(div.nodes[0].text, '');
1258 }); 1258 });
1259 1259
1260 observeTest('TemplateContentRemovedEmptyArray', () { 1260 observeTest('TemplateContentRemovedEmptyArray', () {
1261 var div = createTestHtml('<template iterate>Remove me</template>'); 1261 var div = createTestHtml('<template iterate>Remove me</template>');
1262 var model = toObservable([]); 1262 var model = toObservable([]);
1263 1263
1264 recursivelySetTemplateModel(div, model); 1264 recursivelySetTemplateModel(div, model);
1265 deliverChanges(model); 1265 performMicrotaskCheckpoint();
1266 expect(div.nodes.length, 1); 1266 expect(div.nodes.length, 1);
1267 expect(div.nodes[0].text, ''); 1267 expect(div.nodes[0].text, '');
1268 }); 1268 });
1269 1269
1270 observeTest('TemplateContentRemovedNested', () { 1270 observeTest('TemplateContentRemovedNested', () {
1271 var div = createTestHtml( 1271 var div = createTestHtml(
1272 '<template bind="{{}}">' 1272 '<template bind="{{}}">'
1273 '{{ a }}' 1273 '{{ a }}'
1274 '<template bind="{{}}">' 1274 '<template bind="{{}}">'
1275 '{{ b }}' 1275 '{{ b }}'
1276 '</template>' 1276 '</template>'
1277 '</template>'); 1277 '</template>');
1278 1278
1279 var model = toObservable({ 1279 var model = toObservable({
1280 'a': 1, 1280 'a': 1,
1281 'b': 2 1281 'b': 2
1282 }); 1282 });
1283 recursivelySetTemplateModel(div, model); 1283 recursivelySetTemplateModel(div, model);
1284 deliverChanges(model); 1284 performMicrotaskCheckpoint();
1285 1285
1286 expect(div.nodes[0].text, ''); 1286 expect(div.nodes[0].text, '');
1287 expect(div.nodes[1].text, '1'); 1287 expect(div.nodes[1].text, '1');
1288 expect(div.nodes[2].text, ''); 1288 expect(div.nodes[2].text, '');
1289 expect(div.nodes[3].text, '2'); 1289 expect(div.nodes[3].text, '2');
1290 }); 1290 });
1291 1291
1292 observeTest('BindWithUndefinedModel', () { 1292 observeTest('BindWithUndefinedModel', () {
1293 var div = createTestHtml( 1293 var div = createTestHtml(
1294 '<template bind="{{}}" if="{{}}">{{ a }}</template>'); 1294 '<template bind="{{}}" if="{{}}">{{ a }}</template>');
1295 1295
1296 var model = toObservable({'a': 42}); 1296 var model = toObservable({'a': 42});
1297 recursivelySetTemplateModel(div, model); 1297 recursivelySetTemplateModel(div, model);
1298 deliverChanges(model); 1298 performMicrotaskCheckpoint();
1299 expect(div.nodes[1].text, '42'); 1299 expect(div.nodes[1].text, '42');
1300 1300
1301 model = null; 1301 model = null;
1302 recursivelySetTemplateModel(div, model); 1302 recursivelySetTemplateModel(div, model);
1303 deliverChanges(model); 1303 performMicrotaskCheckpoint();
1304 expect(div.nodes.length, 1); 1304 expect(div.nodes.length, 1);
1305 1305
1306 model = toObservable({'a': 42}); 1306 model = toObservable({'a': 42});
1307 recursivelySetTemplateModel(div, model); 1307 recursivelySetTemplateModel(div, model);
1308 deliverChanges(model); 1308 performMicrotaskCheckpoint();
1309 expect(div.nodes[1].text, '42'); 1309 expect(div.nodes[1].text, '42');
1310 }); 1310 });
1311 1311
1312 observeTest('BindNested', () { 1312 observeTest('BindNested', () {
1313 var div = createTestHtml( 1313 var div = createTestHtml(
1314 '<template bind="{{}}">' 1314 '<template bind="{{}}">'
1315 'Name: {{ name }}' 1315 'Name: {{ name }}'
1316 '<template bind="{{wife}}" if="{{wife}}">' 1316 '<template bind="{{wife}}" if="{{wife}}">'
1317 'Wife: {{ name }}' 1317 'Wife: {{ name }}'
1318 '</template>' 1318 '</template>'
1319 '<template bind="{{child}}" if="{{child}}">' 1319 '<template bind="{{child}}" if="{{child}}">'
1320 'Child: {{ name }}' 1320 'Child: {{ name }}'
1321 '</template>' 1321 '</template>'
1322 '</template>'); 1322 '</template>');
1323 1323
1324 var m = toObservable({ 1324 var m = toObservable({
1325 'name': 'Hermes', 1325 'name': 'Hermes',
1326 'wife': { 1326 'wife': {
1327 'name': 'LaBarbara' 1327 'name': 'LaBarbara'
1328 } 1328 }
1329 }); 1329 });
1330 recursivelySetTemplateModel(div, m); 1330 recursivelySetTemplateModel(div, m);
1331 deliverChanges(m); 1331 performMicrotaskCheckpoint();
1332 1332
1333 expect(div.nodes.length, 5); 1333 expect(div.nodes.length, 5);
1334 expect(div.nodes[1].text, 'Name: Hermes'); 1334 expect(div.nodes[1].text, 'Name: Hermes');
1335 expect(div.nodes[3].text, 'Wife: LaBarbara'); 1335 expect(div.nodes[3].text, 'Wife: LaBarbara');
1336 1336
1337 m['child'] = toObservable({'name': 'Dwight'}); 1337 m['child'] = toObservable({'name': 'Dwight'});
1338 deliverChanges(m); 1338 performMicrotaskCheckpoint();
1339 expect(div.nodes.length, 6); 1339 expect(div.nodes.length, 6);
1340 expect(div.nodes[5].text, 'Child: Dwight'); 1340 expect(div.nodes[5].text, 'Child: Dwight');
1341 1341
1342 m.remove('wife'); 1342 m.remove('wife');
1343 deliverChanges(m); 1343 performMicrotaskCheckpoint();
1344 expect(div.nodes.length, 5); 1344 expect(div.nodes.length, 5);
1345 expect(div.nodes[4].text, 'Child: Dwight'); 1345 expect(div.nodes[4].text, 'Child: Dwight');
1346 }); 1346 });
1347 1347
1348 observeTest('BindRecursive', () { 1348 observeTest('BindRecursive', () {
1349 var div = createTestHtml( 1349 var div = createTestHtml(
1350 '<template bind="{{}}" if="{{}}" id="t">' 1350 '<template bind="{{}}" if="{{}}" id="t">'
1351 'Name: {{ name }}' 1351 'Name: {{ name }}'
1352 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>' 1352 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>'
1353 '</template>'); 1353 '</template>');
1354 1354
1355 var m = toObservable({ 1355 var m = toObservable({
1356 'name': 'Fry', 1356 'name': 'Fry',
1357 'friend': { 1357 'friend': {
1358 'name': 'Bender' 1358 'name': 'Bender'
1359 } 1359 }
1360 }); 1360 });
1361 recursivelySetTemplateModel(div, m); 1361 recursivelySetTemplateModel(div, m);
1362 deliverChanges(m); 1362 performMicrotaskCheckpoint();
1363 1363
1364 expect(div.nodes.length, 5); 1364 expect(div.nodes.length, 5);
1365 expect(div.nodes[1].text, 'Name: Fry'); 1365 expect(div.nodes[1].text, 'Name: Fry');
1366 expect(div.nodes[3].text, 'Name: Bender'); 1366 expect(div.nodes[3].text, 'Name: Bender');
1367 1367
1368 m['friend']['friend'] = toObservable({'name': 'Leela'}); 1368 m['friend']['friend'] = toObservable({'name': 'Leela'});
1369 deliverChanges(m); 1369 performMicrotaskCheckpoint();
1370 expect(div.nodes.length, 7); 1370 expect(div.nodes.length, 7);
1371 expect(div.nodes[5].text, 'Name: Leela'); 1371 expect(div.nodes[5].text, 'Name: Leela');
1372 1372
1373 m['friend'] = toObservable({'name': 'Leela'}); 1373 m['friend'] = toObservable({'name': 'Leela'});
1374 deliverChanges(m); 1374 performMicrotaskCheckpoint();
1375 expect(div.nodes.length, 5); 1375 expect(div.nodes.length, 5);
1376 expect(div.nodes[3].text, 'Name: Leela'); 1376 expect(div.nodes[3].text, 'Name: Leela');
1377 }); 1377 });
1378 1378
1379 observeTest('Template - Self is terminator', () { 1379 observeTest('Template - Self is terminator', () {
1380 var div = createTestHtml( 1380 var div = createTestHtml(
1381 '<template repeat>{{ foo }}' 1381 '<template repeat>{{ foo }}'
1382 '<template bind></template>' 1382 '<template bind></template>'
1383 '</template>'); 1383 '</template>');
1384 1384
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1441 // binding keys. 1441 // binding keys.
1442 var m = toObservable({ 1442 var m = toObservable({
1443 'a': [ 1443 'a': [
1444 [], 1444 [],
1445 { 'b': [1,2,3,4] }, 1445 { 'b': [1,2,3,4] },
1446 // Note: this will use the Map "length" property, not the "length" key. 1446 // Note: this will use the Map "length" property, not the "length" key.
1447 {'length': 42, 'c': 123} 1447 {'length': 42, 'c': 123}
1448 ] 1448 ]
1449 }); 1449 });
1450 recursivelySetTemplateModel(div, m); 1450 recursivelySetTemplateModel(div, m);
1451 deliverChanges(m); 1451 performMicrotaskCheckpoint();
1452 1452
1453 expect(div.nodes.length, 2); 1453 expect(div.nodes.length, 2);
1454 expect(div.nodes[1].text, '3'); 1454 expect(div.nodes[1].text, '3');
1455 1455
1456 nodeBind(template) 1456 nodeBind(template)
1457 ..unbind('bind') 1457 ..unbind('bind')
1458 ..bind('repeat', m, 'a'); 1458 ..bind('repeat', m, 'a');
1459 deliverChanges(m); 1459 performMicrotaskCheckpoint();
1460 expect(div.nodes.length, 4); 1460 expect(div.nodes.length, 4);
1461 expect(div.nodes[1].text, '0'); 1461 expect(div.nodes[1].text, '0');
1462 expect(div.nodes[2].text, '1'); 1462 expect(div.nodes[2].text, '1');
1463 expect(div.nodes[3].text, '2'); 1463 expect(div.nodes[3].text, '2');
1464 1464
1465 nodeBind(template).unbind('repeat'); 1465 nodeBind(template).unbind('repeat');
1466 nodeBind(template).bind('bind', m, 'a.1.b'); 1466 nodeBind(template).bind('bind', m, 'a.1.b');
1467 1467
1468 deliverChanges(m); 1468 performMicrotaskCheckpoint();
1469 expect(div.nodes.length, 2); 1469 expect(div.nodes.length, 2);
1470 expect(div.nodes[1].text, '4'); 1470 expect(div.nodes[1].text, '4');
1471 }); 1471 });
1472 1472
1473 observeTest('ChangeRefId', () { 1473 observeTest('ChangeRefId', () {
1474 var div = createTestHtml( 1474 var div = createTestHtml(
1475 '<template id="a">a:{{ }}</template>' 1475 '<template id="a">a:{{ }}</template>'
1476 '<template id="b">b:{{ }}</template>' 1476 '<template id="b">b:{{ }}</template>'
1477 '<template repeat="{{}}">' 1477 '<template repeat="{{}}">'
1478 '<template ref="a" bind="{{}}"></template>' 1478 '<template ref="a" bind="{{}}"></template>'
1479 '</template>'); 1479 '</template>');
1480 var model = toObservable([]); 1480 var model = toObservable([]);
1481 recursivelySetTemplateModel(div, model); 1481 recursivelySetTemplateModel(div, model);
1482 deliverChanges(model); 1482 performMicrotaskCheckpoint();
1483 1483
1484 expect(div.nodes.length, 3); 1484 expect(div.nodes.length, 3);
1485 1485
1486 document.getElementById('a').id = 'old-a'; 1486 document.getElementById('a').id = 'old-a';
1487 document.getElementById('b').id = 'a'; 1487 document.getElementById('b').id = 'a';
1488 1488
1489 model..add(1)..add(2); 1489 model..add(1)..add(2);
1490 deliverChanges(model); 1490 performMicrotaskCheckpoint();
1491 1491
1492 expect(div.nodes.length, 7); 1492 expect(div.nodes.length, 7);
1493 expect(div.nodes[4].text, 'b:1'); 1493 expect(div.nodes[4].text, 'b:1');
1494 expect(div.nodes[6].text, 'b:2'); 1494 expect(div.nodes[6].text, 'b:2');
1495 }); 1495 });
1496 1496
1497 observeTest('Content', () { 1497 observeTest('Content', () {
1498 var div = createTestHtml( 1498 var div = createTestHtml(
1499 '<template><a></a></template>' 1499 '<template><a></a></template>'
1500 '<template><b></b></template>'); 1500 '<template><b></b></template>');
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1536 expect(templateBind(templateB).content.ownerDocument, 1536 expect(templateBind(templateB).content.ownerDocument,
1537 templateBind(templateA).content.ownerDocument); 1537 templateBind(templateA).content.ownerDocument);
1538 }); 1538 });
1539 1539
1540 observeTest('BindShadowDOM', () { 1540 observeTest('BindShadowDOM', () {
1541 if (ShadowRoot.supported) { 1541 if (ShadowRoot.supported) {
1542 var root = createShadowTestHtml( 1542 var root = createShadowTestHtml(
1543 '<template bind="{{}}">Hi {{ name }}</template>'); 1543 '<template bind="{{}}">Hi {{ name }}</template>');
1544 var model = toObservable({'name': 'Leela'}); 1544 var model = toObservable({'name': 'Leela'});
1545 recursivelySetTemplateModel(root, model); 1545 recursivelySetTemplateModel(root, model);
1546 deliverChanges(model); 1546 performMicrotaskCheckpoint();
1547 expect(root.nodes[1].text, 'Hi Leela'); 1547 expect(root.nodes[1].text, 'Hi Leela');
1548 } 1548 }
1549 }); 1549 });
1550 1550
1551 observeTest('BindShadowDOM createInstance', () { 1551 observeTest('BindShadowDOM createInstance', () {
1552 if (ShadowRoot.supported) { 1552 if (ShadowRoot.supported) {
1553 var model = toObservable({'name': 'Leela'}); 1553 var model = toObservable({'name': 'Leela'});
1554 var template = new Element.html('<template>Hi {{ name }}</template>'); 1554 var template = new Element.html('<template>Hi {{ name }}</template>');
1555 var root = createShadowTestHtml(''); 1555 var root = createShadowTestHtml('');
1556 root.nodes.add(templateBind(template).createInstance(model)); 1556 root.nodes.add(templateBind(template).createInstance(model));
(...skipping 30 matching lines...) Expand all
1587 var model = toObservable({ 1587 var model = toObservable({
1588 'outer': { 1588 'outer': {
1589 'inner': { 1589 'inner': {
1590 'age': 42 1590 'age': 42
1591 } 1591 }
1592 } 1592 }
1593 }); 1593 });
1594 1594
1595 recursivelySetTemplateModel(div, model, syntax); 1595 recursivelySetTemplateModel(div, model, syntax);
1596 1596
1597 deliverChanges(model); 1597 performMicrotaskCheckpoint();
1598 expect(syntax.count, 1); 1598 expect(syntax.count, 1);
1599 1599
1600 var inner = model['outer']['inner']; 1600 var inner = model['outer']['inner'];
1601 model['outer'] = null; 1601 model['outer'] = null;
1602 1602
1603 deliverChanges(model); 1603 performMicrotaskCheckpoint();
1604 expect(syntax.count, 1); 1604 expect(syntax.count, 1);
1605 1605
1606 model['outer'] = toObservable({'inner': {'age': 2}}); 1606 model['outer'] = toObservable({'inner': {'age': 2}});
1607 syntax.expectedAge = 2; 1607 syntax.expectedAge = 2;
1608 1608
1609 deliverChanges(model); 1609 performMicrotaskCheckpoint();
1610 expect(syntax.count, 2); 1610 expect(syntax.count, 2);
1611 }); 1611 });
1612 1612
1613 // https://github.com/toolkitchen/mdv/issues/8 1613 // https://github.com/toolkitchen/mdv/issues/8
1614 observeTest('DontCreateInstancesForAbandonedIterators', () { 1614 observeTest('DontCreateInstancesForAbandonedIterators', () {
1615 var div = createTestHtml( 1615 var div = createTestHtml(
1616 '<template bind="{{}} {{}}">' 1616 '<template bind="{{}} {{}}">'
1617 '<template bind="{{}}">Foo' 1617 '<template bind="{{}}">Foo'
1618 '</template>' 1618 '</template>'
1619 '</template>'); 1619 '</template>');
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1688 int count = 0; 1688 int count = 0;
1689 1689
1690 getBinding(model, path, name, node) { 1690 getBinding(model, path, name, node) {
1691 if (name != 'text' || path != 'age') 1691 if (name != 'text' || path != 'age')
1692 return; 1692 return;
1693 1693
1694 expect(model['age'], expectedAge); 1694 expect(model['age'], expectedAge);
1695 count++; 1695 count++;
1696 } 1696 }
1697 } 1697 }
1698
1699 /**
1700 * Verifies that the model is Observable, then calls
1701 * [performMicrotaskCheckpoint].
1702 */
1703 void deliverChanges(model) {
1704 expectObservable(model);
1705 performMicrotaskCheckpoint();
1706 }
1707
1708 void expectObservable(model) {
1709 if (model is! Observable) {
1710 // This is here to eagerly catch a bug in the test; it means the test
1711 // forgot a toObservable somewhere.
1712 expect(identical(toObservable(model), model), true,
1713 reason: 'model type "${model.runtimeType}" should be observable');
1714 return;
1715 }
1716 if (model is ObservableList) {
1717 for (var item in model) {
1718 expectObservable(item);
1719 }
1720 } else if (model is ObservableMap) {
1721 model.forEach((k, v) {
1722 expectObservable(k);
1723 expectObservable(v);
1724 });
1725 }
1726 }
1727
1728 _deepToSymbol(value) {
1729 if (value is Map) {
1730 var result = new LinkedHashMap();
1731 value.forEach((k, v) {
1732 k = k is String ? new Symbol(k) : _deepToSymbol(k);
1733 result[k] = _deepToSymbol(v);
1734 });
1735 return result;
1736 }
1737 if (value is Iterable) {
1738 return value.map(_deepToSymbol).toList();
1739 }
1740 return value;
1741 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698