| OLD | NEW |
| (Empty) |
| 1 library watch_group_spec; | |
| 2 | |
| 3 import '../_specs.dart'; | |
| 4 import 'package:angular/change_detection/watch_group.dart'; | |
| 5 import 'package:angular/change_detection/dirty_checking_change_detector.dart'; | |
| 6 import 'dirty_checking_change_detector_spec.dart' hide main; | |
| 7 | |
| 8 main() => describe('WatchGroup', () { | |
| 9 var context; | |
| 10 var watchGrp; | |
| 11 DirtyCheckingChangeDetector changeDetector; | |
| 12 Logger logger; | |
| 13 | |
| 14 AST parse(String expression) { | |
| 15 var currentAST = new ContextReferenceAST(); | |
| 16 expression.split('.').forEach((name) { | |
| 17 currentAST = new FieldReadAST(currentAST, name); | |
| 18 }); | |
| 19 return currentAST; | |
| 20 } | |
| 21 | |
| 22 expectOrder(list) { | |
| 23 logger.clear(); | |
| 24 watchGrp.detectChanges(); // Clear the initial queue | |
| 25 logger.clear(); | |
| 26 watchGrp.detectChanges(); | |
| 27 expect(logger).toEqual(list); | |
| 28 } | |
| 29 | |
| 30 beforeEach(inject((Logger _logger) { | |
| 31 context = {}; | |
| 32 changeDetector = new DirtyCheckingChangeDetector(new GetterCache({})); | |
| 33 watchGrp = new RootWatchGroup(changeDetector, context); | |
| 34 logger = _logger; | |
| 35 })); | |
| 36 | |
| 37 describe('watch lifecycle', () { | |
| 38 it('should prevent reaction fn on removed', () { | |
| 39 context['a'] = 'hello'; | |
| 40 var watch ; | |
| 41 watchGrp.watch(parse('a'), (v, p) { | |
| 42 logger('removed'); | |
| 43 watch.remove(); | |
| 44 }); | |
| 45 watch = watchGrp.watch(parse('a'), (v, p) => logger(v)); | |
| 46 watchGrp.detectChanges(); | |
| 47 expect(logger).toEqual(['removed']); | |
| 48 }); | |
| 49 }); | |
| 50 | |
| 51 describe('property chaining', () { | |
| 52 it('should read property', () { | |
| 53 context['a'] = 'hello'; | |
| 54 | |
| 55 // should fire on initial adding | |
| 56 expect(watchGrp.fieldCost).toEqual(0); | |
| 57 var watch = watchGrp.watch(parse('a'), (v, p) => logger(v)); | |
| 58 expect(watch.expression).toEqual('a'); | |
| 59 expect(watchGrp.fieldCost).toEqual(1); | |
| 60 watchGrp.detectChanges(); | |
| 61 expect(logger).toEqual(['hello']); | |
| 62 | |
| 63 // make sore no new changes are logged on extra detectChanges | |
| 64 watchGrp.detectChanges(); | |
| 65 expect(logger).toEqual(['hello']); | |
| 66 | |
| 67 // Should detect value change | |
| 68 context['a'] = 'bye'; | |
| 69 watchGrp.detectChanges(); | |
| 70 expect(logger).toEqual(['hello', 'bye']); | |
| 71 | |
| 72 // should cleanup after itself | |
| 73 watch.remove(); | |
| 74 expect(watchGrp.fieldCost).toEqual(0); | |
| 75 context['a'] = 'cant see me'; | |
| 76 watchGrp.detectChanges(); | |
| 77 expect(logger).toEqual(['hello', 'bye']); | |
| 78 }); | |
| 79 | |
| 80 it('should read property chain', () { | |
| 81 context['a'] = {'b': 'hello'}; | |
| 82 | |
| 83 // should fire on initial adding | |
| 84 expect(watchGrp.fieldCost).toEqual(0); | |
| 85 expect(changeDetector.count).toEqual(0); | |
| 86 var watch = watchGrp.watch(parse('a.b'), (v, p) => logger(v)); | |
| 87 expect(watch.expression).toEqual('a.b'); | |
| 88 expect(watchGrp.fieldCost).toEqual(2); | |
| 89 expect(changeDetector.count).toEqual(2); | |
| 90 watchGrp.detectChanges(); | |
| 91 expect(logger).toEqual(['hello']); | |
| 92 | |
| 93 // make sore no new changes are logged on extra detectChanges | |
| 94 watchGrp.detectChanges(); | |
| 95 expect(logger).toEqual(['hello']); | |
| 96 | |
| 97 // make sure no changes or logged when intermediary object changes | |
| 98 context['a'] = {'b': 'hello'}; | |
| 99 watchGrp.detectChanges(); | |
| 100 expect(logger).toEqual(['hello']); | |
| 101 | |
| 102 // Should detect value change | |
| 103 context['a'] = {'b': 'hello2'}; | |
| 104 watchGrp.detectChanges(); | |
| 105 expect(logger).toEqual(['hello', 'hello2']); | |
| 106 | |
| 107 // Should detect value change | |
| 108 context['a']['b'] = 'bye'; | |
| 109 watchGrp.detectChanges(); | |
| 110 expect(logger).toEqual(['hello', 'hello2', 'bye']); | |
| 111 | |
| 112 // should cleanup after itself | |
| 113 watch.remove(); | |
| 114 expect(watchGrp.fieldCost).toEqual(0); | |
| 115 context['a']['b'] = 'cant see me'; | |
| 116 watchGrp.detectChanges(); | |
| 117 expect(logger).toEqual(['hello', 'hello2', 'bye']); | |
| 118 }); | |
| 119 | |
| 120 it('should reuse handlers', () { | |
| 121 var user1 = {'first': 'misko', 'last': 'hevery'}; | |
| 122 var user2 = {'first': 'misko', 'last': 'Hevery'}; | |
| 123 | |
| 124 context['user'] = user1; | |
| 125 | |
| 126 // should fire on initial adding | |
| 127 expect(watchGrp.fieldCost).toEqual(0); | |
| 128 var watch = watchGrp.watch(parse('user'), (v, p) => logger(v)); | |
| 129 var watchFirst = watchGrp.watch(parse('user.first'), (v, p) => logger(v)); | |
| 130 var watchLast = watchGrp.watch(parse('user.last'), (v, p) => logger(v)); | |
| 131 expect(watchGrp.fieldCost).toEqual(3); | |
| 132 | |
| 133 watchGrp.detectChanges(); | |
| 134 expect(logger).toEqual([user1, 'misko', 'hevery']); | |
| 135 logger.clear(); | |
| 136 | |
| 137 context['user'] = user2; | |
| 138 watchGrp.detectChanges(); | |
| 139 expect(logger).toEqual([user2, 'Hevery']); | |
| 140 | |
| 141 | |
| 142 watch.remove(); | |
| 143 expect(watchGrp.fieldCost).toEqual(3); | |
| 144 | |
| 145 watchFirst.remove(); | |
| 146 expect(watchGrp.fieldCost).toEqual(2); | |
| 147 | |
| 148 watchLast.remove(); | |
| 149 expect(watchGrp.fieldCost).toEqual(0); | |
| 150 | |
| 151 expect(() => watch.remove()).toThrow('Already deleted!'); | |
| 152 }); | |
| 153 | |
| 154 it('should eval pure FunctionApply', () { | |
| 155 context['a'] = {'val': 1}; | |
| 156 | |
| 157 FunctionApply fn = new LoggingFunctionApply(logger); | |
| 158 var watch = watchGrp.watch( | |
| 159 new PureFunctionAST('add', fn, [parse('a.val')]), | |
| 160 (v, p) => logger(v) | |
| 161 ); | |
| 162 | |
| 163 // a; a.val; b; b.val; | |
| 164 expect(watchGrp.fieldCost).toEqual(2); | |
| 165 // add | |
| 166 expect(watchGrp.evalCost).toEqual(1); | |
| 167 | |
| 168 watchGrp.detectChanges(); | |
| 169 expect(logger).toEqual([[1], null]); | |
| 170 logger.clear(); | |
| 171 | |
| 172 context['a'] = {'val': 2}; | |
| 173 watchGrp.detectChanges(); | |
| 174 expect(logger).toEqual([[2]]); | |
| 175 }); | |
| 176 | |
| 177 | |
| 178 it('should eval pure function', () { | |
| 179 context['a'] = {'val': 1}; | |
| 180 context['b'] = {'val': 2}; | |
| 181 | |
| 182 var watch = watchGrp.watch( | |
| 183 new PureFunctionAST('add', | |
| 184 (a, b) { logger('+'); return a+b; }, | |
| 185 [parse('a.val'), parse('b.val')] | |
| 186 ), | |
| 187 (v, p) => logger(v) | |
| 188 ); | |
| 189 | |
| 190 // a; a.val; b; b.val; | |
| 191 expect(watchGrp.fieldCost).toEqual(4); | |
| 192 // add | |
| 193 expect(watchGrp.evalCost).toEqual(1); | |
| 194 | |
| 195 watchGrp.detectChanges(); | |
| 196 expect(logger).toEqual(['+', 3]); | |
| 197 | |
| 198 // extra checks should not trigger functions | |
| 199 watchGrp.detectChanges(); | |
| 200 watchGrp.detectChanges(); | |
| 201 expect(logger).toEqual(['+', 3]); | |
| 202 | |
| 203 // multiple arg changes should only trigger function once. | |
| 204 context['a']['val'] = 3; | |
| 205 context['b']['val'] = 4; | |
| 206 | |
| 207 watchGrp.detectChanges(); | |
| 208 expect(logger).toEqual(['+', 3, '+', 7]); | |
| 209 | |
| 210 watch.remove(); | |
| 211 expect(watchGrp.fieldCost).toEqual(0); | |
| 212 expect(watchGrp.evalCost).toEqual(0); | |
| 213 | |
| 214 context['a']['val'] = 0; | |
| 215 context['b']['val'] = 0; | |
| 216 | |
| 217 watchGrp.detectChanges(); | |
| 218 expect(logger).toEqual(['+', 3, '+', 7]); | |
| 219 }); | |
| 220 | |
| 221 | |
| 222 it('should eval chained pure function', () { | |
| 223 context['a'] = {'val': 1}; | |
| 224 context['b'] = {'val': 2}; | |
| 225 context['c'] = {'val': 3}; | |
| 226 | |
| 227 var a_plus_b = new PureFunctionAST('add1', | |
| 228 (a, b) { logger('$a+$b'); return a + b; }, | |
| 229 [parse('a.val'), parse('b.val')]); | |
| 230 | |
| 231 var a_plus_b_plus_c = new PureFunctionAST('add2', | |
| 232 (b, c) { logger('$b+$c'); return b + c; }, | |
| 233 [a_plus_b, parse('c.val')]); | |
| 234 | |
| 235 var watch = watchGrp.watch(a_plus_b_plus_c, (v, p) => logger(v)); | |
| 236 | |
| 237 // a; a.val; b; b.val; c; c.val; | |
| 238 expect(watchGrp.fieldCost).toEqual(6); | |
| 239 // add | |
| 240 expect(watchGrp.evalCost).toEqual(2); | |
| 241 | |
| 242 watchGrp.detectChanges(); | |
| 243 expect(logger).toEqual(['1+2', '3+3', 6]); | |
| 244 logger.clear(); | |
| 245 | |
| 246 // extra checks should not trigger functions | |
| 247 watchGrp.detectChanges(); | |
| 248 watchGrp.detectChanges(); | |
| 249 expect(logger).toEqual([]); | |
| 250 logger.clear(); | |
| 251 | |
| 252 // multiple arg changes should only trigger function once. | |
| 253 context['a']['val'] = 3; | |
| 254 context['b']['val'] = 4; | |
| 255 context['c']['val'] = 5; | |
| 256 watchGrp.detectChanges(); | |
| 257 expect(logger).toEqual(['3+4', '7+5', 12]); | |
| 258 logger.clear(); | |
| 259 | |
| 260 context['a']['val'] = 9; | |
| 261 watchGrp.detectChanges(); | |
| 262 expect(logger).toEqual(['9+4', '13+5', 18]); | |
| 263 logger.clear(); | |
| 264 | |
| 265 context['c']['val'] = 9; | |
| 266 watchGrp.detectChanges(); | |
| 267 expect(logger).toEqual(['13+9', 22]); | |
| 268 logger.clear(); | |
| 269 | |
| 270 | |
| 271 watch.remove(); | |
| 272 expect(watchGrp.fieldCost).toEqual(0); | |
| 273 expect(watchGrp.evalCost).toEqual(0); | |
| 274 | |
| 275 context['a']['val'] = 0; | |
| 276 context['b']['val'] = 0; | |
| 277 | |
| 278 watchGrp.detectChanges(); | |
| 279 expect(logger).toEqual([]); | |
| 280 }); | |
| 281 | |
| 282 | |
| 283 it('should eval closure', () { | |
| 284 var obj; | |
| 285 obj = { | |
| 286 'methodA': (arg1) { | |
| 287 logger('methodA($arg1) => ${obj['valA']}'); | |
| 288 return obj['valA']; | |
| 289 }, | |
| 290 'valA': 'A' | |
| 291 }; | |
| 292 context['obj'] = obj; | |
| 293 context['arg0'] = 1; | |
| 294 | |
| 295 var watch = watchGrp.watch( | |
| 296 new MethodAST(parse('obj'), 'methodA', [parse('arg0')]), | |
| 297 (v, p) => logger(v) | |
| 298 ); | |
| 299 | |
| 300 // obj, arg0; | |
| 301 expect(watchGrp.fieldCost).toEqual(2); | |
| 302 // methodA() | |
| 303 expect(watchGrp.evalCost).toEqual(1); | |
| 304 | |
| 305 watchGrp.detectChanges(); | |
| 306 expect(logger).toEqual(['methodA(1) => A', 'A']); | |
| 307 logger.clear(); | |
| 308 | |
| 309 watchGrp.detectChanges(); | |
| 310 watchGrp.detectChanges(); | |
| 311 expect(logger).toEqual(['methodA(1) => A', 'methodA(1) => A']); | |
| 312 logger.clear(); | |
| 313 | |
| 314 obj['valA'] = 'B'; | |
| 315 context['arg0'] = 2; | |
| 316 | |
| 317 watchGrp.detectChanges(); | |
| 318 expect(logger).toEqual(['methodA(2) => B', 'B']); | |
| 319 logger.clear(); | |
| 320 | |
| 321 watch.remove(); | |
| 322 expect(watchGrp.fieldCost).toEqual(0); | |
| 323 expect(watchGrp.evalCost).toEqual(0); | |
| 324 | |
| 325 obj['valA'] = 'C'; | |
| 326 context['arg0'] = 3; | |
| 327 | |
| 328 watchGrp.detectChanges(); | |
| 329 expect(logger).toEqual([]); | |
| 330 }); | |
| 331 | |
| 332 | |
| 333 it('should eval method', () { | |
| 334 var obj = new MyClass(logger); | |
| 335 obj.valA = 'A'; | |
| 336 context['obj'] = obj; | |
| 337 context['arg0'] = 1; | |
| 338 | |
| 339 var watch = watchGrp.watch( | |
| 340 new MethodAST(parse('obj'), 'methodA', [parse('arg0')]), | |
| 341 (v, p) => logger(v) | |
| 342 ); | |
| 343 | |
| 344 // obj, arg0; | |
| 345 expect(watchGrp.fieldCost).toEqual(2); | |
| 346 // methodA() | |
| 347 expect(watchGrp.evalCost).toEqual(1); | |
| 348 | |
| 349 watchGrp.detectChanges(); | |
| 350 expect(logger).toEqual(['methodA(1) => A', 'A']); | |
| 351 logger.clear(); | |
| 352 | |
| 353 watchGrp.detectChanges(); | |
| 354 watchGrp.detectChanges(); | |
| 355 expect(logger).toEqual(['methodA(1) => A', 'methodA(1) => A']); | |
| 356 logger.clear(); | |
| 357 | |
| 358 obj.valA = 'B'; | |
| 359 context['arg0'] = 2; | |
| 360 | |
| 361 watchGrp.detectChanges(); | |
| 362 expect(logger).toEqual(['methodA(2) => B', 'B']); | |
| 363 logger.clear(); | |
| 364 | |
| 365 watch.remove(); | |
| 366 expect(watchGrp.fieldCost).toEqual(0); | |
| 367 expect(watchGrp.evalCost).toEqual(0); | |
| 368 | |
| 369 obj.valA = 'C'; | |
| 370 context['arg0'] = 3; | |
| 371 | |
| 372 watchGrp.detectChanges(); | |
| 373 expect(logger).toEqual([]); | |
| 374 }); | |
| 375 | |
| 376 it('should eval method chain', () { | |
| 377 var obj1 = new MyClass(logger); | |
| 378 var obj2 = new MyClass(logger); | |
| 379 obj1.valA = obj2; | |
| 380 obj2.valA = 'A'; | |
| 381 context['obj'] = obj1; | |
| 382 context['arg0'] = 0; | |
| 383 context['arg1'] = 1; | |
| 384 | |
| 385 // obj.methodA(arg0) | |
| 386 var ast = new MethodAST(parse('obj'), 'methodA', [parse('arg0')]); | |
| 387 ast = new MethodAST(ast, 'methodA', [parse('arg1')]); | |
| 388 var watch = watchGrp.watch(ast, (v, p) => logger(v)); | |
| 389 | |
| 390 // obj, arg0, arg1; | |
| 391 expect(watchGrp.fieldCost).toEqual(3); | |
| 392 // methodA(), mothodA() | |
| 393 expect(watchGrp.evalCost).toEqual(2); | |
| 394 | |
| 395 watchGrp.detectChanges(); | |
| 396 expect(logger).toEqual(['methodA(0) => MyClass', 'methodA(1) => A', 'A']); | |
| 397 logger.clear(); | |
| 398 | |
| 399 watchGrp.detectChanges(); | |
| 400 watchGrp.detectChanges(); | |
| 401 expect(logger).toEqual(['methodA(0) => MyClass', 'methodA(1) => A', | |
| 402 'methodA(0) => MyClass', 'methodA(1) => A']); | |
| 403 logger.clear(); | |
| 404 | |
| 405 obj2.valA = 'B'; | |
| 406 context['arg0'] = 10; | |
| 407 context['arg1'] = 11; | |
| 408 | |
| 409 watchGrp.detectChanges(); | |
| 410 expect(logger).toEqual(['methodA(10) => MyClass', 'methodA(11) => B', 'B']
); | |
| 411 logger.clear(); | |
| 412 | |
| 413 watch.remove(); | |
| 414 expect(watchGrp.fieldCost).toEqual(0); | |
| 415 expect(watchGrp.evalCost).toEqual(0); | |
| 416 | |
| 417 obj2.valA = 'C'; | |
| 418 context['arg0'] = 20; | |
| 419 context['arg1'] = 21; | |
| 420 | |
| 421 watchGrp.detectChanges(); | |
| 422 expect(logger).toEqual([]); | |
| 423 }); | |
| 424 | |
| 425 it('should read connstant', () { | |
| 426 // should fire on initial adding | |
| 427 expect(watchGrp.fieldCost).toEqual(0); | |
| 428 var watch = watchGrp.watch(new ConstantAST(123), (v, p) => logger(v)); | |
| 429 expect(watch.expression).toEqual('123'); | |
| 430 expect(watchGrp.fieldCost).toEqual(0); | |
| 431 watchGrp.detectChanges(); | |
| 432 expect(logger).toEqual([123]); | |
| 433 | |
| 434 // make sore no new changes are logged on extra detectChanges | |
| 435 watchGrp.detectChanges(); | |
| 436 expect(logger).toEqual([123]); | |
| 437 }); | |
| 438 | |
| 439 it('should wrap iterable in ObservableList', () { | |
| 440 context['list'] = []; | |
| 441 var watch = watchGrp.watch(new CollectionAST(parse('list')), (v, p) => log
ger(v)); | |
| 442 | |
| 443 expect(watchGrp.fieldCost).toEqual(1); | |
| 444 expect(watchGrp.collectionCost).toEqual(1); | |
| 445 expect(watchGrp.evalCost).toEqual(0); | |
| 446 | |
| 447 watchGrp.detectChanges(); | |
| 448 expect(logger.length).toEqual(1); | |
| 449 expect(logger[0], toEqualCollectionRecord( | |
| 450 collection: [], | |
| 451 additions: [], | |
| 452 moves: [], | |
| 453 removals: [])); | |
| 454 logger.clear(); | |
| 455 | |
| 456 context['list'] = [1]; | |
| 457 watchGrp.detectChanges(); | |
| 458 expect(logger.length).toEqual(1); | |
| 459 expect(logger[0], toEqualCollectionRecord( | |
| 460 collection: ['1[null -> 0]'], | |
| 461 additions: ['1[null -> 0]'], | |
| 462 moves: [], | |
| 463 removals: [])); | |
| 464 logger.clear(); | |
| 465 | |
| 466 watch.remove(); | |
| 467 expect(watchGrp.fieldCost).toEqual(0); | |
| 468 expect(watchGrp.collectionCost).toEqual(0); | |
| 469 expect(watchGrp.evalCost).toEqual(0); | |
| 470 }); | |
| 471 | |
| 472 it('should watch literal arrays made of expressions', () { | |
| 473 context['a'] = 1; | |
| 474 var ast = new CollectionAST( | |
| 475 new PureFunctionAST('[a]', new ArrayFn(), [parse('a')]) | |
| 476 ); | |
| 477 var watch = watchGrp.watch(ast, (v, p) => logger(v)); | |
| 478 watchGrp.detectChanges(); | |
| 479 expect(logger[0], toEqualCollectionRecord( | |
| 480 collection: ['1[null -> 0]'], | |
| 481 additions: ['1[null -> 0]'], | |
| 482 moves: [], | |
| 483 removals: [])); | |
| 484 logger.clear(); | |
| 485 | |
| 486 context['a'] = 2; | |
| 487 watchGrp.detectChanges(); | |
| 488 expect(logger[0], toEqualCollectionRecord( | |
| 489 collection: ['2[null -> 0]'], | |
| 490 additions: ['2[null -> 0]'], | |
| 491 moves: [], | |
| 492 removals: ['1[0 -> null]'])); | |
| 493 logger.clear(); | |
| 494 }); | |
| 495 | |
| 496 it('should watch pure function whose result goes to pure function', () { | |
| 497 context['a'] = 1; | |
| 498 var ast = new PureFunctionAST( | |
| 499 '-', | |
| 500 (v) => -v, | |
| 501 [new PureFunctionAST('++', (v) => v + 1, [parse('a')])] | |
| 502 ); | |
| 503 var watch = watchGrp.watch(ast, (v, p) => logger(v)); | |
| 504 | |
| 505 expect(watchGrp.detectChanges()).not.toBe(null); | |
| 506 expect(logger).toEqual([-2]); | |
| 507 logger.clear(); | |
| 508 | |
| 509 context['a'] = 2; | |
| 510 expect(watchGrp.detectChanges()).not.toBe(null); | |
| 511 expect(logger).toEqual([-3]); | |
| 512 }); | |
| 513 }); | |
| 514 | |
| 515 describe('child group', () { | |
| 516 it('should remove all field watches in group and group\'s children', () { | |
| 517 watchGrp.watch(parse('a'), (v, p) => logger('0a')); | |
| 518 var child1a = watchGrp.newGroup(new PrototypeMap(context)); | |
| 519 var child1b = watchGrp.newGroup(new PrototypeMap(context)); | |
| 520 var child2 = child1a.newGroup(new PrototypeMap(context)); | |
| 521 child1a.watch(parse('a'), (v, p) => logger('1a')); | |
| 522 child1b.watch(parse('a'), (v, p) => logger('1b')); | |
| 523 watchGrp.watch(parse('a'), (v, p) => logger('0A')); | |
| 524 child1a.watch(parse('a'), (v, p) => logger('1A')); | |
| 525 child2.watch(parse('a'), (v, p) => logger('2A')); | |
| 526 | |
| 527 // flush initial reaction functions | |
| 528 expect(watchGrp.detectChanges()).toEqual(6); | |
| 529 // expect(logger).toEqual(['0a', '0A', '1a', '1A', '2A', '1b']); | |
| 530 expect(logger).toEqual(['0a', '1a', '1b', '0A', '1A', '2A']); // we go by
registration order | |
| 531 expect(watchGrp.fieldCost).toEqual(1); | |
| 532 expect(watchGrp.totalFieldCost).toEqual(4); | |
| 533 logger.clear(); | |
| 534 | |
| 535 context['a'] = 1; | |
| 536 expect(watchGrp.detectChanges()).toEqual(6); | |
| 537 expect(logger).toEqual(['0a', '0A', '1a', '1A', '2A', '1b']); // we go by
group order | |
| 538 logger.clear(); | |
| 539 | |
| 540 context['a'] = 2; | |
| 541 child1a.remove(); // should also remove child2 | |
| 542 expect(watchGrp.detectChanges()).toEqual(3); | |
| 543 expect(logger).toEqual(['0a', '0A', '1b']); | |
| 544 expect(watchGrp.fieldCost).toEqual(1); | |
| 545 expect(watchGrp.totalFieldCost).toEqual(2); | |
| 546 }); | |
| 547 | |
| 548 it('should remove all method watches in group and group\'s children', () { | |
| 549 context['my'] = new MyClass(logger); | |
| 550 AST countMethod = new MethodAST(parse('my'), 'count', []); | |
| 551 watchGrp.watch(countMethod, (v, p) => logger('0a')); | |
| 552 expectOrder(['0a']); | |
| 553 | |
| 554 var child1a = watchGrp.newGroup(new PrototypeMap(context)); | |
| 555 var child1b = watchGrp.newGroup(new PrototypeMap(context)); | |
| 556 var child2 = child1a.newGroup(new PrototypeMap(context)); | |
| 557 child1a.watch(countMethod, (v, p) => logger('1a')); | |
| 558 expectOrder(['0a', '1a']); | |
| 559 child1b.watch(countMethod, (v, p) => logger('1b')); | |
| 560 expectOrder(['0a', '1a', '1b']); | |
| 561 watchGrp.watch(countMethod, (v, p) => logger('0A')); | |
| 562 expectOrder(['0a', '0A', '1a', '1b']); | |
| 563 child1a.watch(countMethod, (v, p) => logger('1A')); | |
| 564 expectOrder(['0a', '0A', '1a', '1A', '1b']); | |
| 565 child2.watch(countMethod, (v, p) => logger('2A')); | |
| 566 expectOrder(['0a', '0A', '1a', '1A', '2A', '1b']); | |
| 567 | |
| 568 // flush initial reaction functions | |
| 569 expect(watchGrp.detectChanges()).toEqual(6); | |
| 570 expectOrder(['0a', '0A', '1a', '1A', '2A', '1b']); | |
| 571 | |
| 572 child1a.remove(); // should also remove child2 | |
| 573 expect(watchGrp.detectChanges()).toEqual(3); | |
| 574 expectOrder(['0a', '0A', '1b']); | |
| 575 }); | |
| 576 | |
| 577 it('should add watches within its own group', () { | |
| 578 context['my'] = new MyClass(logger); | |
| 579 AST countMethod = new MethodAST(parse('my'), 'count', []); | |
| 580 var ra = watchGrp.watch(countMethod, (v, p) => logger('a')); | |
| 581 var child = watchGrp.newGroup(new PrototypeMap(context)); | |
| 582 var cb = child.watch(countMethod, (v, p) => logger('b')); | |
| 583 | |
| 584 expectOrder(['a', 'b']); | |
| 585 expectOrder(['a', 'b']); | |
| 586 | |
| 587 ra.remove(); | |
| 588 expectOrder(['b']); | |
| 589 | |
| 590 cb.remove(); | |
| 591 expectOrder([]); | |
| 592 | |
| 593 // TODO: add them back in wrong order, assert events in right order | |
| 594 cb = child.watch(countMethod, (v, p) => logger('b')); | |
| 595 ra = watchGrp.watch(countMethod, (v, p) => logger('a'));; | |
| 596 expectOrder(['a', 'b']); | |
| 597 }); | |
| 598 | |
| 599 | |
| 600 it('should not call reaction function on removed group', () { | |
| 601 var log = []; | |
| 602 context['name'] = 'misko'; | |
| 603 var child = watchGrp.newGroup(context); | |
| 604 watchGrp.watch(parse('name'), (v, _) { | |
| 605 log.add('root $v'); | |
| 606 if (v == 'destroy') { | |
| 607 child.remove(); | |
| 608 } | |
| 609 }); | |
| 610 child.watch(parse('name'), (v, _) => log.add('child $v')); | |
| 611 watchGrp.detectChanges(); | |
| 612 expect(log).toEqual(['root misko', 'child misko']); | |
| 613 log.clear(); | |
| 614 | |
| 615 context['name'] = 'destroy'; | |
| 616 watchGrp.detectChanges(); | |
| 617 expect(log).toEqual(['root destroy']); | |
| 618 }); | |
| 619 | |
| 620 | |
| 621 | |
| 622 it('should watch children', () { | |
| 623 var childContext = new PrototypeMap(context); | |
| 624 context['a'] = 'OK'; | |
| 625 context['b'] = 'BAD'; | |
| 626 childContext['b'] = 'OK'; | |
| 627 watchGrp.watch(parse('a'), (v, p) => logger(v)); | |
| 628 watchGrp.newGroup(childContext).watch(parse('b'), (v, p) => logger(v)); | |
| 629 | |
| 630 watchGrp.detectChanges(); | |
| 631 expect(logger).toEqual(['OK', 'OK']); | |
| 632 logger.clear(); | |
| 633 | |
| 634 context['a'] = 'A'; | |
| 635 childContext['b'] = 'B'; | |
| 636 | |
| 637 watchGrp.detectChanges(); | |
| 638 expect(logger).toEqual(['A', 'B']); | |
| 639 logger.clear(); | |
| 640 }); | |
| 641 }); | |
| 642 | |
| 643 }); | |
| 644 | |
| 645 class MyClass { | |
| 646 final Logger logger; | |
| 647 var valA; | |
| 648 int _count = 0; | |
| 649 | |
| 650 MyClass(this.logger); | |
| 651 | |
| 652 methodA(arg1) { | |
| 653 logger('methodA($arg1) => $valA'); | |
| 654 return valA; | |
| 655 } | |
| 656 | |
| 657 count() => _count++; | |
| 658 | |
| 659 String toString() => 'MyClass'; | |
| 660 } | |
| 661 | |
| 662 class LoggingFunctionApply extends FunctionApply { | |
| 663 Logger logger; | |
| 664 LoggingFunctionApply(this.logger); | |
| 665 apply(List args) => logger(args); | |
| 666 } | |
| OLD | NEW |