| 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);
|
| +}
|
| +
|
|
|