describe('scope/model', function(){ var temp; beforeEach(function() { temp = window.temp = {}; temp.InjectController = function(exampleService, extra) { this.localService = exampleService; this.extra = extra; this.$root.injectController = this; }; temp.InjectController.$inject = ["exampleService"]; }); afterEach(function() { window.temp = undefined; }); it('should create a scope with parent', function(){ var model = createScope({name:'Misko'}); expect(model.name).toEqual('Misko'); }); it('should have $get/$set/$parent', function(){ var parent = {}; var model = createScope(parent); model.$set('name', 'adam'); expect(model.name).toEqual('adam'); expect(model.$get('name')).toEqual('adam'); expect(model.$parent).toEqual(model); expect(model.$root).toEqual(model); }); it('should return noop function when LHS is undefined', function(){ var model = createScope(); expect(model.$eval('x.$filter()')).toEqual(undefined); }); describe('$eval', function(){ var model; beforeEach(function(){model = createScope();}); it('should eval function with correct this', function(){ model.$eval(function(){ this.name = 'works'; }); expect(model.name).toEqual('works'); }); it('should eval expression with correct this', function(){ model.$eval('name="works"'); expect(model.name).toEqual('works'); }); it('should not bind regexps', function(){ model.exp = /abc/; expect(model.$eval('exp')).toEqual(model.exp); }); it('should do nothing on empty string and not update view', function(){ var onEval = jasmine.createSpy('onEval'); model.$onEval(onEval); model.$eval(''); expect(onEval).wasNotCalled(); }); it('should ignore none string/function', function(){ model.$eval(null); model.$eval({}); model.$tryEval(null); model.$tryEval({}); }); }); describe('$watch', function(){ it('should watch an expression for change', function(){ var model = createScope(); model.oldValue = ""; var nameCount = 0, evalCount = 0; model.name = 'adam'; model.$watch('name', function(){ nameCount ++; }); model.$watch(function(){return model.name;}, function(newValue, oldValue){ this.newValue = newValue; this.oldValue = oldValue; }); model.$onEval(function(){evalCount ++;}); model.name = 'misko'; model.$eval(); expect(nameCount).toEqual(2); expect(evalCount).toEqual(1); expect(model.newValue).toEqual('misko'); expect(model.oldValue).toEqual('adam'); }); it('should eval with no arguments', function(){ var model = createScope(); var count = 0; model.$onEval(function(){count++;}); model.$eval(); expect(count).toEqual(1); }); it('should run listener upon registration by default', function() { var model = createScope(); var count = 0, nameNewVal = 'crazy val 1', nameOldVal = 'crazy val 2'; model.$watch('name', function(newVal, oldVal){ count ++; nameNewVal = newVal; nameOldVal = oldVal; }); expect(count).toBe(1); expect(nameNewVal).not.toBeDefined(); expect(nameOldVal).not.toBeDefined(); }); it('should not run listener upon registration if flag is passed in', function() { var model = createScope(); var count = 0, nameNewVal = 'crazy val 1', nameOldVal = 'crazy val 2'; model.$watch('name', function(newVal, oldVal){ count ++; nameNewVal = newVal; nameOldVal = oldVal; }, undefined, false); expect(count).toBe(0); expect(nameNewVal).toBe('crazy val 1'); expect(nameOldVal).toBe('crazy val 2'); }); }); describe('$bind', function(){ it('should curry a function with respect to scope', function(){ var model = createScope(); model.name = 'misko'; expect(model.$bind(function(){return this.name;})()).toEqual('misko'); }); }); describe('$tryEval', function(){ it('should report error using the provided error handler and $log.error', function(){ var scope = createScope(), errorLogs = scope.$service('$log').error.logs; scope.$tryEval(function(){throw "myError";}, function(error){ scope.error = error; }); expect(scope.error).toEqual('myError'); expect(errorLogs.shift()[0]).toBe("myError"); }); it('should report error on visible element', function(){ var element = jqLite('
'), scope = createScope(), errorLogs = scope.$service('$log').error.logs; scope.$tryEval(function(){throw "myError";}, element); expect(element.attr('ng-exception')).toEqual('myError'); expect(element.hasClass('ng-exception')).toBeTruthy(); expect(errorLogs.shift()[0]).toBe("myError"); }); it('should report error on $excetionHandler', function(){ var scope = createScope(null, {$exceptionHandler: $exceptionHandlerMockFactory}, {$log: $logMock}); scope.$tryEval(function(){throw "myError";}); expect(scope.$service('$exceptionHandler').errors.shift()).toEqual("myError"); expect(scope.$service('$log').error.logs.shift()).toEqual(["myError"]); }); }); // $onEval describe('$onEval', function(){ it("should eval using priority", function(){ var scope = createScope(); scope.log = ""; scope.$onEval('log = log + "middle;"'); scope.$onEval(-1, 'log = log + "first;"'); scope.$onEval(1, 'log = log + "last;"'); scope.$eval(); expect(scope.log).toEqual('first;middle;last;'); }); it("should have $root and $parent", function(){ var parent = createScope(); var scope = createScope(parent); expect(scope.$root).toEqual(parent); expect(scope.$parent).toEqual(parent); }); }); describe('getterFn', function(){ it('should get chain', function(){ expect(getterFn('a.b')(undefined)).toEqual(undefined); expect(getterFn('a.b')({})).toEqual(undefined); expect(getterFn('a.b')({a:null})).toEqual(undefined); expect(getterFn('a.b')({a:{}})).toEqual(undefined); expect(getterFn('a.b')({a:{b:null}})).toEqual(null); expect(getterFn('a.b')({a:{b:0}})).toEqual(0); expect(getterFn('a.b')({a:{b:'abc'}})).toEqual('abc'); }); it('should map type method on top of expression', function(){ expect(getterFn('a.$filter')({a:[]})('')).toEqual([]); }); it('should bind function this', function(){ expect(getterFn('a')({a:function($){return this.b + $;}, b:1})(2)).toEqual(3); }); }); describe('$new', function(){ it('should create new child scope and $become controller', function(){ var parent = createScope(null, angularService, {exampleService: 'Example Service'}); var child = parent.$new(temp.InjectController, 10); expect(child.localService).toEqual('Example Service'); expect(child.extra).toEqual(10); child.$onEval(function(){ this.run = true; }); parent.$eval(); expect(child.run).toEqual(true); }); }); describe('$become', function(){ it('should inject properties on controller defined in $inject', function(){ var parent = createScope(null, angularService, {exampleService: 'Example Service'}); var child = createScope(parent); child.$become(temp.InjectController, 10); expect(child.localService).toEqual('Example Service'); expect(child.extra).toEqual(10); }); }); });