Index: third_party/pkg/angular/test/core/scope_spec.dart |
diff --git a/third_party/pkg/angular/test/core/scope_spec.dart b/third_party/pkg/angular/test/core/scope_spec.dart |
index 20a70b113c68e1ff513dc02c023ba3e761e30a14..c0db2d4f43c4c1c09b5609d3bb9cd44362bd0366 100644 |
--- a/third_party/pkg/angular/test/core/scope_spec.dart |
+++ b/third_party/pkg/angular/test/core/scope_spec.dart |
@@ -6,1265 +6,1437 @@ import 'package:angular/change_detection/dirty_checking_change_detector.dart'; |
import 'dart:async'; |
import 'dart:math'; |
-main() => describe('scope', () { |
- beforeEach(module((Module module) { |
- Map context = {}; |
- module.value(GetterCache, new GetterCache({})); |
- module.type(ChangeDetector, implementedBy: DirtyCheckingChangeDetector); |
- module.value(Object, context); |
- module.value(Map, context); |
- module.type(RootScope); |
- module.type(_MultiplyFilter); |
- module.type(_ListHeadFilter); |
- module.type(_ListTailFilter); |
- module.type(_SortFilter); |
- })); |
- |
- describe('AST Bridge', () { |
- it('should watch field', inject((Logger logger, Map context, RootScope rootScope) { |
- context['field'] = 'Worked!'; |
- rootScope.watch('field', (value, previous) => logger([value, previous])); |
- expect(logger).toEqual([]); |
- rootScope.digest(); |
- expect(logger).toEqual([['Worked!', null]]); |
- rootScope.digest(); |
- expect(logger).toEqual([['Worked!', null]]); |
- })); |
- |
- it('should watch field path', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = {'b': 'AB'}; |
- rootScope.watch('a.b', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual(['AB']); |
- context['a']['b'] = '123'; |
- rootScope.digest(); |
- expect(logger).toEqual(['AB', '123']); |
- context['a'] = {'b': 'XYZ'}; |
- rootScope.digest(); |
- expect(logger).toEqual(['AB', '123', 'XYZ']); |
- })); |
- |
- it('should watch math operations', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = 1; |
- context['b'] = 2; |
- rootScope.watch('a + b + 1', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([4]); |
- context['a'] = 3; |
- rootScope.digest(); |
- expect(logger).toEqual([4, 6]); |
- context['b'] = 5; |
- rootScope.digest(); |
- expect(logger).toEqual([4, 6, 9]); |
- })); |
- |
- |
- it('should watch literals', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = 1; |
- rootScope.watch('1', (value, previous) => logger(value)); |
- rootScope.watch('"str"', (value, previous) => logger(value)); |
- rootScope.watch('[a, 2, 3]', (value, previous) => logger(value)); |
- rootScope.watch('{a:a, b:2}', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([1, 'str', [1, 2, 3], {'a': 1, 'b': 2}]); |
- logger.clear(); |
- context['a'] = 3; |
- rootScope.digest(); |
- expect(logger).toEqual([[3, 2, 3], {'a': 3, 'b': 2}]); |
- })); |
- |
- it('should invoke closures', inject((Logger logger, Map context, RootScope rootScope) { |
- context['fn'] = () { |
- logger('fn'); |
- return 1; |
- }; |
- context['a'] = {'fn': () { |
- logger('a.fn'); |
- return 2; |
- }}; |
- rootScope.watch('fn()', (value, previous) => logger('=> $value')); |
- rootScope.watch('a.fn()', (value, previous) => logger('-> $value')); |
- rootScope.digest(); |
- expect(logger).toEqual(['fn', 'a.fn', '=> 1', '-> 2', |
- /* second loop*/ 'fn', 'a.fn']); |
- logger.clear(); |
- rootScope.digest(); |
- expect(logger).toEqual(['fn', 'a.fn']); |
- })); |
- |
- it('should perform conditionals', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = 1; |
- context['b'] = 2; |
- context['c'] = 3; |
- rootScope.watch('a?b:c', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([2]); |
- logger.clear(); |
- context['a'] = 0; |
- rootScope.digest(); |
- expect(logger).toEqual([3]); |
- })); |
- |
- |
- xit('should call function', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = () { |
- return () { return 123; }; |
- }; |
- rootScope.watch('a()()', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([123]); |
- logger.clear(); |
- rootScope.digest(); |
- expect(logger).toEqual([]); |
- })); |
- |
- it('should access bracket', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = {'b': 123}; |
- rootScope.watch('a["b"]', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([123]); |
- logger.clear(); |
- rootScope.digest(); |
- expect(logger).toEqual([]); |
- })); |
- |
- |
- it('should prefix', inject((Logger logger, Map context, RootScope rootScope) { |
- context['a'] = true; |
- rootScope.watch('!a', (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([false]); |
- logger.clear(); |
- context['a'] = false; |
- rootScope.digest(); |
- expect(logger).toEqual([true]); |
- })); |
- |
- it('should support filters', inject((Logger logger, Map context, |
- RootScope rootScope, AstParser parser, |
- FilterMap filters) { |
- context['a'] = 123; |
- context['b'] = 2; |
- rootScope.watch( |
- parser('a | multiply:b', filters: filters), |
- (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual([246]); |
- logger.clear(); |
- rootScope.digest(); |
- expect(logger).toEqual([]); |
- logger.clear(); |
- })); |
- |
- it('should support arrays in filters', inject((Logger logger, Map context, |
- RootScope rootScope, |
- AstParser parser, |
- FilterMap filters) { |
- context['a'] = [1]; |
- rootScope.watch( |
- parser('a | sort | listHead:"A" | listTail:"B"', filters: filters), |
- (value, previous) => logger(value)); |
- rootScope.digest(); |
- expect(logger).toEqual(['sort', 'listHead', 'listTail', ['A', 1, 'B']]); |
- logger.clear(); |
- |
- rootScope.digest(); |
- expect(logger).toEqual([]); |
- logger.clear(); |
- |
- context['a'].add(2); |
- rootScope.digest(); |
- expect(logger).toEqual(['sort', 'listHead', 'listTail', ['A', 1, 2, 'B']]); |
- logger.clear(); |
- |
- // We change the order, but sort should change it to same one and it should not |
- // call subsequent filters. |
- context['a'] = [2, 1]; |
- rootScope.digest(); |
- expect(logger).toEqual(['sort']); |
- logger.clear(); |
- })); |
- }); |
+void main() { |
+ describe('scope', () { |
+ beforeEachModule((Module module) { |
+ Map context = {}; |
+ module |
+ ..type(ChangeDetector, implementedBy: DirtyCheckingChangeDetector) |
+ ..value(Object, context) |
+ ..value(Map, context) |
+ ..type(RootScope) |
+ ..type(_MultiplyFilter) |
+ ..type(_ListHeadFilter) |
+ ..type(_ListTailFilter) |
+ ..type(_SortFilter) |
+ ..type(_IdentityFilter) |
+ ..type(_MapKeys) |
+ ..type(ScopeStatsEmitter, implementedBy: MockScopeStatsEmitter); |
+ }); |
+ describe('AST Bridge', () { |
+ it('should watch field', (Logger logger, Map context, RootScope rootScope) { |
+ context['field'] = 'Worked!'; |
+ rootScope.watch('field', (value, previous) => logger([value, previous])); |
+ expect(logger).toEqual([]); |
+ rootScope.digest(); |
+ expect(logger).toEqual([['Worked!', null]]); |
+ rootScope.digest(); |
+ expect(logger).toEqual([['Worked!', null]]); |
+ }); |
- describe('properties', () { |
- describe('root', () { |
- it('should point to itself', inject((RootScope rootScope) { |
- expect(rootScope.rootScope).toEqual(rootScope); |
- })); |
+ it('should watch field path', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = {'b': 'AB'}; |
+ rootScope.watch('a.b', (value, previous) => logger(value)); |
+ rootScope.digest(); |
+ expect(logger).toEqual(['AB']); |
+ context['a']['b'] = '123'; |
+ rootScope.digest(); |
+ expect(logger).toEqual(['AB', '123']); |
+ context['a'] = {'b': 'XYZ'}; |
+ rootScope.digest(); |
+ expect(logger).toEqual(['AB', '123', 'XYZ']); |
+ }); |
+ |
+ it('should watch math operations', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = 1; |
+ context['b'] = 2; |
+ rootScope.watch('a + b + 1', (value, previous) => logger(value)); |
+ rootScope.digest(); |
+ expect(logger).toEqual([4]); |
+ context['a'] = 3; |
+ rootScope.digest(); |
+ expect(logger).toEqual([4, 6]); |
+ context['b'] = 5; |
+ rootScope.digest(); |
+ expect(logger).toEqual([4, 6, 9]); |
+ }); |
+ |
+ |
+ it('should watch literals', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = 1; |
+ rootScope |
+ ..watch('', (value, previous) => logger(value)) |
+ ..watch('""', (value, previous) => logger(value)) |
+ ..watch('1', (value, previous) => logger(value)) |
+ ..watch('"str"', (value, previous) => logger(value)) |
+ ..watch('[a, 2, 3]', (value, previous) => logger(value)) |
+ ..watch('{a:a, b:2}', (value, previous) => logger(value)) |
+ ..digest(); |
+ expect(logger).toEqual(['', '', 1, 'str', [1, 2, 3], {'a': 1, 'b': 2}]); |
+ logger.clear(); |
+ context['a'] = 3; |
+ rootScope.digest(); |
+ expect(logger).toEqual([[3, 2, 3], {'a': 3, 'b': 2}]); |
+ }); |
+ |
+ it('should watch nulls', (Logger logger, Map context, RootScope rootScope) { |
+ var r = (value, _) => logger(value); |
+ rootScope |
+ ..watch('null < 0',r) |
+ ..watch('null * 3', r) |
+ ..watch('null + 6', r) |
+ ..watch('5 + null', r) |
+ ..watch('null - 4', r) |
+ ..watch('3 - null', r) |
+ ..watch('null + null', r) |
+ ..watch('null - null', r) |
+ ..watch('null == null', r) |
+ ..watch('null != null', r) |
+ ..digest(); |
+ expect(logger).toEqual([null, null, 6, 5, -4, 3, 0, 0, true, false]); |
+ }); |
+ |
+ it('should invoke closures', (Logger logger, Map context, RootScope rootScope) { |
+ context['fn'] = () { |
+ logger('fn'); |
+ return 1; |
+ }; |
+ context['a'] = {'fn': () { |
+ logger('a.fn'); |
+ return 2; |
+ }}; |
+ rootScope.watch('fn()', (value, previous) => logger('=> $value')); |
+ rootScope.watch('a.fn()', (value, previous) => logger('-> $value')); |
+ rootScope.digest(); |
+ expect(logger).toEqual(['fn', 'a.fn', '=> 1', '-> 2', |
+ /* second loop*/ 'fn', 'a.fn']); |
+ logger.clear(); |
+ rootScope.digest(); |
+ expect(logger).toEqual(['fn', 'a.fn']); |
+ }); |
+ |
+ it('should perform conditionals', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = 1; |
+ context['b'] = 2; |
+ context['c'] = 3; |
+ rootScope.watch('a?b:c', (value, previous) => logger(value)); |
+ rootScope.digest(); |
+ expect(logger).toEqual([2]); |
+ logger.clear(); |
+ context['a'] = 0; |
+ rootScope.digest(); |
+ expect(logger).toEqual([3]); |
+ }); |
+ |
+ |
+ xit('should call function', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = () { |
+ return () { return 123; }; |
+ }; |
+ rootScope.watch('a()()', (value, previous) => logger(value)); |
+ rootScope.digest(); |
+ expect(logger).toEqual([123]); |
+ logger.clear(); |
+ rootScope.digest(); |
+ expect(logger).toEqual([]); |
+ }); |
+ |
+ it('should access bracket', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = {'b': 123}; |
+ rootScope.watch('a["b"]', (value, previous) => logger(value)); |
+ rootScope.digest(); |
+ expect(logger).toEqual([123]); |
+ logger.clear(); |
+ rootScope.digest(); |
+ expect(logger).toEqual([]); |
+ logger.clear(); |
+ |
+ context['a']['b'] = 234; |
+ rootScope.digest(); |
+ expect(logger).toEqual([234]); |
+ }); |
+ |
+ |
+ it('should prefix', (Logger logger, Map context, RootScope rootScope) { |
+ context['a'] = true; |
+ rootScope.watch('!a', (value, previous) => logger(value)); |
+ rootScope.digest(); |
+ expect(logger).toEqual([false]); |
+ logger.clear(); |
+ context['a'] = false; |
+ rootScope.digest(); |
+ expect(logger).toEqual([true]); |
+ }); |
+ |
+ it('should support formatters', (Logger logger, Map context, |
+ RootScope rootScope, FormatterMap formatters) { |
+ context['a'] = 123; |
+ context['b'] = 2; |
+ rootScope.watch('a | multiply:b', (value, previous) => logger(value), |
+ formatters: formatters); |
+ rootScope.digest(); |
+ expect(logger).toEqual([246]); |
+ logger.clear(); |
+ rootScope.digest(); |
+ expect(logger).toEqual([]); |
+ logger.clear(); |
+ }); |
+ |
+ it('should support arrays in formatters', (Logger logger, Map context, |
+ RootScope rootScope, FormatterMap formatters) { |
+ context['a'] = [1]; |
+ rootScope.watch('a | sort | listHead:"A" | listTail:"B"', |
+ (value, previous) => logger(value), formatters: formatters); |
+ rootScope.digest(); |
+ expect(logger).toEqual(['sort', 'listHead', 'listTail', ['A', 1, 'B']]); |
+ logger.clear(); |
+ |
+ rootScope.digest(); |
+ expect(logger).toEqual([]); |
+ logger.clear(); |
+ |
+ context['a'].add(2); |
+ rootScope.digest(); |
+ expect(logger).toEqual(['sort', 'listHead', 'listTail', ['A', 1, 2, 'B']]); |
+ logger.clear(); |
+ |
+ // We change the order, but sort should change it to same one and it should not |
+ // call subsequent formatters. |
+ context['a'] = [2, 1]; |
+ rootScope.digest(); |
+ expect(logger).toEqual(['sort']); |
+ logger.clear(); |
+ }); |
+ |
+ it('should support maps in formatters', (Logger logger, Map context, |
+ RootScope rootScope, FormatterMap formatters) { |
+ context['a'] = {'foo': 'bar'}; |
+ rootScope.watch('a | identity | keys', |
+ (value, previous) => logger(value), formatters: formatters); |
+ rootScope.digest(); |
+ expect(logger).toEqual(['identity', 'keys', ['foo']]); |
+ logger.clear(); |
+ |
+ rootScope.digest(); |
+ expect(logger).toEqual([]); |
+ logger.clear(); |
+ |
+ context['a']['bar'] = 'baz'; |
+ rootScope.digest(); |
+ expect(logger).toEqual(['identity', 'keys', ['foo', 'bar']]); |
+ logger.clear(); |
+ }); |
- it('children should point to root', inject((RootScope rootScope) { |
- var child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
- expect(child.rootScope).toEqual(rootScope); |
- expect(child.createChild(new PrototypeMap(rootScope.context)).rootScope).toEqual(rootScope); |
- })); |
}); |
- describe('parent', () { |
- it('should not have parent', inject((RootScope rootScope) { |
- expect(rootScope.parentScope).toEqual(null); |
- })); |
+ describe('properties', () { |
+ describe('root', () { |
+ it('should point to itself', (RootScope rootScope) { |
+ expect(rootScope.rootScope).toEqual(rootScope); |
+ }); |
+ it('children should point to root', (RootScope rootScope) { |
+ var child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
+ expect(child.rootScope).toEqual(rootScope); |
+ expect(child.createChild(new PrototypeMap(rootScope.context)).rootScope).toEqual(rootScope); |
+ }); |
+ }); |
- it('should point to parent', inject((RootScope rootScope) { |
- var child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
- expect(rootScope.parentScope).toEqual(null); |
- expect(child.parentScope).toEqual(rootScope); |
- expect(child.createChild(new PrototypeMap(rootScope.context)).parentScope).toEqual(child); |
- })); |
+ |
+ describe('parent', () { |
+ it('should not have parent', (RootScope rootScope) { |
+ expect(rootScope.parentScope).toEqual(null); |
+ expect(rootScope.id).toEqual(''); |
+ }); |
+ |
+ |
+ it('should point to parent', (RootScope rootScope) { |
+ var child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
+ expect(child.id).toEqual(':0'); |
+ expect(rootScope.parentScope).toEqual(null); |
+ expect(child.parentScope).toEqual(rootScope); |
+ expect(child.createChild(new PrototypeMap(rootScope.context)).parentScope).toEqual(child); |
+ }); |
+ }); |
}); |
- }); |
- describe(r'events', () { |
+ describe(r'events', () { |
- describe('on', () { |
- it('should allow emit/broadcast when no listeners', inject((RootScope scope) { |
- scope.emit('foo'); |
- scope.broadcast('foo'); |
- })); |
+ describe('on', () { |
+ it('should allow emit/broadcast when no listeners', (RootScope scope) { |
+ scope.emit('foo'); |
+ scope.broadcast('foo'); |
+ }); |
- it(r'should add listener for both emit and broadcast events', inject((RootScope rootScope) { |
- var log = '', |
- child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
+ it(r'should add listener for both emit and broadcast events', (RootScope rootScope) { |
+ var log = '', |
+ child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
- eventFn(event) { |
- expect(event).not.toEqual(null); |
- log += 'X'; |
- } |
+ eventFn(event) { |
+ expect(event).not.toEqual(null); |
+ log += 'X'; |
+ } |
- child.on('abc').listen(eventFn); |
- expect(log).toEqual(''); |
+ child.on('abc').listen(eventFn); |
+ expect(log).toEqual(''); |
- child.emit('abc'); |
- expect(log).toEqual('X'); |
+ child.emit('abc'); |
+ expect(log).toEqual('X'); |
- child.broadcast('abc'); |
- expect(log).toEqual('XX'); |
- })); |
+ child.broadcast('abc'); |
+ expect(log).toEqual('XX'); |
+ }); |
- it(r'should return a function that deregisters the listener', inject((RootScope rootScope) { |
- var log = ''; |
- var child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
- var subscription; |
+ it(r'should return a function that deregisters the listener', (RootScope rootScope) { |
+ var log = ''; |
+ var child = rootScope.createChild(new PrototypeMap(rootScope.context)); |
+ var subscription; |
- eventFn(e) { |
- log += 'X'; |
- } |
+ eventFn(e) { |
+ log += 'X'; |
+ } |
- subscription = child.on('abc').listen(eventFn); |
- expect(log).toEqual(''); |
- expect(subscription).toBeDefined(); |
+ subscription = child.on('abc').listen(eventFn); |
+ expect(log).toEqual(''); |
+ expect(subscription).toBeDefined(); |
- child.emit(r'abc'); |
- child.broadcast('abc'); |
- expect(log).toEqual('XX'); |
+ child.emit(r'abc'); |
+ child.broadcast('abc'); |
+ expect(log).toEqual('XX'); |
- log = ''; |
- expect(subscription.cancel()).toBe(null); |
- child.emit(r'abc'); |
- child.broadcast('abc'); |
- expect(log).toEqual(''); |
- })); |
+ log = ''; |
+ expect(subscription.cancel()).toBe(null); |
+ child.emit(r'abc'); |
+ child.broadcast('abc'); |
+ expect(log).toEqual(''); |
+ }); |
- it('should not trigger assertions on scope fork', inject((RootScope root) { |
- var d1 = root.createChild({}); |
- var d2 = root.createChild({}); |
- var d3 = d2.createChild({}); |
- expect(root.apply).not.toThrow(); |
- d1.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(root.apply).not.toThrow(); |
- d3.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(root.apply).not.toThrow(); |
- d2.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(root.apply).not.toThrow(); |
- })); |
+ it('should not trigger assertions on scope fork', (RootScope root) { |
+ var d1 = root.createChild({}); |
+ var d2 = root.createChild({}); |
+ var d3 = d2.createChild({}); |
+ expect(root.apply).not.toThrow(); |
+ d1.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(root.apply).not.toThrow(); |
+ d3.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(root.apply).not.toThrow(); |
+ d2.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(root.apply).not.toThrow(); |
+ }); |
- it('should not too eagerly create own streams', inject((RootScope root) { |
- var a = root.createChild({}); |
- var a2 = root.createChild({}); |
- var b = a.createChild({}); |
- var c = b.createChild({}); |
- var d = c.createChild({}); |
- var e = d.createChild({}); |
+ it('should not too eagerly create own streams', (RootScope root) { |
+ var a = root.createChild({}); |
+ var a2 = root.createChild({}); |
+ var b = a.createChild({}); |
+ var c = b.createChild({}); |
+ var d = c.createChild({}); |
+ var e = d.createChild({}); |
- getStreamState() => [root.hasOwnStreams, a.hasOwnStreams, a2.hasOwnStreams, |
- b.hasOwnStreams, c.hasOwnStreams, d.hasOwnStreams, |
- e.hasOwnStreams]; |
+ getStreamState() => [root.hasOwnStreams, a.hasOwnStreams, a2.hasOwnStreams, |
+ b.hasOwnStreams, c.hasOwnStreams, d.hasOwnStreams, |
+ e.hasOwnStreams]; |
- expect(getStreamState()).toEqual([false, false, false, false, false, false, false]); |
- expect(root.apply).not.toThrow(); |
+ expect(getStreamState()).toEqual([false, false, false, false, false, false, false]); |
+ expect(root.apply).not.toThrow(); |
- e.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([false, false, false, false, false, false, true]); |
- expect(root.apply).not.toThrow(); |
+ e.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([false, false, false, false, false, false, true]); |
+ expect(root.apply).not.toThrow(); |
- d.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([false, false, false, false, false, true, true]); |
- expect(root.apply).not.toThrow(); |
+ d.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([false, false, false, false, false, true, true]); |
+ expect(root.apply).not.toThrow(); |
- b.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([false, false, false, true, false, true, true]); |
- expect(root.apply).not.toThrow(); |
+ b.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([false, false, false, true, false, true, true]); |
+ expect(root.apply).not.toThrow(); |
- c.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([false, false, false, true, true, true, true]); |
- expect(root.apply).not.toThrow(); |
+ c.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([false, false, false, true, true, true, true]); |
+ expect(root.apply).not.toThrow(); |
- a.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([false, true, false, true, true, true, true]); |
- expect(root.apply).not.toThrow(); |
+ a.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([false, true, false, true, true, true, true]); |
+ expect(root.apply).not.toThrow(); |
- a2.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([true, true, true, true, true, true, true]); |
- expect(root.apply).not.toThrow(); |
- })); |
+ a2.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([true, true, true, true, true, true, true]); |
+ expect(root.apply).not.toThrow(); |
+ }); |
- it('should not properly merge streams', inject((RootScope root) { |
- var a = root.createChild({}); |
- var a2 = root.createChild({}); |
- var b = a.createChild({}); |
- var c = b.createChild({}); |
- var d = c.createChild({}); |
- var e = d.createChild({}); |
+ it('should not properly merge streams', (RootScope root) { |
+ var a = root.createChild({}); |
+ var a2 = root.createChild({}); |
+ var b = a.createChild({}); |
+ var c = b.createChild({}); |
+ var d = c.createChild({}); |
+ var e = d.createChild({}); |
- getStreamState() => [root.hasOwnStreams, a.hasOwnStreams, a2.hasOwnStreams, |
- b.hasOwnStreams, c.hasOwnStreams, d.hasOwnStreams, |
- e.hasOwnStreams]; |
+ getStreamState() => [root.hasOwnStreams, a.hasOwnStreams, a2.hasOwnStreams, |
+ b.hasOwnStreams, c.hasOwnStreams, d.hasOwnStreams, |
+ e.hasOwnStreams]; |
- expect(getStreamState()).toEqual([false, false, false, false, false, false, false]); |
- expect(root.apply).not.toThrow(); |
+ expect(getStreamState()).toEqual([false, false, false, false, false, false, false]); |
+ expect(root.apply).not.toThrow(); |
- a2.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([false, false, true, false, false, false, false]); |
- expect(root.apply).not.toThrow(); |
+ a2.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([false, false, true, false, false, false, false]); |
+ expect(root.apply).not.toThrow(); |
- e.on(ScopeEvent.DESTROY).listen((_) => null); |
- expect(getStreamState()).toEqual([true, false, true, false, false, false, true]); |
- expect(root.apply).not.toThrow(); |
- })); |
+ e.on(ScopeEvent.DESTROY).listen((_) => null); |
+ expect(getStreamState()).toEqual([true, false, true, false, false, false, true]); |
+ expect(root.apply).not.toThrow(); |
+ }); |
- it('should clean up on cancel', inject((RootScope root) { |
- var child = root.createChild(null); |
- var cl = child.on("E").listen((e) => null); |
- var rl = root.on("E").listen((e) => null); |
- rl.cancel(); |
- expect(root.apply).not.toThrow(); |
- })); |
+ it('should clean up on cancel', (RootScope root) { |
+ var child = root.createChild(null); |
+ var cl = child.on("E").listen((e) => null); |
+ var rl = root.on("E").listen((e) => null); |
+ rl.cancel(); |
+ expect(root.apply).not.toThrow(); |
+ }); |
- it('should find random bugs', inject((RootScope root) { |
- List scopes; |
- List listeners; |
- List steps; |
- var random = new Random(); |
- for (var i = 0; i < 1000; i++) { |
- if (i % 10 == 0) { |
- scopes = [root.createChild(null)]; |
- listeners = []; |
- steps = []; |
- } |
- switch(random.nextInt(4)) { |
- case 0: |
- if (scopes.length > 10) break; |
- var index = random.nextInt(scopes.length); |
- Scope scope = scopes[index]; |
- var child = scope.createChild(null); |
- scopes.add(child); |
- steps.add('scopes[$index].createChild(null)'); |
- break; |
- case 1: |
- var index = random.nextInt(scopes.length); |
- Scope scope = scopes[index]; |
- listeners.add(scope.on('E').listen((e) => null)); |
- steps.add('scopes[$index].on("E").listen((e)=>null)'); |
- break; |
- case 2: |
- if (scopes.length < 3) break; |
- var index = random.nextInt(scopes.length - 1) + 1; |
- Scope scope = scopes[index]; |
- scope.destroy(); |
- scopes = scopes.where((Scope s) => s.isAttached).toList(); |
- steps.add('scopes[$index].destroy()'); |
- break; |
- case 3: |
- if (listeners.length == 0) break; |
- var index = random.nextInt(listeners.length); |
- var l = listeners[index]; |
- l.cancel(); |
- listeners.remove(l); |
- steps.add('listeners[$index].cancel()'); |
- break; |
- } |
- try { |
- root.apply(); |
- } catch (e) { |
- expect('').toEqual(steps.join(';\n')); |
+ it('should find random bugs', (RootScope root) { |
+ List scopes; |
+ List listeners; |
+ List steps; |
+ var random = new Random(); |
+ for (var i = 0; i < 1000; i++) { |
+ if (i % 10 == 0) { |
+ scopes = [root.createChild(null)]; |
+ listeners = []; |
+ steps = []; |
+ } |
+ switch(random.nextInt(4)) { |
+ case 0: |
+ if (scopes.length > 10) break; |
+ var index = random.nextInt(scopes.length); |
+ Scope scope = scopes[index]; |
+ var child = scope.createChild(null); |
+ scopes.add(child); |
+ steps.add('scopes[$index].createChild(null)'); |
+ break; |
+ case 1: |
+ var index = random.nextInt(scopes.length); |
+ Scope scope = scopes[index]; |
+ listeners.add(scope.on('E').listen((e) => null)); |
+ steps.add('scopes[$index].on("E").listen((e)=>null)'); |
+ break; |
+ case 2: |
+ if (scopes.length < 3) break; |
+ var index = random.nextInt(scopes.length - 1) + 1; |
+ Scope scope = scopes[index]; |
+ scope.destroy(); |
+ scopes = scopes.where((Scope s) => s.isAttached).toList(); |
+ steps.add('scopes[$index].destroy()'); |
+ break; |
+ case 3: |
+ if (listeners.length == 0) break; |
+ var index = random.nextInt(listeners.length); |
+ var l = listeners[index]; |
+ l.cancel(); |
+ listeners.remove(l); |
+ steps.add('listeners[$index].cancel()'); |
+ break; |
+ } |
+ try { |
+ root.apply(); |
+ } catch (e) { |
+ expect('').toEqual(steps.join(';\n')); |
+ } |
} |
+ }); |
+ }); |
+ |
+ |
+ describe('emit', () { |
+ var log, child, grandChild, greatGrandChild; |
+ |
+ logger(event) { |
+ log.add(event.currentScope.context['id']); |
} |
- })); |
- }); |
+ beforeEachModule(() { |
+ return (RootScope rootScope) { |
+ log = []; |
+ child = rootScope.createChild({'id': 1}); |
+ grandChild = child.createChild({'id': 2}); |
+ greatGrandChild = grandChild.createChild({'id': 3}); |
+ |
+ rootScope.context['id'] = 0; |
+ |
+ rootScope.on('myEvent').listen(logger); |
+ child.on('myEvent').listen(logger); |
+ grandChild.on('myEvent').listen(logger); |
+ greatGrandChild.on('myEvent').listen(logger); |
+ }; |
+ }); |
+ |
+ it(r'should bubble event up to the root scope', (RootScope rootScope) { |
+ grandChild.emit(r'myEvent'); |
+ expect(log.join('>')).toEqual('2>1>0'); |
+ }); |
- describe('emit', () { |
- var log, child, grandChild, greatGrandChild; |
- logger(event) { |
- log.add(event.currentScope.context['id']); |
- } |
+ describe('exceptions', () { |
+ beforeEachModule((Module module) { |
+ module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
+ }); |
- beforeEach(module(() { |
- return (RootScope rootScope) { |
- log = []; |
- child = rootScope.createChild({'id': 1}); |
- grandChild = child.createChild({'id': 2}); |
- greatGrandChild = grandChild.createChild({'id': 3}); |
- rootScope.context['id'] = 0; |
+ it(r'should dispatch exceptions to the exceptionHandler', (ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ child.on('myEvent').listen((e) { throw 'bubbleException'; }); |
+ grandChild.emit(r'myEvent'); |
+ expect(log.join('>')).toEqual('2>1>0'); |
+ expect(exceptionHandler.errors[0].error).toEqual('bubbleException'); |
+ }); |
- rootScope.on('myEvent').listen(logger); |
- child.on('myEvent').listen(logger); |
- grandChild.on('myEvent').listen(logger); |
- greatGrandChild.on('myEvent').listen(logger); |
- }; |
- })); |
- it(r'should bubble event up to the root scope', inject((RootScope rootScope) { |
- grandChild.emit(r'myEvent'); |
- expect(log.join('>')).toEqual('2>1>0'); |
- })); |
+ it('should throw "model unstable" error when observer is present', (RootScope rootScope, VmTurnZone zone, ExceptionHandler e) { |
+ // Generates a different, equal, list on each evaluation. |
+ rootScope.context['list'] = new UnstableList(); |
+ rootScope.watch('list.list', (n, v) => null, canChangeModel: true); |
+ try { |
+ zone.run(() => null); |
+ } catch(_) {} |
- it(r'should dispatch exceptions to the exceptionHandler', () { |
- module((Module module) { |
- module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
+ var errors = (e as LoggingExceptionHandler).errors; |
+ expect(errors.length).toEqual(1); |
+ expect(errors.first.error, startsWith('Model did not stabilize')); |
+ }); |
}); |
- inject((ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
- child.on('myEvent').listen((e) { throw 'bubbleException'; }); |
+ |
+ it(r'should allow stopping event propagation', (RootScope rootScope) { |
+ child.on('myEvent').listen((event) { event.stopPropagation(); }); |
grandChild.emit(r'myEvent'); |
- expect(log.join('>')).toEqual('2>1>0'); |
- expect(exceptionHandler.errors[0].error).toEqual('bubbleException'); |
+ expect(log.join('>')).toEqual('2>1'); |
}); |
- }); |
- it(r'should allow stopping event propagation', inject((RootScope rootScope) { |
- child.on('myEvent').listen((event) { event.stopPropagation(); }); |
- grandChild.emit(r'myEvent'); |
- expect(log.join('>')).toEqual('2>1'); |
- })); |
+ it(r'should forward method arguments', (RootScope rootScope) { |
+ var eventName; |
+ var eventData; |
+ child.on('abc').listen((event) { |
+ eventName = event.name; |
+ eventData = event.data; |
+ }); |
+ child.emit('abc', ['arg1', 'arg2']); |
+ expect(eventName).toEqual('abc'); |
+ expect(eventData).toEqual(['arg1', 'arg2']); |
+ }); |
+ |
+ |
+ describe(r'event object', () { |
+ it(r'should have methods/properties', (RootScope rootScope) { |
+ var event; |
+ child.on('myEvent').listen((e) { |
+ expect(e.targetScope).toBe(grandChild); |
+ expect(e.currentScope).toBe(child); |
+ expect(e.name).toBe('myEvent'); |
+ event = e; |
+ }); |
+ grandChild.emit(r'myEvent'); |
+ expect(event).toBeDefined(); |
+ }); |
- it(r'should forward method arguments', inject((RootScope rootScope) { |
- var eventName; |
- var eventData; |
- child.on('abc').listen((event) { |
- eventName = event.name; |
- eventData = event.data; |
+ it(r'should have preventDefault method and defaultPrevented property', (RootScope rootScope) { |
+ var event = grandChild.emit(r'myEvent'); |
+ expect(event.defaultPrevented).toBe(false); |
+ |
+ child.on('myEvent').listen((event) { |
+ event.preventDefault(); |
+ }); |
+ event = grandChild.emit(r'myEvent'); |
+ expect(event.defaultPrevented).toBe(true); |
+ }); |
}); |
- child.emit('abc', ['arg1', 'arg2']); |
- expect(eventName).toEqual('abc'); |
- expect(eventData).toEqual(['arg1', 'arg2']); |
- })); |
+ }); |
+ |
+ |
+ describe('broadcast', () { |
+ describe(r'event propagation', () { |
+ var log, child1, child2, child3, grandChild11, grandChild21, grandChild22, grandChild23, |
+ greatGrandChild211; |
+ logger(event) { |
+ log.add(event.currentScope.context['id']); |
+ } |
- describe(r'event object', () { |
- it(r'should have methods/properties', inject((RootScope rootScope) { |
- var event; |
- child.on('myEvent').listen((e) { |
- expect(e.targetScope).toBe(grandChild); |
- expect(e.currentScope).toBe(child); |
- expect(e.name).toBe('myEvent'); |
- event = e; |
+ beforeEach((RootScope rootScope) { |
+ log = []; |
+ child1 = rootScope.createChild({}); |
+ child2 = rootScope.createChild({}); |
+ child3 = rootScope.createChild({}); |
+ grandChild11 = child1.createChild({}); |
+ grandChild21 = child2.createChild({}); |
+ grandChild22 = child2.createChild({}); |
+ grandChild23 = child2.createChild({}); |
+ greatGrandChild211 = grandChild21.createChild({}); |
+ |
+ rootScope.context['id'] = 0; |
+ child1.context['id'] = 1; |
+ child2.context['id'] = 2; |
+ child3.context['id'] = 3; |
+ grandChild11.context['id'] = 11; |
+ grandChild21.context['id'] = 21; |
+ grandChild22.context['id'] = 22; |
+ grandChild23.context['id'] = 23; |
+ greatGrandChild211.context['id'] = 211; |
+ |
+ rootScope.on('myEvent').listen(logger); |
+ child1.on('myEvent').listen(logger); |
+ child2.on('myEvent').listen(logger); |
+ child3.on('myEvent').listen(logger); |
+ grandChild11.on('myEvent').listen(logger); |
+ grandChild21.on('myEvent').listen(logger); |
+ grandChild22.on('myEvent').listen(logger); |
+ grandChild23.on('myEvent').listen(logger); |
+ greatGrandChild211.on('myEvent').listen(logger); |
+ |
+ // R |
+ // / | \ |
+ // 1 2 3 |
+ // / / | \ |
+ // 11 21 22 23 |
+ // | |
+ // 211 |
}); |
- grandChild.emit(r'myEvent'); |
- expect(event).toBeDefined(); |
- })); |
- it(r'should have preventDefault method and defaultPrevented property', inject((RootScope rootScope) { |
- var event = grandChild.emit(r'myEvent'); |
- expect(event.defaultPrevented).toBe(false); |
+ it(r'should broadcast an event from the root scope', (RootScope rootScope) { |
+ rootScope.broadcast('myEvent'); |
+ expect(log.join('>')).toEqual('0>1>11>2>21>211>22>23>3'); |
+ }); |
+ |
- child.on('myEvent').listen((event) { |
- event.preventDefault(); |
+ it(r'should broadcast an event from a child scope', (RootScope rootScope) { |
+ child2.broadcast('myEvent'); |
+ expect(log.join('>')).toEqual('2>21>211>22>23'); |
}); |
- event = grandChild.emit(r'myEvent'); |
- expect(event.defaultPrevented).toBe(true); |
- })); |
- }); |
- }); |
- describe('broadcast', () { |
- describe(r'event propagation', () { |
- var log, child1, child2, child3, grandChild11, grandChild21, grandChild22, grandChild23, |
- greatGrandChild211; |
+ it(r'should broadcast an event from a leaf scope with a sibling', (RootScope rootScope) { |
+ grandChild22.broadcast('myEvent'); |
+ expect(log.join('>')).toEqual('22'); |
+ }); |
+ |
+ |
+ it(r'should broadcast an event from a leaf scope without a sibling', (RootScope rootScope) { |
+ grandChild23.broadcast('myEvent'); |
+ expect(log.join('>')).toEqual('23'); |
+ }); |
- logger(event) { |
- log.add(event.currentScope.context['id']); |
- } |
- beforeEach(inject((RootScope rootScope) { |
- log = []; |
- child1 = rootScope.createChild({}); |
- child2 = rootScope.createChild({}); |
- child3 = rootScope.createChild({}); |
- grandChild11 = child1.createChild({}); |
- grandChild21 = child2.createChild({}); |
- grandChild22 = child2.createChild({}); |
- grandChild23 = child2.createChild({}); |
- greatGrandChild211 = grandChild21.createChild({}); |
- |
- rootScope.context['id'] = 0; |
- child1.context['id'] = 1; |
- child2.context['id'] = 2; |
- child3.context['id'] = 3; |
- grandChild11.context['id'] = 11; |
- grandChild21.context['id'] = 21; |
- grandChild22.context['id'] = 22; |
- grandChild23.context['id'] = 23; |
- greatGrandChild211.context['id'] = 211; |
- |
- rootScope.on('myEvent').listen(logger); |
- child1.on('myEvent').listen(logger); |
- child2.on('myEvent').listen(logger); |
- child3.on('myEvent').listen(logger); |
- grandChild11.on('myEvent').listen(logger); |
- grandChild21.on('myEvent').listen(logger); |
- grandChild22.on('myEvent').listen(logger); |
- grandChild23.on('myEvent').listen(logger); |
- greatGrandChild211.on('myEvent').listen(logger); |
- |
- // R |
- // / | \ |
- // 1 2 3 |
- // / / | \ |
- // 11 21 22 23 |
- // | |
- // 211 |
- })); |
- |
- |
- it(r'should broadcast an event from the root scope', inject((RootScope rootScope) { |
- rootScope.broadcast('myEvent'); |
- expect(log.join('>')).toEqual('0>1>11>2>21>211>22>23>3'); |
- })); |
- |
- |
- it(r'should broadcast an event from a child scope', inject((RootScope rootScope) { |
- child2.broadcast('myEvent'); |
- expect(log.join('>')).toEqual('2>21>211>22>23'); |
- })); |
- |
- |
- it(r'should broadcast an event from a leaf scope with a sibling', inject((RootScope rootScope) { |
- grandChild22.broadcast('myEvent'); |
- expect(log.join('>')).toEqual('22'); |
- })); |
- |
- |
- it(r'should broadcast an event from a leaf scope without a sibling', inject((RootScope rootScope) { |
- grandChild23.broadcast('myEvent'); |
- expect(log.join('>')).toEqual('23'); |
- })); |
- |
- |
- it(r'should not not fire any listeners for other events', inject((RootScope rootScope) { |
- rootScope.broadcast('fooEvent'); |
- expect(log.join('>')).toEqual(''); |
- })); |
- |
- |
- it(r'should return event object', inject((RootScope rootScope) { |
- var result = child1.broadcast('some'); |
- |
- expect(result).toBeDefined(); |
- expect(result.name).toBe('some'); |
- expect(result.targetScope).toBe(child1); |
- })); |
- |
- |
- it('should skip scopes which dont have given event', |
- inject((RootScope rootScope, Logger log) { |
- var child1 = rootScope.createChild('A'); |
- rootScope.createChild('A1'); |
- rootScope.createChild('A2'); |
- rootScope.createChild('A3'); |
- var child2 = rootScope.createChild('B'); |
- child2.on('event').listen((e) => log(e.data)); |
- rootScope.broadcast('event', 'OK'); |
- expect(log).toEqual(['OK']); |
- })); |
- }); |
- |
- |
- describe(r'listener', () { |
- it(r'should receive event object', inject((RootScope rootScope) { |
- var scope = rootScope, |
- child = scope.createChild({}), |
- event; |
- |
- child.on('fooEvent').listen((e) { |
- event = e; |
+ it(r'should not not fire any listeners for other events', (RootScope rootScope) { |
+ rootScope.broadcast('fooEvent'); |
+ expect(log.join('>')).toEqual(''); |
}); |
- scope.broadcast('fooEvent'); |
- expect(event.name).toBe('fooEvent'); |
- expect(event.targetScope).toBe(scope); |
- expect(event.currentScope).toBe(child); |
- })); |
- it(r'should support passing messages as varargs', inject((RootScope rootScope) { |
- var scope = rootScope, |
- child = scope.createChild({}), |
- args; |
+ it(r'should return event object', (RootScope rootScope) { |
+ var result = child1.broadcast('some'); |
- child.on('fooEvent').listen((e) { |
- args = e.data; |
+ expect(result).toBeDefined(); |
+ expect(result.name).toBe('some'); |
+ expect(result.targetScope).toBe(child1); |
}); |
- scope.broadcast('fooEvent', ['do', 're', 'me', 'fa']); |
- expect(args.length).toBe(4); |
- expect(args).toEqual(['do', 're', 'me', 'fa']); |
- })); |
- }); |
- }); |
- }); |
+ it('should skip scopes which dont have given event', |
+ inject((RootScope rootScope, Logger log) { |
+ var child1 = rootScope.createChild('A'); |
+ rootScope.createChild('A1'); |
+ rootScope.createChild('A2'); |
+ rootScope.createChild('A3'); |
+ var child2 = rootScope.createChild('B'); |
+ child2.on('event').listen((e) => log(e.data)); |
+ rootScope.broadcast('event', 'OK'); |
+ expect(log).toEqual(['OK']); |
+ })); |
+ }); |
- describe(r'destroy', () { |
- var first = null, middle = null, last = null, log = null; |
- beforeEach(inject((RootScope rootScope) { |
- log = ''; |
+ describe(r'listener', () { |
+ it(r'should receive event object', (RootScope rootScope) { |
+ var scope = rootScope, |
+ child = scope.createChild({}), |
+ event; |
- first = rootScope.createChild({"check": (n) { log+= '$n'; return n;}}); |
- middle = rootScope.createChild({"check": (n) { log+= '$n'; return n;}}); |
- last = rootScope.createChild({"check": (n) { log+= '$n'; return n;}}); |
+ child.on('fooEvent').listen((e) { |
+ event = e; |
+ }); |
+ scope.broadcast('fooEvent'); |
- first.watch('check(1)', (v, l) {}); |
- middle.watch('check(2)', (v, l) {}); |
- last.watch('check(3)', (v, l) {}); |
+ expect(event.name).toBe('fooEvent'); |
+ expect(event.targetScope).toBe(scope); |
+ expect(event.currentScope).toBe(child); |
+ }); |
- first.on(ScopeEvent.DESTROY).listen((e) { log += 'destroy:first;'; }); |
+ it(r'should support passing messages as varargs', (RootScope rootScope) { |
+ var scope = rootScope, |
+ child = scope.createChild({}), |
+ args; |
- rootScope.digest(); |
- log = ''; |
- })); |
+ child.on('fooEvent').listen((e) { |
+ args = e.data; |
+ }); |
+ scope.broadcast('fooEvent', ['do', 're', 'me', 'fa']); |
+ expect(args.length).toBe(4); |
+ expect(args).toEqual(['do', 're', 'me', 'fa']); |
+ }); |
- it(r'should ignore remove on root', inject((RootScope rootScope) { |
- rootScope.destroy(); |
- rootScope.digest(); |
- expect(log).toEqual('123'); |
- })); |
+ it('should allow removing/adding listener during an event', (RootScope rootScope, Logger log) { |
+ StreamSubscription subscription; |
+ subscription = rootScope.on('foo').listen((_) { |
+ subscription.cancel(); |
+ rootScope.on('foo').listen((_) => log(3)); |
+ log(2); |
+ }); |
+ expect(() { |
+ log(1); |
+ rootScope.broadcast('foo'); |
+ }).not.toThrow(); |
+ rootScope.broadcast('foo'); |
+ expect(log).toEqual([1, 2, 3]); |
+ }); |
+ }); |
+ }); |
+ }); |
- it(r'should remove first', inject((RootScope rootScope) { |
- first.destroy(); |
- rootScope.digest(); |
- expect(log).toEqual('destroy:first;23'); |
- })); |
+ describe(r'destroy', () { |
+ var first = null, middle = null, last = null, log = null; |
+ beforeEach((RootScope rootScope) { |
+ log = ''; |
- it(r'should remove middle', inject((RootScope rootScope) { |
- middle.destroy(); |
- rootScope.digest(); |
- expect(log).toEqual('13'); |
- })); |
+ first = rootScope.createChild({"check": (n) { log+= '$n'; return n;}}); |
+ middle = rootScope.createChild({"check": (n) { log+= '$n'; return n;}}); |
+ last = rootScope.createChild({"check": (n) { log+= '$n'; return n;}}); |
+ first.watch('check(1)', (v, l) {}); |
+ middle.watch('check(2)', (v, l) {}); |
+ last.watch('check(3)', (v, l) {}); |
- it(r'should remove last', inject((RootScope rootScope) { |
- last.destroy(); |
- rootScope.digest(); |
- expect(log).toEqual('12'); |
- })); |
+ first.on(ScopeEvent.DESTROY).listen((e) { log += 'destroy:first;'; }); |
+ rootScope.digest(); |
+ log = ''; |
+ }); |
- it(r'should broadcast the destroy event', inject((RootScope rootScope) { |
- var log = []; |
- first.on(ScopeEvent.DESTROY).listen((s) => log.add('first')); |
- var child = first.createChild({}); |
- child.on(ScopeEvent.DESTROY).listen((s) => log.add('first-child')); |
- first.destroy(); |
- expect(log).toEqual(['first', 'first-child']); |
- })); |
+ it(r'should ignore remove on root', (RootScope rootScope) { |
+ rootScope.destroy(); |
+ rootScope.digest(); |
+ expect(log).toEqual('123'); |
+ }); |
- it('should not call reaction function on destroyed scope', inject((RootScope rootScope, Logger log) { |
- rootScope.context['name'] = 'misko'; |
- var child = rootScope.createChild(rootScope.context); |
- rootScope.watch('name', (v, _) { |
- log('root $v'); |
- if (v == 'destroy') { |
- child.destroy(); |
- } |
+ it(r'should remove first', (RootScope rootScope) { |
+ first.destroy(); |
+ rootScope.digest(); |
+ expect(log).toEqual('destroy:first;23'); |
}); |
- rootScope.watch('name', (v, _) => log('root2 $v')); |
- child.watch('name', (v, _) => log('child $v')); |
- rootScope.apply(); |
- expect(log).toEqual(['root misko', 'root2 misko', 'child misko']); |
- log.clear(); |
- rootScope.context['name'] = 'destroy'; |
- rootScope.apply(); |
- expect(log).toEqual(['root destroy', 'root2 destroy']); |
- })); |
- }); |
+ |
+ it(r'should remove middle', (RootScope rootScope) { |
+ middle.destroy(); |
+ rootScope.digest(); |
+ expect(log).toEqual('13'); |
+ }); |
- describe('digest lifecycle', () { |
- it(r'should apply expression with full lifecycle', inject((RootScope rootScope) { |
- var log = ''; |
- var child = rootScope.createChild({"parent": rootScope.context}); |
- rootScope.watch('a', (a, _) { log += '1'; }); |
- child.apply('parent.a = 0'); |
- expect(log).toEqual('1'); |
- })); |
+ it(r'should remove last', (RootScope rootScope) { |
+ last.destroy(); |
+ rootScope.digest(); |
+ expect(log).toEqual('12'); |
+ }); |
- it(r'should catch exceptions', () { |
- module((Module module) => module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler)); |
- inject((RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
+ it(r'should broadcast the destroy event', (RootScope rootScope) { |
var log = []; |
- var child = rootScope.createChild({}); |
- rootScope.watch('a', (a, _) => log.add('1')); |
- rootScope.context['a'] = 0; |
- child.apply(() { throw 'MyError'; }); |
- expect(log.join(',')).toEqual('1'); |
- expect(exceptionHandler.errors[0].error).toEqual('MyError'); |
- exceptionHandler.errors.removeAt(0); |
- exceptionHandler.assertEmpty(); |
+ first.on(ScopeEvent.DESTROY).listen((s) => log.add('first')); |
+ var child = first.createChild({}); |
+ child.on(ScopeEvent.DESTROY).listen((s) => log.add('first-child')); |
+ |
+ first.destroy(); |
+ expect(log).toEqual(['first', 'first-child']); |
+ }); |
+ |
+ |
+ it('should not call reaction function on destroyed scope', (RootScope rootScope, Logger log) { |
+ rootScope.context['name'] = 'misko'; |
+ var child = rootScope.createChild(rootScope.context); |
+ rootScope.watch('name', (v, _) { |
+ log('root $v'); |
+ if (v == 'destroy') { |
+ child.destroy(); |
+ } |
+ }); |
+ rootScope.watch('name', (v, _) => log('root2 $v')); |
+ child.watch('name', (v, _) => log('child $v')); |
+ rootScope.apply(); |
+ expect(log).toEqual(['root misko', 'root2 misko', 'child misko']); |
+ log.clear(); |
+ |
+ rootScope.context['name'] = 'destroy'; |
+ rootScope.apply(); |
+ expect(log).toEqual(['root destroy', 'root2 destroy']); |
+ }); |
+ |
+ |
+ it('should not call reaction fn when destroyed', (RootScope scope) { |
+ var testScope = scope.createChild({}); |
+ bool called = false; |
+ testScope.watch('items', (_, __) { |
+ called = true; |
+ }); |
+ testScope.destroy(); |
+ scope.apply(); |
+ expect(called).toBeFalsy(); |
}); |
}); |
- describe(r'exceptions', () { |
- var log; |
- beforeEach(module((Module module) { |
- return module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
- })); |
- beforeEach(inject((RootScope rootScope) { |
- rootScope.context['log'] = () { log += 'digest;'; return null; }; |
- log = ''; |
- rootScope.watch('log()', (v, o) => null); |
- rootScope.digest(); |
- log = ''; |
- })); |
+ describe('digest lifecycle', () { |
+ it(r'should apply expression with full lifecycle', (RootScope rootScope) { |
+ var log = ''; |
+ var child = rootScope.createChild({"parent": rootScope.context}); |
+ rootScope.watch('a', (a, _) { log += '1'; }); |
+ child.apply('parent.a = 0'); |
+ expect(log).toEqual('1'); |
+ }); |
+ describe(r'exceptions', () { |
+ var log; |
+ beforeEachModule((Module module) { |
+ return module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
+ }); |
- it(r'should execute and return value and update', inject( |
- (RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
- rootScope.context['name'] = 'abc'; |
- expect(rootScope.apply((context) => context['name'])).toEqual('abc'); |
- expect(log).toEqual('digest;digest;'); |
- exceptionHandler.assertEmpty(); |
- })); |
+ beforeEach((RootScope rootScope) { |
+ rootScope.context['log'] = () { log += 'digest;'; return null; }; |
+ log = ''; |
+ rootScope.watch('log()', (v, o) => null); |
+ rootScope.digest(); |
+ log = ''; |
+ }); |
+ it(r'should catch exceptions', (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ var log = []; |
+ var child = rootScope.createChild({}); |
+ rootScope.watch('a', (a, _) => log.add('1')); |
+ rootScope.context['a'] = 0; |
+ child.apply(() { throw 'MyError'; }); |
+ expect(log.join(',')).toEqual('1'); |
+ expect(exceptionHandler.errors[0].error).toEqual('MyError'); |
+ exceptionHandler.errors.removeAt(0); |
+ exceptionHandler.assertEmpty(); |
+ }); |
- it(r'should execute and return value and update', inject((RootScope rootScope) { |
- rootScope.context['name'] = 'abc'; |
- expect(rootScope.apply('name', {'name': 123})).toEqual(123); |
- })); |
+ it(r'should execute and return value and update', inject( |
+ (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ rootScope.context['name'] = 'abc'; |
+ expect(rootScope.apply((context) => context['name'])).toEqual('abc'); |
+ expect(log).toEqual('digest;digest;'); |
+ exceptionHandler.assertEmpty(); |
+ })); |
- it(r'should catch exception and update', inject((RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
+ |
+ it(r'should execute and return value and update', (RootScope rootScope) { |
+ rootScope.context['name'] = 'abc'; |
+ expect(rootScope.apply('name', {'name': 123})).toEqual(123); |
+ }); |
+ |
+ |
+ it(r'should catch exception and update', (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ var error = 'MyError'; |
+ rootScope.apply(() { throw error; }); |
+ expect(log).toEqual('digest;digest;'); |
+ expect(exceptionHandler.errors[0].error).toEqual(error); |
+ }); |
+ }); |
+ |
+ it(r'should properly reset phase on exception', (RootScope rootScope) { |
var error = 'MyError'; |
- rootScope.apply(() { throw error; }); |
- expect(log).toEqual('digest;digest;'); |
- expect(exceptionHandler.errors[0].error).toEqual(error); |
- })); |
+ expect(() => rootScope.apply(() { throw error; })).toThrow(error); |
+ expect(() => rootScope.apply(() { throw error; })).toThrow(error); |
+ }); |
}); |
- it(r'should proprely reset phase on exception', inject((RootScope rootScope) { |
- var error = 'MyError'; |
- expect(() => rootScope.apply(() { throw error; })).toThrow(error); |
- expect(() => rootScope.apply(() { throw error; })).toThrow(error); |
- })); |
- }); |
+ |
+ describe('flush lifecycle', () { |
+ it(r'should apply expression with full lifecycle', (RootScope rootScope) { |
+ var log = ''; |
+ var child = rootScope.createChild({"parent": rootScope.context}); |
+ rootScope.watch('a', (a, _) { log += '1'; }, canChangeModel: false); |
+ child.apply('parent.a = 0'); |
+ expect(log).toEqual('1'); |
+ }); |
- describe('flush lifecycle', () { |
- it(r'should apply expression with full lifecycle', inject((RootScope rootScope) { |
- var log = ''; |
- var child = rootScope.createChild({"parent": rootScope.context}); |
- rootScope.watch('a', (a, _) { log += '1'; }, readOnly: true); |
- child.apply('parent.a = 0'); |
- expect(log).toEqual('1'); |
- })); |
+ it(r'should schedule domWrites and domReads', (RootScope rootScope) { |
+ var log = ''; |
+ var child = rootScope.createChild({"parent": rootScope.context}); |
+ rootScope.watch('a', (a, _) { log += '1'; }, canChangeModel: false); |
+ child.apply('parent.a = 0'); |
+ expect(log).toEqual('1'); |
+ }); |
+ describe(r'exceptions', () { |
+ var log; |
+ beforeEachModule((Module module) { |
+ return module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
+ }); |
+ beforeEach((RootScope rootScope) { |
+ rootScope.context['log'] = () { log += 'digest;'; return null; }; |
+ log = ''; |
+ rootScope.watch('log()', (v, o) => null, canChangeModel: false); |
+ rootScope.digest(); |
+ log = ''; |
+ }); |
- it(r'should schedule domWrites and domReads', inject((RootScope rootScope) { |
- var log = ''; |
- var child = rootScope.createChild({"parent": rootScope.context}); |
- rootScope.watch('a', (a, _) { log += '1'; }, readOnly: true); |
- child.apply('parent.a = 0'); |
- expect(log).toEqual('1'); |
- })); |
+ it(r'should catch exceptions', (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ var log = []; |
+ var child = rootScope.createChild({}); |
+ rootScope.watch('a', (a, _) => log.add('1'), canChangeModel: false); |
+ rootScope.context['a'] = 0; |
+ child.apply(() { throw 'MyError'; }); |
+ expect(log.join(',')).toEqual('1'); |
+ expect(exceptionHandler.errors[0].error).toEqual('MyError'); |
+ exceptionHandler.errors.removeAt(0); |
+ exceptionHandler.assertEmpty(); |
+ }); |
+ it(r'should execute and return value and update', inject( |
+ (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ rootScope.context['name'] = 'abc'; |
+ expect(rootScope.apply((context) => context['name'])).toEqual('abc'); |
+ expect(log).toEqual('digest;digest;'); |
+ exceptionHandler.assertEmpty(); |
+ })); |
+ |
+ it(r'should execute and return value and update', (RootScope rootScope) { |
+ rootScope.context['name'] = 'abc'; |
+ expect(rootScope.apply('name', {'name': 123})).toEqual(123); |
+ }); |
- it(r'should catch exceptions', () { |
- module((Module module) => module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler)); |
- inject((RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
- var log = []; |
- var child = rootScope.createChild({}); |
- rootScope.watch('a', (a, _) => log.add('1'), readOnly: true); |
- rootScope.context['a'] = 0; |
- child.apply(() { throw 'MyError'; }); |
- expect(log.join(',')).toEqual('1'); |
- expect(exceptionHandler.errors[0].error).toEqual('MyError'); |
- exceptionHandler.errors.removeAt(0); |
- exceptionHandler.assertEmpty(); |
+ it(r'should catch exception and update', (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ var error = 'MyError'; |
+ rootScope.apply(() { throw error; }); |
+ expect(log).toEqual('digest;digest;'); |
+ expect(exceptionHandler.errors[0].error).toEqual(error); |
+ }); |
+ |
+ it(r'should throw assertion when model changes in flush', (RootScope rootScope, Logger log) { |
+ var retValue = 1; |
+ rootScope.context['logger'] = (name) { log(name); return retValue; }; |
+ |
+ rootScope.watch('logger("watch")', (n, v) => null); |
+ rootScope.watch('logger("flush")', (n, v) => null, |
+ canChangeModel: false); |
+ |
+ // clear watches |
+ rootScope.digest(); |
+ log.clear(); |
+ |
+ rootScope.flush(); |
+ expect(log).toEqual(['flush', /*assertion*/ 'watch', 'flush']); |
+ |
+ retValue = 2; |
+ expect(rootScope.flush). |
+ toThrow('Observer reaction functions should not change model. \n' |
+ 'These watch changes were detected: logger("watch"): 2 <= 1\n' |
+ 'These observe changes were detected: '); |
+ }); |
}); |
+ |
}); |
- describe(r'exceptions', () { |
- var log; |
- beforeEach(module((Module module) { |
- return module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
- })); |
- beforeEach(inject((RootScope rootScope) { |
- rootScope.context['log'] = () { log += 'digest;'; return null; }; |
- log = ''; |
- rootScope.watch('log()', (v, o) => null, readOnly: true); |
- rootScope.digest(); |
- log = ''; |
- })); |
+ describe('ScopeLocals', () { |
+ it('should read from locals', (RootScope scope) { |
+ scope.context['a'] = 'XXX'; |
+ scope.context['c'] = 'C'; |
+ var scopeLocal = new ScopeLocals(scope.context, {'a': 'A', 'b': 'B'}); |
+ expect(scopeLocal['a']).toEqual('A'); |
+ expect(scopeLocal['b']).toEqual('B'); |
+ expect(scopeLocal['c']).toEqual('C'); |
+ }); |
+ it('should write to Scope', (RootScope scope) { |
+ scope.context['a'] = 'XXX'; |
+ scope.context['c'] = 'C'; |
+ var scopeLocal = new ScopeLocals(scope.context, {'a': 'A', 'b': 'B'}); |
- it(r'should execute and return value and update', inject( |
- (RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
- rootScope.context['name'] = 'abc'; |
- expect(rootScope.apply((context) => context['name'])).toEqual('abc'); |
- expect(log).toEqual('digest;digest;'); |
- exceptionHandler.assertEmpty(); |
- })); |
+ scopeLocal['a'] = 'aW'; |
+ scopeLocal['b'] = 'bW'; |
+ scopeLocal['c'] = 'cW'; |
- it(r'should execute and return value and update', inject((RootScope rootScope) { |
- rootScope.context['name'] = 'abc'; |
- expect(rootScope.apply('name', {'name': 123})).toEqual(123); |
- })); |
+ expect(scope.context['a']).toEqual('aW'); |
+ expect(scope.context['b']).toEqual('bW'); |
+ expect(scope.context['c']).toEqual('cW'); |
- it(r'should catch exception and update', inject((RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
- var error = 'MyError'; |
- rootScope.apply(() { throw error; }); |
- expect(log).toEqual('digest;digest;'); |
- expect(exceptionHandler.errors[0].error).toEqual(error); |
- })); |
+ expect(scopeLocal['a']).toEqual('A'); |
+ expect(scopeLocal['b']).toEqual('B'); |
+ expect(scopeLocal['c']).toEqual('cW'); |
+ }); |
+ }); |
- it(r'should throw assertion when model changes in flush', inject((RootScope rootScope, Logger log) { |
- var retValue = 1; |
- rootScope.context['logger'] = (name) { log(name); return retValue; }; |
- rootScope.watch('logger("watch")', (n, v) => null); |
- rootScope.watch('logger("flush")', (n, v) => null, readOnly: true); |
+ describe(r'watch/digest', () { |
+ it(r'should watch and fire on simple property change', (RootScope rootScope) { |
+ var log; |
- // clear watches |
+ rootScope.watch('name', (a, b) { |
+ log = [a, b]; |
+ }); |
rootScope.digest(); |
- log.clear(); |
+ log = null; |
- rootScope.flush(); |
- expect(log).toEqual(['flush', /*assertion*/ 'watch', 'flush']); |
+ expect(log).toEqual(null); |
+ rootScope.digest(); |
+ expect(log).toEqual(null); |
+ rootScope.context['name'] = 'misko'; |
+ rootScope.digest(); |
+ expect(log).toEqual(['misko', null]); |
+ }); |
- retValue = 2; |
- expect(rootScope.flush). |
- toThrow('Observer reaction functions should not change model. \n' |
- 'These watch changes were detected: logger("watch"): 2 <= 1\n' |
- 'These observe changes were detected: '); |
- })); |
- }); |
- }); |
+ it('should watch/observe on objects other then contex', (RootScope rootScope) { |
+ var log = ''; |
+ var map = {'a': 'A', 'b': 'B'}; |
+ rootScope.watch('a', (a, b) => log += a, context: map); |
+ rootScope.watch('b', (a, b) => log += a, context: map); |
+ rootScope.apply(); |
+ expect(log).toEqual('AB'); |
+ }); |
- describe('ScopeLocals', () { |
- it('should read from locals', inject((RootScope scope) { |
- scope.context['a'] = 'XXX'; |
- scope.context['c'] = 'C'; |
- var scopeLocal = new ScopeLocals(scope.context, {'a': 'A', 'b': 'B'}); |
- expect(scopeLocal['a']).toEqual('A'); |
- expect(scopeLocal['b']).toEqual('B'); |
- expect(scopeLocal['c']).toEqual('C'); |
- })); |
- |
- it('should write to Scope', inject((RootScope scope) { |
- scope.context['a'] = 'XXX'; |
- scope.context['c'] = 'C'; |
- var scopeLocal = new ScopeLocals(scope.context, {'a': 'A', 'b': 'B'}); |
- |
- scopeLocal['a'] = 'aW'; |
- scopeLocal['b'] = 'bW'; |
- scopeLocal['c'] = 'cW'; |
- |
- expect(scope.context['a']).toEqual('aW'); |
- expect(scope.context['b']).toEqual('bW'); |
- expect(scope.context['c']).toEqual('cW'); |
- |
- expect(scopeLocal['a']).toEqual('A'); |
- expect(scopeLocal['b']).toEqual('B'); |
- expect(scopeLocal['c']).toEqual('cW'); |
- })); |
- }); |
+ it(r'should watch and fire on expression change', (RootScope rootScope) { |
+ var log; |
+ |
+ rootScope.watch('name.first', (a, b) => log = [a, b]); |
+ rootScope.digest(); |
+ log = null; |
+ rootScope.context['name'] = {}; |
+ expect(log).toEqual(null); |
+ rootScope.digest(); |
+ expect(log).toEqual(null); |
+ rootScope.context['name']['first'] = 'misko'; |
+ rootScope.digest(); |
+ expect(log).toEqual(['misko', null]); |
+ }); |
- describe(r'watch/digest', () { |
- it(r'should watch and fire on simple property change', inject((RootScope rootScope) { |
- var log; |
- rootScope.watch('name', (a, b) { |
- log = [a, b]; |
+ describe('exceptions', () { |
+ beforeEachModule((Module module) { |
+ module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
+ }); |
+ it(r'should delegate exceptions', (RootScope rootScope, ExceptionHandler e) { |
+ LoggingExceptionHandler exceptionHandler = e; |
+ rootScope.watch('a', (n, o) {throw 'abc';}); |
+ rootScope.context['a'] = 1; |
+ rootScope.digest(); |
+ expect(exceptionHandler.errors.length).toEqual(1); |
+ expect(exceptionHandler.errors[0].error).toEqual('abc'); |
+ }); |
}); |
- rootScope.digest(); |
- log = null; |
- expect(log).toEqual(null); |
- rootScope.digest(); |
- expect(log).toEqual(null); |
- rootScope.context['name'] = 'misko'; |
- rootScope.digest(); |
- expect(log).toEqual(['misko', null]); |
- })); |
- it('should watch/observe on objects other then contex', inject((RootScope rootScope) { |
- var log = ''; |
- var map = {'a': 'A', 'b': 'B'}; |
- rootScope.watch('a', (a, b) => log += a, context: map); |
- rootScope.watch('b', (a, b) => log += a, context: map); |
- rootScope.apply(); |
- expect(log).toEqual('AB'); |
- })); |
+ it(r'should fire watches in order of addition', (RootScope rootScope) { |
+ // this is not an external guarantee, just our own sanity |
+ var log = ''; |
+ rootScope |
+ ..watch('a', (a, b) { log += 'a'; }) |
+ ..watch('b', (a, b) { log += 'b'; }) |
+ ..watch('c', (a, b) { log += 'c'; }) |
+ ..context['a'] = rootScope.context['b'] = rootScope.context['c'] = 1 |
+ ..digest(); |
+ expect(log).toEqual('abc'); |
+ }); |
+ |
+ it(r'should call child watchers in addition order', (RootScope rootScope) { |
+ // this is not an external guarantee, just our own sanity |
+ var log = ''; |
+ var childA = rootScope.createChild({}); |
+ var childB = rootScope.createChild({}); |
+ var childC = rootScope.createChild({}); |
+ childA.watch('a', (a, b) { log += 'a'; }); |
+ childB.watch('b', (a, b) { log += 'b'; }); |
+ childC.watch('c', (a, b) { log += 'c'; }); |
+ childA.context['a'] = childB.context['b'] = childC.context['c'] = 1; |
+ rootScope.digest(); |
+ expect(log).toEqual('abc'); |
+ }); |
- it(r'should watch and fire on expression change', inject((RootScope rootScope) { |
- var log; |
- rootScope.watch('name.first', (a, b) => log = [a, b]); |
- rootScope.digest(); |
- log = null; |
+ it(r'should run digest multiple times', inject( |
+ (RootScope rootScope) { |
+ // tests a traversal edge case which we originally missed |
+ var log = []; |
+ var childA = rootScope.createChild({'log': log}); |
+ var childB = rootScope.createChild({'log': log}); |
- rootScope.context['name'] = {}; |
- expect(log).toEqual(null); |
- rootScope.digest(); |
- expect(log).toEqual(null); |
- rootScope.context['name']['first'] = 'misko'; |
- rootScope.digest(); |
- expect(log).toEqual(['misko', null]); |
- })); |
+ rootScope.context['log'] = log; |
+ rootScope.watch("log.add('r')", (_, __) => null); |
+ childA.watch("log.add('a')", (_, __) => null); |
+ childB.watch("log.add('b')", (_, __) => null); |
- it(r'should delegate exceptions', () { |
- module((Module module) { |
- module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
+ // init |
+ rootScope.digest(); |
+ expect(log.join('')).toEqual('rabrab'); |
+ })); |
+ |
+ |
+ it(r'should repeat watch cycle while model changes are identified', (RootScope rootScope) { |
+ var log = ''; |
+ rootScope |
+ ..watch('c', (v, b) {rootScope.context['d'] = v; log+='c'; }) |
+ ..watch('b', (v, b) {rootScope.context['c'] = v; log+='b'; }) |
+ ..watch('a', (v, b) {rootScope.context['b'] = v; log+='a'; }) |
+ ..digest(); |
+ log = ''; |
+ rootScope.context['a'] = 1; |
+ rootScope.digest(); |
+ expect(rootScope.context['b']).toEqual(1); |
+ expect(rootScope.context['c']).toEqual(1); |
+ expect(rootScope.context['d']).toEqual(1); |
+ expect(log).toEqual('abc'); |
}); |
- inject((RootScope rootScope, ExceptionHandler e) { |
- LoggingExceptionHandler exceptionHandler = e; |
- rootScope.watch('a', (n, o) {throw 'abc';}); |
+ |
+ |
+ it(r'should repeat watch cycle from the root element', (RootScope rootScope) { |
+ var log = []; |
+ rootScope.context['log'] = log; |
+ var child = rootScope.createChild({'log':log}); |
+ rootScope.watch("log.add('a')", (_, __) => null); |
+ child.watch("log.add('b')", (_, __) => null); |
+ rootScope.digest(); |
+ expect(log.join('')).toEqual('abab'); |
+ }); |
+ |
+ |
+ it(r'should not fire upon watch registration on initial digest', (RootScope rootScope) { |
+ var log = ''; |
rootScope.context['a'] = 1; |
+ rootScope.watch('a', (a, b) { log += 'a'; }); |
+ rootScope.watch('b', (a, b) { log += 'b'; }); |
+ rootScope.digest(); |
+ log = ''; |
rootScope.digest(); |
- expect(exceptionHandler.errors.length).toEqual(1); |
- expect(exceptionHandler.errors[0].error).toEqual('abc'); |
+ expect(log).toEqual(''); |
}); |
- }); |
- it(r'should fire watches in order of addition', inject((RootScope rootScope) { |
- // this is not an external guarantee, just our own sanity |
- var log = ''; |
- rootScope.watch('a', (a, b) { log += 'a'; }); |
- rootScope.watch('b', (a, b) { log += 'b'; }); |
- rootScope.watch('c', (a, b) { log += 'c'; }); |
- rootScope.context['a'] = rootScope.context['b'] = rootScope.context['c'] = 1; |
- rootScope.digest(); |
- expect(log).toEqual('abc'); |
- })); |
- |
- |
- it(r'should call child watchers in addition order', inject((RootScope rootScope) { |
- // this is not an external guarantee, just our own sanity |
- var log = ''; |
- var childA = rootScope.createChild({}); |
- var childB = rootScope.createChild({}); |
- var childC = rootScope.createChild({}); |
- childA.watch('a', (a, b) { log += 'a'; }); |
- childB.watch('b', (a, b) { log += 'b'; }); |
- childC.watch('c', (a, b) { log += 'c'; }); |
- childA.context['a'] = childB.context['b'] = childC.context['c'] = 1; |
- rootScope.digest(); |
- expect(log).toEqual('abc'); |
- })); |
- |
- |
- it(r'should run digest multiple times', inject( |
- (RootScope rootScope) { |
- // tests a traversal edge case which we originally missed |
- var log = []; |
- var childA = rootScope.createChild({'log': log}); |
- var childB = rootScope.createChild({'log': log}); |
+ it(r'should prevent digest recursion', (RootScope rootScope) { |
+ var callCount = 0; |
+ rootScope.watch('name', (a, b) { |
+ expect(() { |
+ rootScope.digest(); |
+ }).toThrow(r'digest already in progress'); |
+ callCount++; |
+ }); |
+ rootScope.context['name'] = 'a'; |
+ rootScope.digest(); |
+ expect(callCount).toEqual(1); |
+ }); |
+ |
+ |
+ it(r'should return a function that allows listeners to be unregistered', inject( |
+ (RootScope rootScope) { |
+ var listener = jasmine.createSpy('watch listener'); |
+ var watch; |
+ |
+ watch = rootScope.watch('foo', listener); |
+ rootScope.digest(); //init |
+ expect(listener).toHaveBeenCalled(); |
+ expect(watch).toBeDefined(); |
+ |
+ listener.reset(); |
+ rootScope.context['foo'] = 'bar'; |
+ rootScope.digest(); //trigger |
+ expect(listener).toHaveBeenCalledOnce(); |
+ |
+ listener.reset(); |
+ rootScope.context['foo'] = 'baz'; |
+ watch.remove(); |
+ rootScope.digest(); //trigger |
+ expect(listener).not.toHaveBeenCalled(); |
+ })); |
- rootScope.context['log'] = log; |
- rootScope.watch("log.add('r')", (_, __) => null); |
- childA.watch("log.add('a')", (_, __) => null); |
- childB.watch("log.add('b')", (_, __) => null); |
+ it(r'should be possible to remove every watch', |
+ (RootScope rootScope, FormatterMap formatters) { |
+ rootScope.context['foo'] = 'bar'; |
+ var watch1 = rootScope.watch('(foo|json)+"bar"', (v, p) => null, |
+ formatters: formatters); |
+ var watch2 = rootScope.watch('(foo|json)+"bar"', (v, p) => null, |
+ formatters: formatters); |
+ |
+ expect(() => watch1.remove()).not.toThrow(); |
+ expect(() => watch2.remove()).not.toThrow(); |
+ }); |
- // init |
+ |
+ it(r'should not infinitely digest when current value is NaN', (RootScope rootScope) { |
+ rootScope.context['nan'] = double.NAN; |
+ rootScope.watch('nan', (_, __) => null); |
+ |
+ expect(() { |
rootScope.digest(); |
- expect(log.join('')).toEqual('rabrab'); |
- })); |
- |
- |
- it(r'should repeat watch cycle while model changes are identified', inject((RootScope rootScope) { |
- var log = ''; |
- rootScope.watch('c', (v, b) {rootScope.context['d'] = v; log+='c'; }); |
- rootScope.watch('b', (v, b) {rootScope.context['c'] = v; log+='b'; }); |
- rootScope.watch('a', (v, b) {rootScope.context['b'] = v; log+='a'; }); |
- rootScope.digest(); |
- log = ''; |
- rootScope.context['a'] = 1; |
- rootScope.digest(); |
- expect(rootScope.context['b']).toEqual(1); |
- expect(rootScope.context['c']).toEqual(1); |
- expect(rootScope.context['d']).toEqual(1); |
- expect(log).toEqual('abc'); |
- })); |
- |
- |
- it(r'should repeat watch cycle from the root element', inject((RootScope rootScope) { |
- var log = []; |
- rootScope.context['log'] = log; |
- var child = rootScope.createChild({'log':log}); |
- rootScope.watch("log.add('a')", (_, __) => null); |
- child.watch("log.add('b')", (_, __) => null); |
- rootScope.digest(); |
- expect(log.join('')).toEqual('abab'); |
- })); |
- |
- |
- it(r'should not fire upon watch registration on initial digest', inject((RootScope rootScope) { |
- var log = ''; |
- rootScope.context['a'] = 1; |
- rootScope.watch('a', (a, b) { log += 'a'; }); |
- rootScope.watch('b', (a, b) { log += 'b'; }); |
- rootScope.digest(); |
- log = ''; |
- rootScope.digest(); |
- expect(log).toEqual(''); |
- })); |
- |
- |
- it(r'should prevent digest recursion', inject((RootScope rootScope) { |
- var callCount = 0; |
- rootScope.watch('name', (a, b) { |
+ }).not.toThrow(); |
+ }); |
+ |
+ |
+ it(r'should prevent infinite digest and should log firing expressions', (RootScope rootScope) { |
+ rootScope.context['a'] = 0; |
+ rootScope.context['b'] = 0; |
+ rootScope.watch('a', (a, __) => rootScope.context['a'] = a + 1); |
+ rootScope.watch('b', (b, __) => rootScope.context['b'] = b + 1); |
+ |
expect(() { |
rootScope.digest(); |
- }).toThrow(r'digest already in progress'); |
- callCount++; |
+ }).toThrow('Model did not stabilize in 5 digests. ' |
+ 'Last 3 iterations:\n' |
+ 'a: 2 <= 1, b: 2 <= 1\n' |
+ 'a: 3 <= 2, b: 3 <= 2\n' |
+ 'a: 4 <= 3, b: 4 <= 3'); |
}); |
- rootScope.context['name'] = 'a'; |
- rootScope.digest(); |
- expect(callCount).toEqual(1); |
- })); |
- it(r'should return a function that allows listeners to be unregistered', inject( |
- (RootScope rootScope) { |
- var listener = jasmine.createSpy('watch listener'); |
- var watch; |
+ it(r'should always call the watchr with newVal and oldVal equal on the first run', |
+ inject((RootScope rootScope) { |
+ var log = []; |
+ var logger = (newVal, oldVal) { |
+ var val = (newVal == oldVal || (newVal != oldVal && oldVal != newVal)) ? newVal : 'xxx'; |
+ log.add(val); |
+ }; |
+ |
+ rootScope |
+ ..context['nanValue'] = double.NAN |
+ ..context['nullValue'] = null |
+ ..context['emptyString'] = '' |
+ ..context['falseValue'] = false |
+ ..context['numberValue'] = 23 |
+ ..watch('nanValue', logger) |
+ ..watch('nullValue', logger) |
+ ..watch('emptyString', logger) |
+ ..watch('falseValue', logger) |
+ ..watch('numberValue', logger) |
+ ..digest(); |
+ |
+ expect(log.removeAt(0).isNaN).toEqual(true); //jasmine's toBe and toEqual don't work well with NaNs |
+ expect(log).toEqual([null, '', false, 23]); |
+ log = []; |
+ rootScope.digest(); |
+ expect(log).toEqual([]); |
+ })); |
- watch = rootScope.watch('foo', listener); |
- rootScope.digest(); //init |
- expect(listener).toHaveBeenCalled(); |
- expect(watch).toBeDefined(); |
- listener.reset(); |
- rootScope.context['foo'] = 'bar'; |
- rootScope.digest(); //triger |
- expect(listener).toHaveBeenCalledOnce(); |
+ it('should properly watch constants', (RootScope rootScope, Logger log) { |
+ rootScope.watch('[1, 2]', (v, o) => log([v, o])); |
+ expect(log).toEqual([]); |
+ rootScope.apply(); |
+ expect(log).toEqual([[[1, 2], null]]); |
+ }); |
- listener.reset(); |
- rootScope.context['foo'] = 'baz'; |
- watch.remove(); |
- rootScope.digest(); //trigger |
- expect(listener).not.toHaveBeenCalled(); |
- })); |
+ it('should properly watch array of fields 1', (RootScope rootScope, Logger log) { |
+ rootScope.context['foo'] = 12; |
+ rootScope.context['bar'] = 34; |
+ rootScope.watch('[foo, bar]', (v, o) => log([v, o])); |
+ expect(log).toEqual([]); |
+ rootScope.apply(); |
+ expect(log).toEqual([[[12, 34], null]]); |
+ log.clear(); |
- it(r'should not infinitely digest when current value is NaN', inject((RootScope rootScope) { |
- rootScope.context['nan'] = double.NAN; |
- rootScope.watch('nan', (_, __) => null); |
+ rootScope.context['foo'] = 56; |
+ rootScope.context['bar'] = 78; |
+ rootScope.apply(); |
+ expect(log).toEqual([[[56, 78], [12, 34]]]); |
+ }); |
- expect(() { |
- rootScope.digest(); |
- }).not.toThrow(); |
- })); |
+ it('should properly watch array of fields 2', (RootScope rootScope, Logger log) { |
+ rootScope.context['foo'] = () => 12; |
+ rootScope.watch('foo()', (v, o) => log(v)); |
+ expect(log).toEqual([]); |
+ rootScope.apply(); |
+ expect(log).toEqual([12]); |
+ }); |
- it(r'should prevent infinite digest and should log firing expressions', inject((RootScope rootScope) { |
- rootScope.context['a'] = 0; |
- rootScope.context['b'] = 0; |
- rootScope.watch('a', (a, __) => rootScope.context['a'] = a + 1); |
- rootScope.watch('b', (b, __) => rootScope.context['b'] = b + 1); |
- expect(() { |
- rootScope.digest(); |
- }).toThrow('Model did not stabilize in 5 digests. ' |
- 'Last 3 iterations:\n' |
- 'a: 2 <= 1, b: 2 <= 1\n' |
- 'a: 3 <= 2, b: 3 <= 2\n' |
- 'a: 4 <= 3, b: 4 <= 3'); |
- })); |
- |
- |
- it(r'should always call the watchr with newVal and oldVal equal on the first run', |
- inject((RootScope rootScope) { |
- var log = []; |
- var logger = (newVal, oldVal) { |
- var val = (newVal == oldVal || (newVal != oldVal && oldVal != newVal)) ? newVal : 'xxx'; |
- log.add(val); |
- }; |
- |
- rootScope.context['nanValue'] = double.NAN; |
- rootScope.context['nullValue'] = null; |
- rootScope.context['emptyString'] = ''; |
- rootScope.context['falseValue'] = false; |
- rootScope.context['numberValue'] = 23; |
- |
- rootScope.watch('nanValue', logger); |
- rootScope.watch('nullValue', logger); |
- rootScope.watch('emptyString', logger); |
- rootScope.watch('falseValue', logger); |
- rootScope.watch('numberValue', logger); |
- |
- rootScope.digest(); |
- expect(log.removeAt(0).isNaN).toEqual(true); //jasmine's toBe and toEqual don't work well with NaNs |
- expect(log).toEqual([null, '', false, 23]); |
- log = []; |
- rootScope.digest(); |
- expect(log).toEqual([]); |
- })); |
- |
- |
- it('should properly watch canstants', inject((RootScope rootScope, Logger log) { |
- rootScope.watch('[1, 2]', (v, o) => log([v, o])); |
- expect(log).toEqual([]); |
- rootScope.apply(); |
- expect(log).toEqual([[[1, 2], null]]); |
- })); |
- |
- |
- it('should properly watch array of fields', inject((RootScope rootScope, Logger log) { |
- rootScope.context['foo'] = 12; |
- rootScope.context['bar'] = 34; |
- rootScope.watch('[foo, bar]', (v, o) => log([v, o])); |
- expect(log).toEqual([]); |
- rootScope.apply(); |
- expect(log).toEqual([[[12, 34], null]]); |
- log.clear(); |
- |
- rootScope.context['foo'] = 56; |
- rootScope.context['bar'] = 78; |
- rootScope.apply(); |
- expect(log).toEqual([[[56, 78], [12, 34]]]); |
- })); |
- |
- |
- it('should properly watch array of fields2', inject((RootScope rootScope, Logger log) { |
- rootScope.watch('[ctrl.foo, ctrl.bar]', (v, o) => log([v, o])); |
- expect(log).toEqual([]); |
- rootScope.apply(); |
- expect(log).toEqual([[[null, null], null]]); |
- log.clear(); |
- |
- rootScope.context['ctrl'] = {'foo': 56, 'bar': 78}; |
- rootScope.apply(); |
- expect(log).toEqual([[[56, 78], [null, null]]]); |
- })); |
- }); |
+ it('should properly watch array of fields 3', (RootScope rootScope, Logger log) { |
+ rootScope.context['foo'] = 'abc'; |
+ rootScope.watch('foo.contains("b")', (v, o) => log([v, o])); |
+ expect(log).toEqual([]); |
+ rootScope.apply(); |
+ expect(log).toEqual([[true, null]]); |
+ log.clear(); |
+ }); |
- describe('special binding modes', () { |
- it('should bind one time', inject((RootScope rootScope, Logger log) { |
- rootScope.watch('foo', (v, _) => log('foo:$v')); |
- rootScope.watch(':foo', (v, _) => log(':foo:$v')); |
- rootScope.watch('::foo', (v, _) => log('::foo:$v')); |
+ it('should not trigger new watcher in the flush where it was added', (Scope scope) { |
+ var log = [] ; |
+ scope.context['foo'] = () => 'foo'; |
+ scope.context['name'] = 'misko'; |
+ scope.context['list'] = [2, 3]; |
+ scope.context['map'] = {'bar': 'chocolate'}; |
+ scope.watch('1', (value, __) { |
+ expect(value).toEqual(1); |
+ scope.watch('foo()', (value, __) => log.add(value)); |
+ scope.watch('name', (value, __) => log.add(value)); |
+ scope.watch('(foo() + "-" + name).toUpperCase()', (value, __) => log.add(value)); |
+ scope.watch('list', (value, __) => log.add(value)); |
+ scope.watch('map', (value, __) => log.add(value)); |
+ }); |
+ scope.apply(); |
+ expect(log).toEqual(['foo', 'misko', 'FOO-MISKO', [2, 3], {'bar': 'chocolate'}]); |
+ }); |
- rootScope.apply(); |
- expect(log).toEqual(['foo:null']); |
- log.clear(); |
- rootScope.context['foo'] = true; |
- rootScope.apply(); |
- expect(log).toEqual(['foo:true', ':foo:true', '::foo:true']); |
- log.clear(); |
+ it('should allow multiple nested watches', (RootScope scope) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ scope.watch('1', (_, __) { |
+ // make this deeper then ScopeTTL; |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ }); |
+ expect(scope.apply).not.toThrow(); |
+ }); |
- rootScope.context['foo'] = 123; |
- rootScope.apply(); |
- expect(log).toEqual(['foo:123', ':foo:123']); |
- log.clear(); |
- rootScope.context['foo'] = null; |
- rootScope.apply(); |
- expect(log).toEqual(['foo:null']); |
- log.clear(); |
- })); |
- }); |
+ it('should properly watch array of fields 4', (RootScope rootScope, Logger log) { |
+ rootScope.watch('[ctrl.foo, ctrl.bar]', (v, o) => log([v, o])); |
+ expect(log).toEqual([]); |
+ rootScope.apply(); |
+ expect(log).toEqual([[[null, null], null]]); |
+ log.clear(); |
+ rootScope.context['ctrl'] = {'foo': 56, 'bar': 78}; |
+ rootScope.apply(); |
+ expect(log).toEqual([[[56, 78], [null, null]]]); |
+ }); |
+ }); |
- describe('runAsync', () { |
- it(r'should run callback before watch', inject((RootScope rootScope) { |
- var log = ''; |
- rootScope.runAsync(() { log += 'parent.async;'; }); |
- rootScope.watch('value', (_, __) { log += 'parent.digest;'; }); |
- rootScope.digest(); |
- expect(log).toEqual('parent.async;parent.digest;'); |
- })); |
- |
- it(r'should cause a digest rerun', inject((RootScope rootScope) { |
- rootScope.context['log'] = ''; |
- rootScope.context['value'] = 0; |
- // NOTE(deboer): watch listener string functions not yet supported |
- //rootScope.watch('value', 'log = log + ".";'); |
- rootScope.watch('value', (_, __) { rootScope.context['log'] += "."; }); |
- rootScope.watch('init', (_, __) { |
- rootScope.runAsync(() => rootScope.eval('value = 123; log = log + "=" ')); |
- expect(rootScope.context['value']).toEqual(0); |
- }); |
- rootScope.digest(); |
- expect(rootScope.context['log']).toEqual('.=.'); |
- })); |
- |
- it(r'should run async in the same order as added', inject((RootScope rootScope) { |
- rootScope.context['log'] = ''; |
- rootScope.runAsync(() => rootScope.eval("log = log + 1")); |
- rootScope.runAsync(() => rootScope.eval("log = log + 2")); |
- rootScope.digest(); |
- expect(rootScope.context['log']).toEqual('12'); |
- })); |
- }); |
+ describe('special binding modes', () { |
+ it('should bind one time', (RootScope rootScope, Logger log) { |
+ rootScope.watch('foo', (v, _) => log('foo:$v')); |
+ rootScope.watch(':foo', (v, _) => log(':foo:$v')); |
+ rootScope.watch('::foo', (v, _) => log('::foo:$v')); |
+ |
+ rootScope.apply(); |
+ expect(log).toEqual(['foo:null']); |
+ log.clear(); |
+ |
+ rootScope.context['foo'] = true; |
+ rootScope.apply(); |
+ expect(log).toEqual(['foo:true', ':foo:true', '::foo:true']); |
+ log.clear(); |
+ |
+ rootScope.context['foo'] = 123; |
+ rootScope.apply(); |
+ expect(log).toEqual(['foo:123', ':foo:123']); |
+ log.clear(); |
+ |
+ rootScope.context['foo'] = null; |
+ rootScope.apply(); |
+ expect(log).toEqual(['foo:null']); |
+ log.clear(); |
+ }); |
+ }); |
+ |
+ |
+ describe('runAsync', () { |
+ it(r'should run callback before watch', (RootScope rootScope) { |
+ var log = ''; |
+ rootScope.runAsync(() { log += 'parent.async;'; }); |
+ rootScope.watch('value', (_, __) { log += 'parent.digest;'; }); |
+ rootScope.digest(); |
+ expect(log).toEqual('parent.async;parent.digest;'); |
+ }); |
+ |
+ it(r'should cause a digest rerun', (RootScope rootScope) { |
+ rootScope.context['log'] = ''; |
+ rootScope.context['value'] = 0; |
+ // NOTE(deboer): watch listener string functions not yet supported |
+ //rootScope.watch('value', 'log = log + ".";'); |
+ rootScope.watch('value', (_, __) { rootScope.context['log'] += "."; }); |
+ rootScope.watch('init', (_, __) { |
+ rootScope.runAsync(() => rootScope.eval('value = 123; log = log + "=" ')); |
+ expect(rootScope.context['value']).toEqual(0); |
+ }); |
+ rootScope.digest(); |
+ expect(rootScope.context['log']).toEqual('.=.'); |
+ }); |
+ |
+ it(r'should run async in the same order as added', (RootScope rootScope) { |
+ rootScope.context['log'] = ''; |
+ rootScope.runAsync(() => rootScope.eval("log = log + 1")); |
+ rootScope.runAsync(() => rootScope.eval("log = log + 2")); |
+ rootScope.digest(); |
+ expect(rootScope.context['log']).toEqual('12'); |
+ }); |
+ }); |
- describe('domRead/domWrite', () { |
- it(r'should run writes before reads', () { |
- module((Module module) { |
+ |
+ describe('domRead/domWrite', () { |
+ beforeEachModule((Module module) { |
module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
}); |
- inject((RootScope rootScope, Logger logger, ExceptionHandler e) { |
+ |
+ it(r'should run writes before reads', (RootScope rootScope, Logger logger, ExceptionHandler e) { |
LoggingExceptionHandler exceptionHandler = e as LoggingExceptionHandler; |
rootScope.domWrite(() { |
logger('write1'); |
@@ -1277,7 +1449,8 @@ main() => describe('scope', () { |
rootScope.domWrite(() => logger('write3')); |
throw 'read1'; |
}); |
- rootScope.watch('value', (_, __) => logger('observe'), readOnly: true); |
+ rootScope.watch('value', (_, __) => logger('observe'), |
+ canChangeModel: false); |
rootScope.flush(); |
expect(logger).toEqual(['write1', 'write2', 'observe', 'read1', 'read2', 'write3']); |
expect(exceptionHandler.errors.length).toEqual(2); |
@@ -1285,28 +1458,24 @@ main() => describe('scope', () { |
expect(exceptionHandler.errors[1].error).toEqual('read1'); |
}); |
}); |
- }); |
- describe('exceptionHander', () { |
- it('should call ExceptionHandler on zone errors', () { |
- module((Module module) { |
+ describe('exceptionHander', () { |
+ beforeEachModule((Module module) { |
module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
}); |
- async((inject((RootScope rootScope, NgZone zone, ExceptionHandler e) { |
+ |
+ it('should call ExceptionHandler on zone errors', |
+ async((RootScope rootScope, VmTurnZone zone, ExceptionHandler e) { |
zone.run(() { |
scheduleMicrotask(() => throw 'my error'); |
}); |
var errors = (e as LoggingExceptionHandler).errors; |
expect(errors.length).toEqual(1); |
expect(errors.first.error).toEqual('my error'); |
- }))); |
- }); |
+ })); |
- it('should call ExceptionHandler on digest errors', () { |
- module((Module module) { |
- module.type(ExceptionHandler, implementedBy: LoggingExceptionHandler); |
- }); |
- async((inject((RootScope rootScope, NgZone zone, ExceptionHandler e) { |
+ it('should call ExceptionHandler on digest errors', |
+ async((RootScope rootScope, VmTurnZone zone, ExceptionHandler e) { |
rootScope.context['badOne'] = () => new Map(); |
rootScope.watch('badOne()', (_, __) => null); |
@@ -1317,57 +1486,140 @@ main() => describe('scope', () { |
var errors = (e as LoggingExceptionHandler).errors; |
expect(errors.length).toEqual(1); |
expect(errors.first.error, startsWith('Model did not stabilize')); |
- }))); |
+ })); |
+ }); |
+ |
+ describe('logging', () { |
+ it('should log a message on digest if reporting is enabled', (RootScope rootScope, |
+ Injector injector) { |
+ ScopeStatsConfig config = injector.get(ScopeStatsConfig); |
+ config.emit = true; |
+ rootScope.digest(); |
+ expect((injector.get(ScopeStatsEmitter) as MockScopeStatsEmitter).invoked) |
+ .toEqual(true); |
+ }); |
+ |
+ it('should log a message on flush if reporting is enabled', (RootScope rootScope, |
+ Injector injector) { |
+ ScopeStatsConfig config = injector.get(ScopeStatsConfig); |
+ config.emit = true; |
+ rootScope.flush(); |
+ expect((injector.get(ScopeStatsEmitter) as MockScopeStatsEmitter).invoked) |
+ .toEqual(true); |
+ }); |
+ |
+ it('should not log a message on digest if reporting is disabled', (RootScope rootScope, |
+ Injector injector) { |
+ rootScope.digest(); |
+ expect((injector.get(ScopeStatsEmitter) as MockScopeStatsEmitter).invoked) |
+ .toEqual(false); |
+ }); |
+ |
+ it('should not log a message on flush if reporting is disabled', (RootScope rootScope, |
+ Injector injector) { |
+ rootScope.flush(); |
+ expect((injector.get(ScopeStatsEmitter) as MockScopeStatsEmitter).invoked) |
+ .toEqual(false); |
+ }); |
+ |
+ it('can be turned on at runtime', (RootScope rootScope, Injector injector) { |
+ rootScope.digest(); |
+ expect((injector.get(ScopeStatsEmitter) as MockScopeStatsEmitter).invoked) |
+ .toEqual(false); |
+ ScopeStatsConfig config = injector.get(ScopeStatsConfig); |
+ config.emit = true; |
+ rootScope.digest(); |
+ expect((injector.get(ScopeStatsEmitter) as MockScopeStatsEmitter).invoked) |
+ .toEqual(true); |
+ }); |
}); |
}); |
-}); |
+} |
+ |
+@Formatter(name: 'identity') |
+class _IdentityFilter { |
+ Logger logger; |
+ _IdentityFilter(this.logger); |
+ call(v) { |
+ logger('identity'); |
+ return v; |
+ } |
+} |
+ |
+@Formatter(name: 'keys') |
+class _MapKeys { |
+ Logger logger; |
+ _MapKeys(this.logger); |
+ call(Map m) { |
+ logger('keys'); |
+ return m.keys; |
+ } |
+} |
-@NgFilter(name: 'multiply') |
+@Formatter(name: 'multiply') |
class _MultiplyFilter { |
call(a, b) => a * b; |
} |
-@NgFilter(name: 'listHead') |
+@Formatter(name: 'listHead') |
class _ListHeadFilter { |
Logger logger; |
- _ListHeadFilter(Logger this.logger); |
+ _ListHeadFilter(this.logger); |
call(list, head) { |
logger('listHead'); |
return [head]..addAll(list); |
} |
} |
- |
-@NgFilter(name: 'listTail') |
+@Formatter(name: 'listTail') |
class _ListTailFilter { |
Logger logger; |
- _ListTailFilter(Logger this.logger); |
+ _ListTailFilter(this.logger); |
call(list, tail) { |
logger('listTail'); |
return new List.from(list)..add(tail); |
} |
} |
-@NgFilter(name: 'sort') |
+@Formatter(name: 'sort') |
class _SortFilter { |
Logger logger; |
- _SortFilter(Logger this.logger); |
+ _SortFilter(this.logger); |
call(list) { |
logger('sort'); |
return new List.from(list)..sort(); |
} |
} |
-@NgFilter(name:'newFilter') |
+@Formatter(name:'newFilter') |
class FilterOne { |
call(String str) { |
return '$str 1'; |
} |
} |
-@NgFilter(name:'newFilter') |
+@Formatter(name:'newFilter') |
class FilterTwo { |
call(String str) { |
return '$str 2'; |
} |
} |
+ |
+class MockScopeStatsEmitter implements ScopeStatsEmitter { |
+ bool invoked = false; |
+ |
+ void emitMessage(String message) {} |
+ |
+ void emitSummary(List<int> digestTimes, int flushPhaseDuration, |
+ int assertFlushPhaseDuration) {} |
+ |
+ void emit(String phaseOrLoopNo, AvgStopwatch fieldStopwatch, |
+ AvgStopwatch evalStopwatch, AvgStopwatch processStopwatch) { |
+ invoked = true; |
+ } |
+} |
+ |
+class UnstableList { |
+ List get list => new List.generate(3, (i) => i); |
+} |
+ |