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

Side by Side Diff: third_party/pkg/angular/test/core/scope_spec.dart

Issue 1058283006: Update pubspecs and dependencies to get pkgbuild tests working. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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
(Empty)
1 library scope2_spec;
2
3 import '../_specs.dart';
4 import 'package:angular/change_detection/change_detection.dart' hide ExceptionHa ndler;
5 import 'package:angular/change_detection/dirty_checking_change_detector.dart';
6 import 'dart:async';
7 import 'dart:math';
8
9 main() => describe('scope', () {
10 beforeEach(module((Module module) {
11 Map context = {};
12 module.value(GetterCache, new GetterCache({}));
13 module.type(ChangeDetector, implementedBy: DirtyCheckingChangeDetector);
14 module.value(Object, context);
15 module.value(Map, context);
16 module.type(RootScope);
17 module.type(_MultiplyFilter);
18 module.type(_ListHeadFilter);
19 module.type(_ListTailFilter);
20 module.type(_SortFilter);
21 }));
22
23 describe('AST Bridge', () {
24 it('should watch field', inject((Logger logger, Map context, RootScope rootS cope) {
25 context['field'] = 'Worked!';
26 rootScope.watch('field', (value, previous) => logger([value, previous]));
27 expect(logger).toEqual([]);
28 rootScope.digest();
29 expect(logger).toEqual([['Worked!', null]]);
30 rootScope.digest();
31 expect(logger).toEqual([['Worked!', null]]);
32 }));
33
34 it('should watch field path', inject((Logger logger, Map context, RootScope rootScope) {
35 context['a'] = {'b': 'AB'};
36 rootScope.watch('a.b', (value, previous) => logger(value));
37 rootScope.digest();
38 expect(logger).toEqual(['AB']);
39 context['a']['b'] = '123';
40 rootScope.digest();
41 expect(logger).toEqual(['AB', '123']);
42 context['a'] = {'b': 'XYZ'};
43 rootScope.digest();
44 expect(logger).toEqual(['AB', '123', 'XYZ']);
45 }));
46
47 it('should watch math operations', inject((Logger logger, Map context, RootS cope rootScope) {
48 context['a'] = 1;
49 context['b'] = 2;
50 rootScope.watch('a + b + 1', (value, previous) => logger(value));
51 rootScope.digest();
52 expect(logger).toEqual([4]);
53 context['a'] = 3;
54 rootScope.digest();
55 expect(logger).toEqual([4, 6]);
56 context['b'] = 5;
57 rootScope.digest();
58 expect(logger).toEqual([4, 6, 9]);
59 }));
60
61
62 it('should watch literals', inject((Logger logger, Map context, RootScope ro otScope) {
63 context['a'] = 1;
64 rootScope.watch('1', (value, previous) => logger(value));
65 rootScope.watch('"str"', (value, previous) => logger(value));
66 rootScope.watch('[a, 2, 3]', (value, previous) => logger(value));
67 rootScope.watch('{a:a, b:2}', (value, previous) => logger(value));
68 rootScope.digest();
69 expect(logger).toEqual([1, 'str', [1, 2, 3], {'a': 1, 'b': 2}]);
70 logger.clear();
71 context['a'] = 3;
72 rootScope.digest();
73 expect(logger).toEqual([[3, 2, 3], {'a': 3, 'b': 2}]);
74 }));
75
76 it('should invoke closures', inject((Logger logger, Map context, RootScope r ootScope) {
77 context['fn'] = () {
78 logger('fn');
79 return 1;
80 };
81 context['a'] = {'fn': () {
82 logger('a.fn');
83 return 2;
84 }};
85 rootScope.watch('fn()', (value, previous) => logger('=> $value'));
86 rootScope.watch('a.fn()', (value, previous) => logger('-> $value'));
87 rootScope.digest();
88 expect(logger).toEqual(['fn', 'a.fn', '=> 1', '-> 2',
89 /* second loop*/ 'fn', 'a.fn']);
90 logger.clear();
91 rootScope.digest();
92 expect(logger).toEqual(['fn', 'a.fn']);
93 }));
94
95 it('should perform conditionals', inject((Logger logger, Map context, RootSc ope rootScope) {
96 context['a'] = 1;
97 context['b'] = 2;
98 context['c'] = 3;
99 rootScope.watch('a?b:c', (value, previous) => logger(value));
100 rootScope.digest();
101 expect(logger).toEqual([2]);
102 logger.clear();
103 context['a'] = 0;
104 rootScope.digest();
105 expect(logger).toEqual([3]);
106 }));
107
108
109 xit('should call function', inject((Logger logger, Map context, RootScope ro otScope) {
110 context['a'] = () {
111 return () { return 123; };
112 };
113 rootScope.watch('a()()', (value, previous) => logger(value));
114 rootScope.digest();
115 expect(logger).toEqual([123]);
116 logger.clear();
117 rootScope.digest();
118 expect(logger).toEqual([]);
119 }));
120
121 it('should access bracket', inject((Logger logger, Map context, RootScope ro otScope) {
122 context['a'] = {'b': 123};
123 rootScope.watch('a["b"]', (value, previous) => logger(value));
124 rootScope.digest();
125 expect(logger).toEqual([123]);
126 logger.clear();
127 rootScope.digest();
128 expect(logger).toEqual([]);
129 }));
130
131
132 it('should prefix', inject((Logger logger, Map context, RootScope rootScope) {
133 context['a'] = true;
134 rootScope.watch('!a', (value, previous) => logger(value));
135 rootScope.digest();
136 expect(logger).toEqual([false]);
137 logger.clear();
138 context['a'] = false;
139 rootScope.digest();
140 expect(logger).toEqual([true]);
141 }));
142
143 it('should support filters', inject((Logger logger, Map context,
144 RootScope rootScope, AstParser parser,
145 FilterMap filters) {
146 context['a'] = 123;
147 context['b'] = 2;
148 rootScope.watch(
149 parser('a | multiply:b', filters: filters),
150 (value, previous) => logger(value));
151 rootScope.digest();
152 expect(logger).toEqual([246]);
153 logger.clear();
154 rootScope.digest();
155 expect(logger).toEqual([]);
156 logger.clear();
157 }));
158
159 it('should support arrays in filters', inject((Logger logger, Map context,
160 RootScope rootScope,
161 AstParser parser,
162 FilterMap filters) {
163 context['a'] = [1];
164 rootScope.watch(
165 parser('a | sort | listHead:"A" | listTail:"B"', filters: filters),
166 (value, previous) => logger(value));
167 rootScope.digest();
168 expect(logger).toEqual(['sort', 'listHead', 'listTail', ['A', 1, 'B']]);
169 logger.clear();
170
171 rootScope.digest();
172 expect(logger).toEqual([]);
173 logger.clear();
174
175 context['a'].add(2);
176 rootScope.digest();
177 expect(logger).toEqual(['sort', 'listHead', 'listTail', ['A', 1, 2, 'B']]) ;
178 logger.clear();
179
180 // We change the order, but sort should change it to same one and it shoul d not
181 // call subsequent filters.
182 context['a'] = [2, 1];
183 rootScope.digest();
184 expect(logger).toEqual(['sort']);
185 logger.clear();
186 }));
187 });
188
189
190 describe('properties', () {
191 describe('root', () {
192 it('should point to itself', inject((RootScope rootScope) {
193 expect(rootScope.rootScope).toEqual(rootScope);
194 }));
195
196 it('children should point to root', inject((RootScope rootScope) {
197 var child = rootScope.createChild(new PrototypeMap(rootScope.context));
198 expect(child.rootScope).toEqual(rootScope);
199 expect(child.createChild(new PrototypeMap(rootScope.context)).rootScope) .toEqual(rootScope);
200 }));
201 });
202
203
204 describe('parent', () {
205 it('should not have parent', inject((RootScope rootScope) {
206 expect(rootScope.parentScope).toEqual(null);
207 }));
208
209
210 it('should point to parent', inject((RootScope rootScope) {
211 var child = rootScope.createChild(new PrototypeMap(rootScope.context));
212 expect(rootScope.parentScope).toEqual(null);
213 expect(child.parentScope).toEqual(rootScope);
214 expect(child.createChild(new PrototypeMap(rootScope.context)).parentScop e).toEqual(child);
215 }));
216 });
217 });
218
219
220 describe(r'events', () {
221
222 describe('on', () {
223 it('should allow emit/broadcast when no listeners', inject((RootScope scop e) {
224 scope.emit('foo');
225 scope.broadcast('foo');
226 }));
227
228
229 it(r'should add listener for both emit and broadcast events', inject((Root Scope rootScope) {
230 var log = '',
231 child = rootScope.createChild(new PrototypeMap(rootScope.context));
232
233 eventFn(event) {
234 expect(event).not.toEqual(null);
235 log += 'X';
236 }
237
238 child.on('abc').listen(eventFn);
239 expect(log).toEqual('');
240
241 child.emit('abc');
242 expect(log).toEqual('X');
243
244 child.broadcast('abc');
245 expect(log).toEqual('XX');
246 }));
247
248
249 it(r'should return a function that deregisters the listener', inject((Root Scope rootScope) {
250 var log = '';
251 var child = rootScope.createChild(new PrototypeMap(rootScope.context));
252 var subscription;
253
254 eventFn(e) {
255 log += 'X';
256 }
257
258 subscription = child.on('abc').listen(eventFn);
259 expect(log).toEqual('');
260 expect(subscription).toBeDefined();
261
262 child.emit(r'abc');
263 child.broadcast('abc');
264 expect(log).toEqual('XX');
265
266 log = '';
267 expect(subscription.cancel()).toBe(null);
268 child.emit(r'abc');
269 child.broadcast('abc');
270 expect(log).toEqual('');
271 }));
272
273 it('should not trigger assertions on scope fork', inject((RootScope root) {
274 var d1 = root.createChild({});
275 var d2 = root.createChild({});
276 var d3 = d2.createChild({});
277 expect(root.apply).not.toThrow();
278 d1.on(ScopeEvent.DESTROY).listen((_) => null);
279 expect(root.apply).not.toThrow();
280 d3.on(ScopeEvent.DESTROY).listen((_) => null);
281 expect(root.apply).not.toThrow();
282 d2.on(ScopeEvent.DESTROY).listen((_) => null);
283 expect(root.apply).not.toThrow();
284 }));
285
286 it('should not too eagerly create own streams', inject((RootScope root) {
287 var a = root.createChild({});
288 var a2 = root.createChild({});
289 var b = a.createChild({});
290 var c = b.createChild({});
291 var d = c.createChild({});
292 var e = d.createChild({});
293
294 getStreamState() => [root.hasOwnStreams, a.hasOwnStreams, a2.hasOwnStrea ms,
295 b.hasOwnStreams, c.hasOwnStreams, d.hasOwnStreams,
296 e.hasOwnStreams];
297
298 expect(getStreamState()).toEqual([false, false, false, false, false, fal se, false]);
299 expect(root.apply).not.toThrow();
300
301 e.on(ScopeEvent.DESTROY).listen((_) => null);
302 expect(getStreamState()).toEqual([false, false, false, false, false, fal se, true]);
303 expect(root.apply).not.toThrow();
304
305 d.on(ScopeEvent.DESTROY).listen((_) => null);
306 expect(getStreamState()).toEqual([false, false, false, false, false, tru e, true]);
307 expect(root.apply).not.toThrow();
308
309 b.on(ScopeEvent.DESTROY).listen((_) => null);
310 expect(getStreamState()).toEqual([false, false, false, true, false, true , true]);
311 expect(root.apply).not.toThrow();
312
313 c.on(ScopeEvent.DESTROY).listen((_) => null);
314 expect(getStreamState()).toEqual([false, false, false, true, true, true, true]);
315 expect(root.apply).not.toThrow();
316
317 a.on(ScopeEvent.DESTROY).listen((_) => null);
318 expect(getStreamState()).toEqual([false, true, false, true, true, true, true]);
319 expect(root.apply).not.toThrow();
320
321 a2.on(ScopeEvent.DESTROY).listen((_) => null);
322 expect(getStreamState()).toEqual([true, true, true, true, true, true, tr ue]);
323 expect(root.apply).not.toThrow();
324 }));
325
326
327 it('should not properly merge streams', inject((RootScope root) {
328 var a = root.createChild({});
329 var a2 = root.createChild({});
330 var b = a.createChild({});
331 var c = b.createChild({});
332 var d = c.createChild({});
333 var e = d.createChild({});
334
335 getStreamState() => [root.hasOwnStreams, a.hasOwnStreams, a2.hasOwnStrea ms,
336 b.hasOwnStreams, c.hasOwnStreams, d.hasOwnStreams,
337 e.hasOwnStreams];
338
339 expect(getStreamState()).toEqual([false, false, false, false, false, fal se, false]);
340 expect(root.apply).not.toThrow();
341
342 a2.on(ScopeEvent.DESTROY).listen((_) => null);
343 expect(getStreamState()).toEqual([false, false, true, false, false, fals e, false]);
344 expect(root.apply).not.toThrow();
345
346 e.on(ScopeEvent.DESTROY).listen((_) => null);
347 expect(getStreamState()).toEqual([true, false, true, false, false, false , true]);
348 expect(root.apply).not.toThrow();
349 }));
350
351
352 it('should clean up on cancel', inject((RootScope root) {
353 var child = root.createChild(null);
354 var cl = child.on("E").listen((e) => null);
355 var rl = root.on("E").listen((e) => null);
356 rl.cancel();
357 expect(root.apply).not.toThrow();
358 }));
359
360
361 it('should find random bugs', inject((RootScope root) {
362 List scopes;
363 List listeners;
364 List steps;
365 var random = new Random();
366 for (var i = 0; i < 1000; i++) {
367 if (i % 10 == 0) {
368 scopes = [root.createChild(null)];
369 listeners = [];
370 steps = [];
371 }
372 switch(random.nextInt(4)) {
373 case 0:
374 if (scopes.length > 10) break;
375 var index = random.nextInt(scopes.length);
376 Scope scope = scopes[index];
377 var child = scope.createChild(null);
378 scopes.add(child);
379 steps.add('scopes[$index].createChild(null)');
380 break;
381 case 1:
382 var index = random.nextInt(scopes.length);
383 Scope scope = scopes[index];
384 listeners.add(scope.on('E').listen((e) => null));
385 steps.add('scopes[$index].on("E").listen((e)=>null)');
386 break;
387 case 2:
388 if (scopes.length < 3) break;
389 var index = random.nextInt(scopes.length - 1) + 1;
390 Scope scope = scopes[index];
391 scope.destroy();
392 scopes = scopes.where((Scope s) => s.isAttached).toList();
393 steps.add('scopes[$index].destroy()');
394 break;
395 case 3:
396 if (listeners.length == 0) break;
397 var index = random.nextInt(listeners.length);
398 var l = listeners[index];
399 l.cancel();
400 listeners.remove(l);
401 steps.add('listeners[$index].cancel()');
402 break;
403 }
404 try {
405 root.apply();
406 } catch (e) {
407 expect('').toEqual(steps.join(';\n'));
408 }
409 }
410 }));
411 });
412
413
414 describe('emit', () {
415 var log, child, grandChild, greatGrandChild;
416
417 logger(event) {
418 log.add(event.currentScope.context['id']);
419 }
420
421 beforeEach(module(() {
422 return (RootScope rootScope) {
423 log = [];
424 child = rootScope.createChild({'id': 1});
425 grandChild = child.createChild({'id': 2});
426 greatGrandChild = grandChild.createChild({'id': 3});
427
428 rootScope.context['id'] = 0;
429
430 rootScope.on('myEvent').listen(logger);
431 child.on('myEvent').listen(logger);
432 grandChild.on('myEvent').listen(logger);
433 greatGrandChild.on('myEvent').listen(logger);
434 };
435 }));
436
437 it(r'should bubble event up to the root scope', inject((RootScope rootScop e) {
438 grandChild.emit(r'myEvent');
439 expect(log.join('>')).toEqual('2>1>0');
440 }));
441
442
443 it(r'should dispatch exceptions to the exceptionHandler', () {
444 module((Module module) {
445 module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler);
446 });
447 inject((ExceptionHandler e) {
448 LoggingExceptionHandler exceptionHandler = e;
449 child.on('myEvent').listen((e) { throw 'bubbleException'; });
450 grandChild.emit(r'myEvent');
451 expect(log.join('>')).toEqual('2>1>0');
452 expect(exceptionHandler.errors[0].error).toEqual('bubbleException');
453 });
454 });
455
456
457 it(r'should allow stopping event propagation', inject((RootScope rootScope ) {
458 child.on('myEvent').listen((event) { event.stopPropagation(); });
459 grandChild.emit(r'myEvent');
460 expect(log.join('>')).toEqual('2>1');
461 }));
462
463
464 it(r'should forward method arguments', inject((RootScope rootScope) {
465 var eventName;
466 var eventData;
467 child.on('abc').listen((event) {
468 eventName = event.name;
469 eventData = event.data;
470 });
471 child.emit('abc', ['arg1', 'arg2']);
472 expect(eventName).toEqual('abc');
473 expect(eventData).toEqual(['arg1', 'arg2']);
474 }));
475
476
477 describe(r'event object', () {
478 it(r'should have methods/properties', inject((RootScope rootScope) {
479 var event;
480 child.on('myEvent').listen((e) {
481 expect(e.targetScope).toBe(grandChild);
482 expect(e.currentScope).toBe(child);
483 expect(e.name).toBe('myEvent');
484 event = e;
485 });
486 grandChild.emit(r'myEvent');
487 expect(event).toBeDefined();
488 }));
489
490
491 it(r'should have preventDefault method and defaultPrevented property', i nject((RootScope rootScope) {
492 var event = grandChild.emit(r'myEvent');
493 expect(event.defaultPrevented).toBe(false);
494
495 child.on('myEvent').listen((event) {
496 event.preventDefault();
497 });
498 event = grandChild.emit(r'myEvent');
499 expect(event.defaultPrevented).toBe(true);
500 }));
501 });
502 });
503
504
505 describe('broadcast', () {
506 describe(r'event propagation', () {
507 var log, child1, child2, child3, grandChild11, grandChild21, grandChild2 2, grandChild23,
508 greatGrandChild211;
509
510 logger(event) {
511 log.add(event.currentScope.context['id']);
512 }
513
514 beforeEach(inject((RootScope rootScope) {
515 log = [];
516 child1 = rootScope.createChild({});
517 child2 = rootScope.createChild({});
518 child3 = rootScope.createChild({});
519 grandChild11 = child1.createChild({});
520 grandChild21 = child2.createChild({});
521 grandChild22 = child2.createChild({});
522 grandChild23 = child2.createChild({});
523 greatGrandChild211 = grandChild21.createChild({});
524
525 rootScope.context['id'] = 0;
526 child1.context['id'] = 1;
527 child2.context['id'] = 2;
528 child3.context['id'] = 3;
529 grandChild11.context['id'] = 11;
530 grandChild21.context['id'] = 21;
531 grandChild22.context['id'] = 22;
532 grandChild23.context['id'] = 23;
533 greatGrandChild211.context['id'] = 211;
534
535 rootScope.on('myEvent').listen(logger);
536 child1.on('myEvent').listen(logger);
537 child2.on('myEvent').listen(logger);
538 child3.on('myEvent').listen(logger);
539 grandChild11.on('myEvent').listen(logger);
540 grandChild21.on('myEvent').listen(logger);
541 grandChild22.on('myEvent').listen(logger);
542 grandChild23.on('myEvent').listen(logger);
543 greatGrandChild211.on('myEvent').listen(logger);
544
545 // R
546 // / | \
547 // 1 2 3
548 // / / | \
549 // 11 21 22 23
550 // |
551 // 211
552 }));
553
554
555 it(r'should broadcast an event from the root scope', inject((RootScope r ootScope) {
556 rootScope.broadcast('myEvent');
557 expect(log.join('>')).toEqual('0>1>11>2>21>211>22>23>3');
558 }));
559
560
561 it(r'should broadcast an event from a child scope', inject((RootScope ro otScope) {
562 child2.broadcast('myEvent');
563 expect(log.join('>')).toEqual('2>21>211>22>23');
564 }));
565
566
567 it(r'should broadcast an event from a leaf scope with a sibling', inject ((RootScope rootScope) {
568 grandChild22.broadcast('myEvent');
569 expect(log.join('>')).toEqual('22');
570 }));
571
572
573 it(r'should broadcast an event from a leaf scope without a sibling', inj ect((RootScope rootScope) {
574 grandChild23.broadcast('myEvent');
575 expect(log.join('>')).toEqual('23');
576 }));
577
578
579 it(r'should not not fire any listeners for other events', inject((RootSc ope rootScope) {
580 rootScope.broadcast('fooEvent');
581 expect(log.join('>')).toEqual('');
582 }));
583
584
585 it(r'should return event object', inject((RootScope rootScope) {
586 var result = child1.broadcast('some');
587
588 expect(result).toBeDefined();
589 expect(result.name).toBe('some');
590 expect(result.targetScope).toBe(child1);
591 }));
592
593
594 it('should skip scopes which dont have given event',
595 inject((RootScope rootScope, Logger log) {
596 var child1 = rootScope.createChild('A');
597 rootScope.createChild('A1');
598 rootScope.createChild('A2');
599 rootScope.createChild('A3');
600 var child2 = rootScope.createChild('B');
601 child2.on('event').listen((e) => log(e.data));
602 rootScope.broadcast('event', 'OK');
603 expect(log).toEqual(['OK']);
604 }));
605 });
606
607
608 describe(r'listener', () {
609 it(r'should receive event object', inject((RootScope rootScope) {
610 var scope = rootScope,
611 child = scope.createChild({}),
612 event;
613
614 child.on('fooEvent').listen((e) {
615 event = e;
616 });
617 scope.broadcast('fooEvent');
618
619 expect(event.name).toBe('fooEvent');
620 expect(event.targetScope).toBe(scope);
621 expect(event.currentScope).toBe(child);
622 }));
623
624 it(r'should support passing messages as varargs', inject((RootScope root Scope) {
625 var scope = rootScope,
626 child = scope.createChild({}),
627 args;
628
629 child.on('fooEvent').listen((e) {
630 args = e.data;
631 });
632 scope.broadcast('fooEvent', ['do', 're', 'me', 'fa']);
633
634 expect(args.length).toBe(4);
635 expect(args).toEqual(['do', 're', 'me', 'fa']);
636 }));
637 });
638 });
639 });
640
641
642 describe(r'destroy', () {
643 var first = null, middle = null, last = null, log = null;
644
645 beforeEach(inject((RootScope rootScope) {
646 log = '';
647
648 first = rootScope.createChild({"check": (n) { log+= '$n'; return n;}});
649 middle = rootScope.createChild({"check": (n) { log+= '$n'; return n;}});
650 last = rootScope.createChild({"check": (n) { log+= '$n'; return n;}});
651
652 first.watch('check(1)', (v, l) {});
653 middle.watch('check(2)', (v, l) {});
654 last.watch('check(3)', (v, l) {});
655
656 first.on(ScopeEvent.DESTROY).listen((e) { log += 'destroy:first;'; });
657
658 rootScope.digest();
659 log = '';
660 }));
661
662
663 it(r'should ignore remove on root', inject((RootScope rootScope) {
664 rootScope.destroy();
665 rootScope.digest();
666 expect(log).toEqual('123');
667 }));
668
669
670 it(r'should remove first', inject((RootScope rootScope) {
671 first.destroy();
672 rootScope.digest();
673 expect(log).toEqual('destroy:first;23');
674 }));
675
676
677 it(r'should remove middle', inject((RootScope rootScope) {
678 middle.destroy();
679 rootScope.digest();
680 expect(log).toEqual('13');
681 }));
682
683
684 it(r'should remove last', inject((RootScope rootScope) {
685 last.destroy();
686 rootScope.digest();
687 expect(log).toEqual('12');
688 }));
689
690
691 it(r'should broadcast the destroy event', inject((RootScope rootScope) {
692 var log = [];
693 first.on(ScopeEvent.DESTROY).listen((s) => log.add('first'));
694 var child = first.createChild({});
695 child.on(ScopeEvent.DESTROY).listen((s) => log.add('first-child'));
696
697 first.destroy();
698 expect(log).toEqual(['first', 'first-child']);
699 }));
700
701
702 it('should not call reaction function on destroyed scope', inject((RootScope rootScope, Logger log) {
703 rootScope.context['name'] = 'misko';
704 var child = rootScope.createChild(rootScope.context);
705 rootScope.watch('name', (v, _) {
706 log('root $v');
707 if (v == 'destroy') {
708 child.destroy();
709 }
710 });
711 rootScope.watch('name', (v, _) => log('root2 $v'));
712 child.watch('name', (v, _) => log('child $v'));
713 rootScope.apply();
714 expect(log).toEqual(['root misko', 'root2 misko', 'child misko']);
715 log.clear();
716
717 rootScope.context['name'] = 'destroy';
718 rootScope.apply();
719 expect(log).toEqual(['root destroy', 'root2 destroy']);
720 }));
721 });
722
723
724 describe('digest lifecycle', () {
725 it(r'should apply expression with full lifecycle', inject((RootScope rootSco pe) {
726 var log = '';
727 var child = rootScope.createChild({"parent": rootScope.context});
728 rootScope.watch('a', (a, _) { log += '1'; });
729 child.apply('parent.a = 0');
730 expect(log).toEqual('1');
731 }));
732
733
734 it(r'should catch exceptions', () {
735 module((Module module) => module.type(ExceptionHandler, implementedBy: Log gingExceptionHandler));
736 inject((RootScope rootScope, ExceptionHandler e) {
737 LoggingExceptionHandler exceptionHandler = e;
738 var log = [];
739 var child = rootScope.createChild({});
740 rootScope.watch('a', (a, _) => log.add('1'));
741 rootScope.context['a'] = 0;
742 child.apply(() { throw 'MyError'; });
743 expect(log.join(',')).toEqual('1');
744 expect(exceptionHandler.errors[0].error).toEqual('MyError');
745 exceptionHandler.errors.removeAt(0);
746 exceptionHandler.assertEmpty();
747 });
748 });
749
750
751 describe(r'exceptions', () {
752 var log;
753 beforeEach(module((Module module) {
754 return module.type(ExceptionHandler, implementedBy: LoggingExceptionHand ler);
755 }));
756 beforeEach(inject((RootScope rootScope) {
757 rootScope.context['log'] = () { log += 'digest;'; return null; };
758 log = '';
759 rootScope.watch('log()', (v, o) => null);
760 rootScope.digest();
761 log = '';
762 }));
763
764
765 it(r'should execute and return value and update', inject(
766 (RootScope rootScope, ExceptionHandler e) {
767 LoggingExceptionHandler exceptionHandler = e;
768 rootScope.context['name'] = 'abc';
769 expect(rootScope.apply((context) => context['name'])).toEqual('abc');
770 expect(log).toEqual('digest;digest;');
771 exceptionHandler.assertEmpty();
772 }));
773
774
775 it(r'should execute and return value and update', inject((RootScope rootSc ope) {
776 rootScope.context['name'] = 'abc';
777 expect(rootScope.apply('name', {'name': 123})).toEqual(123);
778 }));
779
780
781 it(r'should catch exception and update', inject((RootScope rootScope, Exce ptionHandler e) {
782 LoggingExceptionHandler exceptionHandler = e;
783 var error = 'MyError';
784 rootScope.apply(() { throw error; });
785 expect(log).toEqual('digest;digest;');
786 expect(exceptionHandler.errors[0].error).toEqual(error);
787 }));
788 });
789
790 it(r'should proprely reset phase on exception', inject((RootScope rootScope) {
791 var error = 'MyError';
792 expect(() => rootScope.apply(() { throw error; })).toThrow(error);
793 expect(() => rootScope.apply(() { throw error; })).toThrow(error);
794 }));
795 });
796
797
798 describe('flush lifecycle', () {
799 it(r'should apply expression with full lifecycle', inject((RootScope rootSco pe) {
800 var log = '';
801 var child = rootScope.createChild({"parent": rootScope.context});
802 rootScope.watch('a', (a, _) { log += '1'; }, readOnly: true);
803 child.apply('parent.a = 0');
804 expect(log).toEqual('1');
805 }));
806
807
808 it(r'should schedule domWrites and domReads', inject((RootScope rootScope) {
809 var log = '';
810 var child = rootScope.createChild({"parent": rootScope.context});
811 rootScope.watch('a', (a, _) { log += '1'; }, readOnly: true);
812 child.apply('parent.a = 0');
813 expect(log).toEqual('1');
814 }));
815
816
817 it(r'should catch exceptions', () {
818 module((Module module) => module.type(ExceptionHandler, implementedBy: Log gingExceptionHandler));
819 inject((RootScope rootScope, ExceptionHandler e) {
820 LoggingExceptionHandler exceptionHandler = e;
821 var log = [];
822 var child = rootScope.createChild({});
823 rootScope.watch('a', (a, _) => log.add('1'), readOnly: true);
824 rootScope.context['a'] = 0;
825 child.apply(() { throw 'MyError'; });
826 expect(log.join(',')).toEqual('1');
827 expect(exceptionHandler.errors[0].error).toEqual('MyError');
828 exceptionHandler.errors.removeAt(0);
829 exceptionHandler.assertEmpty();
830 });
831 });
832
833
834 describe(r'exceptions', () {
835 var log;
836 beforeEach(module((Module module) {
837 return module.type(ExceptionHandler, implementedBy: LoggingExceptionHand ler);
838 }));
839 beforeEach(inject((RootScope rootScope) {
840 rootScope.context['log'] = () { log += 'digest;'; return null; };
841 log = '';
842 rootScope.watch('log()', (v, o) => null, readOnly: true);
843 rootScope.digest();
844 log = '';
845 }));
846
847
848 it(r'should execute and return value and update', inject(
849 (RootScope rootScope, ExceptionHandler e) {
850 LoggingExceptionHandler exceptionHandler = e;
851 rootScope.context['name'] = 'abc';
852 expect(rootScope.apply((context) => context['name'])).toEqual('abc');
853 expect(log).toEqual('digest;digest;');
854 exceptionHandler.assertEmpty();
855 }));
856
857 it(r'should execute and return value and update', inject((RootScope rootSc ope) {
858 rootScope.context['name'] = 'abc';
859 expect(rootScope.apply('name', {'name': 123})).toEqual(123);
860 }));
861
862 it(r'should catch exception and update', inject((RootScope rootScope, Exce ptionHandler e) {
863 LoggingExceptionHandler exceptionHandler = e;
864 var error = 'MyError';
865 rootScope.apply(() { throw error; });
866 expect(log).toEqual('digest;digest;');
867 expect(exceptionHandler.errors[0].error).toEqual(error);
868 }));
869
870 it(r'should throw assertion when model changes in flush', inject((RootScop e rootScope, Logger log) {
871 var retValue = 1;
872 rootScope.context['logger'] = (name) { log(name); return retValue; };
873
874 rootScope.watch('logger("watch")', (n, v) => null);
875 rootScope.watch('logger("flush")', (n, v) => null, readOnly: true);
876
877 // clear watches
878 rootScope.digest();
879 log.clear();
880
881 rootScope.flush();
882 expect(log).toEqual(['flush', /*assertion*/ 'watch', 'flush']);
883
884 retValue = 2;
885 expect(rootScope.flush).
886 toThrow('Observer reaction functions should not change model. \n'
887 'These watch changes were detected: logger("watch"): 2 <= 1\n'
888 'These observe changes were detected: ');
889 }));
890 });
891
892 });
893
894
895 describe('ScopeLocals', () {
896 it('should read from locals', inject((RootScope scope) {
897 scope.context['a'] = 'XXX';
898 scope.context['c'] = 'C';
899 var scopeLocal = new ScopeLocals(scope.context, {'a': 'A', 'b': 'B'});
900 expect(scopeLocal['a']).toEqual('A');
901 expect(scopeLocal['b']).toEqual('B');
902 expect(scopeLocal['c']).toEqual('C');
903 }));
904
905 it('should write to Scope', inject((RootScope scope) {
906 scope.context['a'] = 'XXX';
907 scope.context['c'] = 'C';
908 var scopeLocal = new ScopeLocals(scope.context, {'a': 'A', 'b': 'B'});
909
910 scopeLocal['a'] = 'aW';
911 scopeLocal['b'] = 'bW';
912 scopeLocal['c'] = 'cW';
913
914 expect(scope.context['a']).toEqual('aW');
915 expect(scope.context['b']).toEqual('bW');
916 expect(scope.context['c']).toEqual('cW');
917
918 expect(scopeLocal['a']).toEqual('A');
919 expect(scopeLocal['b']).toEqual('B');
920 expect(scopeLocal['c']).toEqual('cW');
921 }));
922 });
923
924
925 describe(r'watch/digest', () {
926 it(r'should watch and fire on simple property change', inject((RootScope roo tScope) {
927 var log;
928
929 rootScope.watch('name', (a, b) {
930 log = [a, b];
931 });
932 rootScope.digest();
933 log = null;
934
935 expect(log).toEqual(null);
936 rootScope.digest();
937 expect(log).toEqual(null);
938 rootScope.context['name'] = 'misko';
939 rootScope.digest();
940 expect(log).toEqual(['misko', null]);
941 }));
942
943
944 it('should watch/observe on objects other then contex', inject((RootScope ro otScope) {
945 var log = '';
946 var map = {'a': 'A', 'b': 'B'};
947 rootScope.watch('a', (a, b) => log += a, context: map);
948 rootScope.watch('b', (a, b) => log += a, context: map);
949 rootScope.apply();
950 expect(log).toEqual('AB');
951 }));
952
953
954 it(r'should watch and fire on expression change', inject((RootScope rootScop e) {
955 var log;
956
957 rootScope.watch('name.first', (a, b) => log = [a, b]);
958 rootScope.digest();
959 log = null;
960
961 rootScope.context['name'] = {};
962 expect(log).toEqual(null);
963 rootScope.digest();
964 expect(log).toEqual(null);
965 rootScope.context['name']['first'] = 'misko';
966 rootScope.digest();
967 expect(log).toEqual(['misko', null]);
968 }));
969
970
971 it(r'should delegate exceptions', () {
972 module((Module module) {
973 module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler);
974 });
975 inject((RootScope rootScope, ExceptionHandler e) {
976 LoggingExceptionHandler exceptionHandler = e;
977 rootScope.watch('a', (n, o) {throw 'abc';});
978 rootScope.context['a'] = 1;
979 rootScope.digest();
980 expect(exceptionHandler.errors.length).toEqual(1);
981 expect(exceptionHandler.errors[0].error).toEqual('abc');
982 });
983 });
984
985
986 it(r'should fire watches in order of addition', inject((RootScope rootScope) {
987 // this is not an external guarantee, just our own sanity
988 var log = '';
989 rootScope.watch('a', (a, b) { log += 'a'; });
990 rootScope.watch('b', (a, b) { log += 'b'; });
991 rootScope.watch('c', (a, b) { log += 'c'; });
992 rootScope.context['a'] = rootScope.context['b'] = rootScope.context['c'] = 1;
993 rootScope.digest();
994 expect(log).toEqual('abc');
995 }));
996
997
998 it(r'should call child watchers in addition order', inject((RootScope rootSc ope) {
999 // this is not an external guarantee, just our own sanity
1000 var log = '';
1001 var childA = rootScope.createChild({});
1002 var childB = rootScope.createChild({});
1003 var childC = rootScope.createChild({});
1004 childA.watch('a', (a, b) { log += 'a'; });
1005 childB.watch('b', (a, b) { log += 'b'; });
1006 childC.watch('c', (a, b) { log += 'c'; });
1007 childA.context['a'] = childB.context['b'] = childC.context['c'] = 1;
1008 rootScope.digest();
1009 expect(log).toEqual('abc');
1010 }));
1011
1012
1013 it(r'should run digest multiple times', inject(
1014 (RootScope rootScope) {
1015 // tests a traversal edge case which we originally missed
1016 var log = [];
1017 var childA = rootScope.createChild({'log': log});
1018 var childB = rootScope.createChild({'log': log});
1019
1020 rootScope.context['log'] = log;
1021
1022 rootScope.watch("log.add('r')", (_, __) => null);
1023 childA.watch("log.add('a')", (_, __) => null);
1024 childB.watch("log.add('b')", (_, __) => null);
1025
1026 // init
1027 rootScope.digest();
1028 expect(log.join('')).toEqual('rabrab');
1029 }));
1030
1031
1032 it(r'should repeat watch cycle while model changes are identified', inject(( RootScope rootScope) {
1033 var log = '';
1034 rootScope.watch('c', (v, b) {rootScope.context['d'] = v; log+='c'; });
1035 rootScope.watch('b', (v, b) {rootScope.context['c'] = v; log+='b'; });
1036 rootScope.watch('a', (v, b) {rootScope.context['b'] = v; log+='a'; });
1037 rootScope.digest();
1038 log = '';
1039 rootScope.context['a'] = 1;
1040 rootScope.digest();
1041 expect(rootScope.context['b']).toEqual(1);
1042 expect(rootScope.context['c']).toEqual(1);
1043 expect(rootScope.context['d']).toEqual(1);
1044 expect(log).toEqual('abc');
1045 }));
1046
1047
1048 it(r'should repeat watch cycle from the root element', inject((RootScope roo tScope) {
1049 var log = [];
1050 rootScope.context['log'] = log;
1051 var child = rootScope.createChild({'log':log});
1052 rootScope.watch("log.add('a')", (_, __) => null);
1053 child.watch("log.add('b')", (_, __) => null);
1054 rootScope.digest();
1055 expect(log.join('')).toEqual('abab');
1056 }));
1057
1058
1059 it(r'should not fire upon watch registration on initial digest', inject((Roo tScope rootScope) {
1060 var log = '';
1061 rootScope.context['a'] = 1;
1062 rootScope.watch('a', (a, b) { log += 'a'; });
1063 rootScope.watch('b', (a, b) { log += 'b'; });
1064 rootScope.digest();
1065 log = '';
1066 rootScope.digest();
1067 expect(log).toEqual('');
1068 }));
1069
1070
1071 it(r'should prevent digest recursion', inject((RootScope rootScope) {
1072 var callCount = 0;
1073 rootScope.watch('name', (a, b) {
1074 expect(() {
1075 rootScope.digest();
1076 }).toThrow(r'digest already in progress');
1077 callCount++;
1078 });
1079 rootScope.context['name'] = 'a';
1080 rootScope.digest();
1081 expect(callCount).toEqual(1);
1082 }));
1083
1084
1085 it(r'should return a function that allows listeners to be unregistered', inj ect(
1086 (RootScope rootScope) {
1087 var listener = jasmine.createSpy('watch listener');
1088 var watch;
1089
1090 watch = rootScope.watch('foo', listener);
1091 rootScope.digest(); //init
1092 expect(listener).toHaveBeenCalled();
1093 expect(watch).toBeDefined();
1094
1095 listener.reset();
1096 rootScope.context['foo'] = 'bar';
1097 rootScope.digest(); //triger
1098 expect(listener).toHaveBeenCalledOnce();
1099
1100 listener.reset();
1101 rootScope.context['foo'] = 'baz';
1102 watch.remove();
1103 rootScope.digest(); //trigger
1104 expect(listener).not.toHaveBeenCalled();
1105 }));
1106
1107
1108 it(r'should not infinitely digest when current value is NaN', inject((RootSc ope rootScope) {
1109 rootScope.context['nan'] = double.NAN;
1110 rootScope.watch('nan', (_, __) => null);
1111
1112 expect(() {
1113 rootScope.digest();
1114 }).not.toThrow();
1115 }));
1116
1117
1118 it(r'should prevent infinite digest and should log firing expressions', inje ct((RootScope rootScope) {
1119 rootScope.context['a'] = 0;
1120 rootScope.context['b'] = 0;
1121 rootScope.watch('a', (a, __) => rootScope.context['a'] = a + 1);
1122 rootScope.watch('b', (b, __) => rootScope.context['b'] = b + 1);
1123
1124 expect(() {
1125 rootScope.digest();
1126 }).toThrow('Model did not stabilize in 5 digests. '
1127 'Last 3 iterations:\n'
1128 'a: 2 <= 1, b: 2 <= 1\n'
1129 'a: 3 <= 2, b: 3 <= 2\n'
1130 'a: 4 <= 3, b: 4 <= 3');
1131 }));
1132
1133
1134 it(r'should always call the watchr with newVal and oldVal equal on the first run',
1135 inject((RootScope rootScope) {
1136 var log = [];
1137 var logger = (newVal, oldVal) {
1138 var val = (newVal == oldVal || (newVal != oldVal && oldVal != newVal)) ? newVal : 'xxx';
1139 log.add(val);
1140 };
1141
1142 rootScope.context['nanValue'] = double.NAN;
1143 rootScope.context['nullValue'] = null;
1144 rootScope.context['emptyString'] = '';
1145 rootScope.context['falseValue'] = false;
1146 rootScope.context['numberValue'] = 23;
1147
1148 rootScope.watch('nanValue', logger);
1149 rootScope.watch('nullValue', logger);
1150 rootScope.watch('emptyString', logger);
1151 rootScope.watch('falseValue', logger);
1152 rootScope.watch('numberValue', logger);
1153
1154 rootScope.digest();
1155 expect(log.removeAt(0).isNaN).toEqual(true); //jasmine's toBe and toEqual don't work well with NaNs
1156 expect(log).toEqual([null, '', false, 23]);
1157 log = [];
1158 rootScope.digest();
1159 expect(log).toEqual([]);
1160 }));
1161
1162
1163 it('should properly watch canstants', inject((RootScope rootScope, Logger lo g) {
1164 rootScope.watch('[1, 2]', (v, o) => log([v, o]));
1165 expect(log).toEqual([]);
1166 rootScope.apply();
1167 expect(log).toEqual([[[1, 2], null]]);
1168 }));
1169
1170
1171 it('should properly watch array of fields', inject((RootScope rootScope, Log ger log) {
1172 rootScope.context['foo'] = 12;
1173 rootScope.context['bar'] = 34;
1174 rootScope.watch('[foo, bar]', (v, o) => log([v, o]));
1175 expect(log).toEqual([]);
1176 rootScope.apply();
1177 expect(log).toEqual([[[12, 34], null]]);
1178 log.clear();
1179
1180 rootScope.context['foo'] = 56;
1181 rootScope.context['bar'] = 78;
1182 rootScope.apply();
1183 expect(log).toEqual([[[56, 78], [12, 34]]]);
1184 }));
1185
1186
1187 it('should properly watch array of fields2', inject((RootScope rootScope, Lo gger log) {
1188 rootScope.watch('[ctrl.foo, ctrl.bar]', (v, o) => log([v, o]));
1189 expect(log).toEqual([]);
1190 rootScope.apply();
1191 expect(log).toEqual([[[null, null], null]]);
1192 log.clear();
1193
1194 rootScope.context['ctrl'] = {'foo': 56, 'bar': 78};
1195 rootScope.apply();
1196 expect(log).toEqual([[[56, 78], [null, null]]]);
1197 }));
1198 });
1199
1200
1201 describe('special binding modes', () {
1202 it('should bind one time', inject((RootScope rootScope, Logger log) {
1203 rootScope.watch('foo', (v, _) => log('foo:$v'));
1204 rootScope.watch(':foo', (v, _) => log(':foo:$v'));
1205 rootScope.watch('::foo', (v, _) => log('::foo:$v'));
1206
1207 rootScope.apply();
1208 expect(log).toEqual(['foo:null']);
1209 log.clear();
1210
1211 rootScope.context['foo'] = true;
1212 rootScope.apply();
1213 expect(log).toEqual(['foo:true', ':foo:true', '::foo:true']);
1214 log.clear();
1215
1216 rootScope.context['foo'] = 123;
1217 rootScope.apply();
1218 expect(log).toEqual(['foo:123', ':foo:123']);
1219 log.clear();
1220
1221 rootScope.context['foo'] = null;
1222 rootScope.apply();
1223 expect(log).toEqual(['foo:null']);
1224 log.clear();
1225 }));
1226 });
1227
1228
1229 describe('runAsync', () {
1230 it(r'should run callback before watch', inject((RootScope rootScope) {
1231 var log = '';
1232 rootScope.runAsync(() { log += 'parent.async;'; });
1233 rootScope.watch('value', (_, __) { log += 'parent.digest;'; });
1234 rootScope.digest();
1235 expect(log).toEqual('parent.async;parent.digest;');
1236 }));
1237
1238 it(r'should cause a digest rerun', inject((RootScope rootScope) {
1239 rootScope.context['log'] = '';
1240 rootScope.context['value'] = 0;
1241 // NOTE(deboer): watch listener string functions not yet supported
1242 //rootScope.watch('value', 'log = log + ".";');
1243 rootScope.watch('value', (_, __) { rootScope.context['log'] += "."; });
1244 rootScope.watch('init', (_, __) {
1245 rootScope.runAsync(() => rootScope.eval('value = 123; log = log + "=" ') );
1246 expect(rootScope.context['value']).toEqual(0);
1247 });
1248 rootScope.digest();
1249 expect(rootScope.context['log']).toEqual('.=.');
1250 }));
1251
1252 it(r'should run async in the same order as added', inject((RootScope rootSco pe) {
1253 rootScope.context['log'] = '';
1254 rootScope.runAsync(() => rootScope.eval("log = log + 1"));
1255 rootScope.runAsync(() => rootScope.eval("log = log + 2"));
1256 rootScope.digest();
1257 expect(rootScope.context['log']).toEqual('12');
1258 }));
1259 });
1260
1261
1262 describe('domRead/domWrite', () {
1263 it(r'should run writes before reads', () {
1264 module((Module module) {
1265 module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler);
1266 });
1267 inject((RootScope rootScope, Logger logger, ExceptionHandler e) {
1268 LoggingExceptionHandler exceptionHandler = e as LoggingExceptionHandler;
1269 rootScope.domWrite(() {
1270 logger('write1');
1271 rootScope.domWrite(() => logger('write2'));
1272 throw 'write1';
1273 });
1274 rootScope.domRead(() {
1275 logger('read1');
1276 rootScope.domRead(() => logger('read2'));
1277 rootScope.domWrite(() => logger('write3'));
1278 throw 'read1';
1279 });
1280 rootScope.watch('value', (_, __) => logger('observe'), readOnly: true);
1281 rootScope.flush();
1282 expect(logger).toEqual(['write1', 'write2', 'observe', 'read1', 'read2', 'write3']);
1283 expect(exceptionHandler.errors.length).toEqual(2);
1284 expect(exceptionHandler.errors[0].error).toEqual('write1');
1285 expect(exceptionHandler.errors[1].error).toEqual('read1');
1286 });
1287 });
1288 });
1289
1290 describe('exceptionHander', () {
1291 it('should call ExceptionHandler on zone errors', () {
1292 module((Module module) {
1293 module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler);
1294 });
1295 async((inject((RootScope rootScope, NgZone zone, ExceptionHandler e) {
1296 zone.run(() {
1297 scheduleMicrotask(() => throw 'my error');
1298 });
1299 var errors = (e as LoggingExceptionHandler).errors;
1300 expect(errors.length).toEqual(1);
1301 expect(errors.first.error).toEqual('my error');
1302 })));
1303 });
1304
1305 it('should call ExceptionHandler on digest errors', () {
1306 module((Module module) {
1307 module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler);
1308 });
1309 async((inject((RootScope rootScope, NgZone zone, ExceptionHandler e) {
1310 rootScope.context['badOne'] = () => new Map();
1311 rootScope.watch('badOne()', (_, __) => null);
1312
1313 try {
1314 zone.run(() => null);
1315 } catch(_) {}
1316
1317 var errors = (e as LoggingExceptionHandler).errors;
1318 expect(errors.length).toEqual(1);
1319 expect(errors.first.error, startsWith('Model did not stabilize'));
1320 })));
1321 });
1322 });
1323 });
1324
1325 @NgFilter(name: 'multiply')
1326 class _MultiplyFilter {
1327 call(a, b) => a * b;
1328 }
1329
1330 @NgFilter(name: 'listHead')
1331 class _ListHeadFilter {
1332 Logger logger;
1333 _ListHeadFilter(Logger this.logger);
1334 call(list, head) {
1335 logger('listHead');
1336 return [head]..addAll(list);
1337 }
1338 }
1339
1340
1341 @NgFilter(name: 'listTail')
1342 class _ListTailFilter {
1343 Logger logger;
1344 _ListTailFilter(Logger this.logger);
1345 call(list, tail) {
1346 logger('listTail');
1347 return new List.from(list)..add(tail);
1348 }
1349 }
1350
1351 @NgFilter(name: 'sort')
1352 class _SortFilter {
1353 Logger logger;
1354 _SortFilter(Logger this.logger);
1355 call(list) {
1356 logger('sort');
1357 return new List.from(list)..sort();
1358 }
1359 }
1360
1361 @NgFilter(name:'newFilter')
1362 class FilterOne {
1363 call(String str) {
1364 return '$str 1';
1365 }
1366 }
1367
1368 @NgFilter(name:'newFilter')
1369 class FilterTwo {
1370 call(String str) {
1371 return '$str 2';
1372 }
1373 }
OLDNEW
« no previous file with comments | « third_party/pkg/angular/test/core/registry_spec.dart ('k') | third_party/pkg/angular/test/core/templateurl_spec.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698