diff options
| -rw-r--r-- | Rakefile | 1 | ||||
| -rw-r--r-- | src/Angular.js | 6 | ||||
| -rw-r--r-- | src/AngularPublic.js | 1 | ||||
| -rw-r--r-- | src/Compiler.js | 7 | ||||
| -rw-r--r-- | src/Injector.js | 59 | ||||
| -rw-r--r-- | src/Scope.js | 61 | ||||
| -rw-r--r-- | src/angular-bootstrap.js | 1 | ||||
| -rw-r--r-- | src/services.js | 67 | ||||
| -rw-r--r-- | src/widgets.js | 6 | ||||
| -rw-r--r-- | test/InjectorSpec.js | 71 | ||||
| -rw-r--r-- | test/ResourceSpec.js | 20 | ||||
| -rw-r--r-- | test/ScenarioSpec.js | 5 | ||||
| -rw-r--r-- | test/ScopeSpec.js | 75 | ||||
| -rw-r--r-- | test/ValidatorsTest.js | 3 | ||||
| -rw-r--r-- | test/directivesSpec.js | 2 | ||||
| -rw-r--r-- | test/servicesSpec.js | 171 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 4 | 
17 files changed, 347 insertions, 213 deletions
@@ -29,6 +29,7 @@ task :compile_scenario do        src/jqLite.js \        src/JSON.js \        src/Scope.js \ +      src/Injector.js \        src/Parser.js \        src/Resource.js \        src/Browser.js \ diff --git a/src/Angular.js b/src/Angular.js index f7351bdc..5bffac53 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -330,6 +330,10 @@ function escapeAttr(html) {        '"');  } +function concat(array1, array2, index) { +  return array1.concat(slice.call(array2, index, array2.length)); +} +  function bind(self, fn) {    var curryArgs = arguments.length > 2 ? slice.call(arguments, 2, arguments.length) : [];    if (typeof fn == $function) { @@ -403,7 +407,7 @@ function angularInit(config){      // TODO default to the source of angular.js      var scope = compile(window.document, _null, {'$config':config});      if (config.css) -      scope.$browser.addCss(config.base_url + config.css); +      scope.$inject('$browser').addCss(config.base_url + config.css);      scope.$init();    }  } diff --git a/src/AngularPublic.js b/src/AngularPublic.js index 617a7e2e..2b5d4fbc 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -21,6 +21,7 @@ extend(angular, {    'extend': extend,    'equals': equals,    'foreach': foreach, +  'injector': createInjector,    'noop':noop,    'bind':bind,    'toJson': toJson, diff --git a/src/Compiler.js b/src/Compiler.js index 0c80d3fc..a78a04c9 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -34,7 +34,7 @@ Template.prototype = {      foreach(this.inits, function(fn) {        queue.push(function() {          childScope.$tryEval(function(){ -          return fn.call(childScope, element); +          return childScope.$inject(fn, childScope, element);          }, element);        });      }); @@ -96,8 +96,7 @@ Compiler.prototype = {      return function(element, parentScope){        element = jqLite(element);        var scope = parentScope && parentScope.$eval ? -          parentScope : -          createScope(parentScope || {}, angularService); +          parentScope : createScope(parentScope);        return extend(scope, {          $element:element,          $init: function() { @@ -124,7 +123,7 @@ Compiler.prototype = {            text:function(text) {return jqLite(document.createTextNode(text));},            descend: function(value){ if(isDefined(value)) descend = value; return descend;},            directives: function(value){ if(isDefined(value)) directives = value; return directives;}, -          scope: function(value){ if(isDefined(value)) template.newScope = template.newScope || value ; return template.newScope;} +          scope: function(value){ if(isDefined(value)) template.newScope = template.newScope || value; return template.newScope;}          };      try {        priority = element.attr('ng:eval-order') || priority || 0; diff --git a/src/Injector.js b/src/Injector.js new file mode 100644 index 00000000..554e9089 --- /dev/null +++ b/src/Injector.js @@ -0,0 +1,59 @@ +/** + * Create an inject method + * @param providerScope provider's "this" + * @param providers a function(name) which returns provider function + * @param cache place where instances are saved for reuse + * @returns {Function} + */ +function createInjector(providerScope, providers, cache) { +  providers = providers || angularService; +  cache = cache || {}; +  providerScope = providerScope || {}; +  /** +   * injection function +   * @param value: string, array, object or function. +   * @param scope: optional function "this" +   * @param args: optional arguments to pass to function after injection +   *              parameters +   * @returns depends on value: +   *   string: return an instance for the injection key. +   *   array of keys: returns an array of instances. +   *   function: look at $inject property of function to determine instances +   *             and then call the function with instances and scope. Any +   *             additional arguments are passed on to function. +   *   object: initialize eager providers and publish them the ones with publish here. +   *   none:   same as object but use providerScope as place to publish. +   */ +  return function inject(value, scope, args){ +    var returnValue, provider, creation; +    if (isString(value)) { +      if (!cache.hasOwnProperty(value)) { +        provider = providers[value]; +        if (!provider) throw "Unknown provider for '"+value+"'."; +        cache[value] = inject(provider, providerScope); +      } +      returnValue = cache[value]; +    } else if (isArray(value)) { +      returnValue = []; +      foreach(value, function(name) { +        returnValue.push(inject(name)); +      }); +    } else if (isFunction(value)) { +      returnValue = inject(value.$inject || []); +      returnValue = value.apply(scope, concat(returnValue, arguments, 2)); +    } else if (isObject(value)) { +      foreach(providers, function(provider, name){ +        creation = provider.$creation; +        if (creation == 'eager') { +          inject(name); +        } +        if (creation == 'eager-published') { +          setter(value, name, inject(name)); +        } +      }); +    } else { +      returnValue = inject(providerScope); +    } +    return returnValue; +  }; +}
\ No newline at end of file diff --git a/src/Scope.js b/src/Scope.js index 3aaff361..ed608e95 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -108,20 +108,14 @@ function errorHandlerFor(element, error) {    elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error);  } -function createScope(parent, services, existing) { +function createScope(parent, providers, instanceCache) {    function Parent(){} -  function API(){} -  function Behavior(){} -    parent = Parent.prototype = (parent || {}); +  var instance = new Parent();    var evalLists = {sorted:[]};    var postList = [], postHash = {}, postId = 0; -  var servicesCache = extend({}, existing); -  var api = API.prototype = new Parent(); -  var behavior = Behavior.prototype = new API(); -  var instance = new Behavior(); -  extend(api, { +  extend(instance, {      'this': instance,      $id: (scopeId++),      $parent: parent, @@ -227,46 +221,29 @@ function createScope(parent, services, existing) {      },      $become: function(Class) { -      // remove existing -      foreach(behavior, function(value, key){ delete behavior[key]; }); -      foreach((Class || noop).prototype, function(fn, name){ -        behavior[name] = bind(instance, fn); -      }); -      (Class || noop).call(instance); - -      //TODO: backwards compatibility hack, remove when Feedback's init methods are removed -      if (behavior.hasOwnProperty('init')) { -        behavior.init(); +      if (isFunction(Class)) { +        instance.constructor = Class; +        foreach(Class.prototype, function(fn, name){ +          instance[name] = bind(instance, fn); +        }); +        instance.$inject.apply(instance, concat([Class, instance], arguments, 1));        } +    }, + +    $new: function(Class) { +      var child = createScope(instance); +      child.$become.apply(instance, concat([Class], arguments, 1)); +      instance.$onEval(child.$eval); +      return child;      }    });    if (!parent.$root) { -    api.$root = instance; -    api.$parent = instance; -  } - -  function inject(name){ -    var service = servicesCache[name], factory, args = []; -    if (isUndefined(service)) { -      factory = services[name]; -      if (!isFunction(factory)) -        throw "Don't know how to inject '" + name + "'."; -      foreach(factory.inject, function(dependency){ -        args.push(inject(dependency)); -      }); -      servicesCache[name] = service = factory.apply(instance, args); -    } -    return service; +    instance.$root = instance; +    instance.$parent = instance; +    (instance.$inject = createInjector(instance, providers, instanceCache))();    } -  foreach(services, function(_, name){ -    var service = inject(name); -    if (service) { -      setter(instance, name, service); -    } -  }); -    return instance;  } diff --git a/src/angular-bootstrap.js b/src/angular-bootstrap.js index 1f03b8a3..581f4ff9 100644 --- a/src/angular-bootstrap.js +++ b/src/angular-bootstrap.js @@ -41,6 +41,7 @@    addScript("/JSON.js");    addScript("/Compiler.js");    addScript("/Scope.js"); +  addScript("/Injector.js");    addScript("/jqLite.js");    addScript("/Parser.js");    addScript("/Resource.js"); diff --git a/src/services.js b/src/services.js index 9dc3b456..5b65f8fd 100644 --- a/src/services.js +++ b/src/services.js @@ -1,13 +1,19 @@  var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?([^\?#]+)(\?([^#]*))?(#(.*))?$/,      HASH_MATCH = /^([^\?]*)?(\?([^\?]*))?$/, -    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21}; +    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21}, +    EAGER = 'eager', +    EAGER_PUBLISHED = EAGER + '-published'; -angularService("$window", bind(window, identity, window)); -angularService("$document", function(window){ +function angularServiceInject(name, fn, inject, eager) { +  angularService(name, fn, {$inject:inject, $creation:eager}); +} + +angularServiceInject("$window", bind(window, identity, window), [], EAGER_PUBLISHED); +angularServiceInject("$document", function(window){    return jqLite(window.document); -}, {inject:['$window']}); +}, ['$window'], EAGER_PUBLISHED); -angularService("$location", function(browser){ +angularServiceInject("$location", function(browser){    var scope = this,        location = {parse:parseUrl, toString:toString, update:update},        lastLocation = {}; @@ -92,9 +98,9 @@ angularService("$location", function(browser){      update();      return location.href;    } -}, {inject: ['$browser']}); +}, ['$browser'], EAGER_PUBLISHED); -angularService("$log", function($window){ +angularServiceInject("$log", function($window){    var console = $window.console || {log: noop, warn: noop, info: noop, error: noop},        log = console.log || noop;    return { @@ -103,15 +109,15 @@ angularService("$log", function($window){      info: bind(console, console.info || log),      error: bind(console, console.error || log)    }; -}, {inject:['$window']}); +}, ['$window'], EAGER_PUBLISHED); -angularService('$exceptionHandler', function($log){ +angularServiceInject('$exceptionHandler', function($log){    return function(e) {      $log.error(e);    }; -}, {inject:['$log']}); +}, ['$log'], EAGER_PUBLISHED); -angularService("$hover", function(browser, document) { +angularServiceInject("$hover", function(browser, document) {    var tooltip, self = this, error, width = 300, arrowWidth = 10, body = jqLite(document[0].body);    browser.hover(function(element, show){      if (show && (error = element.attr(NG_EXCEPTION) || element.attr(NG_VALIDATION_ERROR))) { @@ -155,14 +161,13 @@ angularService("$hover", function(browser, document) {        tooltip = _null;      }    }); -}, {inject:['$browser', '$document']}); - +}, ['$browser', '$document'], EAGER);  /* Keeps references to all invalid widgets found during validation. Can be queried to find if there   * are invalid widgets currently displayed   */ -angularService("$invalidWidgets", function(){ +angularServiceInject("$invalidWidgets", function(){    var invalidWidgets = []; @@ -217,7 +222,7 @@ angularService("$invalidWidgets", function(){    }    return invalidWidgets; -}); +}, [], EAGER_PUBLISHED); @@ -244,7 +249,7 @@ function switchRouteMatcher(on, when, dstName) {    return match ? dst : _null;  } -angularService('$route', function(location){ +angularServiceInject('$route', function(location){    var routes = {},        onChange = [],        matcher = switchRouteMatcher, @@ -284,9 +289,9 @@ angularService('$route', function(location){    }    this.$watch(function(){return dirty + location.hash;}, updateRoute);    return $route; -}, {inject: ['$location']}); +}, ['$location']); -angularService('$xhr', function($browser, $error, $log){ +angularServiceInject('$xhr', function($browser, $error, $log){    var self = this;    return function(method, url, post, callback){      if (isFunction(post)) { @@ -315,15 +320,15 @@ angularService('$xhr', function($browser, $error, $log){        }      });    }; -}, {inject:['$browser', '$xhr.error', '$log']}); +}, ['$browser', '$xhr.error', '$log']); -angularService('$xhr.error', function($log){ +angularServiceInject('$xhr.error', function($log){    return function(request, response){      $log.error('ERROR: XHR: ' + request.url, request, response);    }; -}, {inject:['$log']}); +}, ['$log']); -angularService('$xhr.bulk', function($xhr, $error, $log){ +angularServiceInject('$xhr.bulk', function($xhr, $error, $log){    var requests = [],        scope = this;    function bulkXHR(method, url, post, callback) { @@ -371,9 +376,9 @@ angularService('$xhr.bulk', function($xhr, $error, $log){    };    this.$onEval(PRIORITY_LAST, bulkXHR.flush);    return bulkXHR; -}, {inject:['$xhr', '$xhr.error', '$log']}); +}, ['$xhr', '$xhr.error', '$log']); -angularService('$xhr.cache', function($xhr){ +angularServiceInject('$xhr.cache', function($xhr){    var inflight = {}, self = this;    function cache(method, url, post, callback, verifyCache){      if (isFunction(post)) { @@ -415,12 +420,12 @@ angularService('$xhr.cache', function($xhr){    cache.data = {};    cache.delegate = $xhr;    return cache; -}, {inject:['$xhr.bulk']}); +}, ['$xhr.bulk']); -angularService('$resource', function($xhr){ +angularServiceInject('$resource', function($xhr){    var resource = new ResourceFactory($xhr);    return bind(resource, resource.route); -}, {inject: ['$xhr.cache']}); +}, ['$xhr.cache']);  /** @@ -430,7 +435,7 @@ angularService('$resource', function($xhr){   * Only a simple Object is exposed and by adding or removing properties to/from this object, new   * cookies are created or deleted from the browser at the end of the current eval.   */ -angularService('$cookies', function($browser) { +angularServiceInject('$cookies', function($browser) {    var rootScope = this,        cookies = {},        lastCookies = {}, @@ -499,14 +504,14 @@ angularService('$cookies', function($browser) {        }      }    } -}, {inject: ['$browser']}); +}, ['$browser'], EAGER_PUBLISHED);  /**   * $cookieStore provides a key-value (string-object) storage that is backed by session cookies.   * Objects put or retrieved from this storage are automatically serialized or deserialized.   */ -angularService('$cookieStore', function($store) { +angularServiceInject('$cookieStore', function($store) {    return {      get: function(/**string*/key) { @@ -522,4 +527,4 @@ angularService('$cookieStore', function($store) {      }    }; -}, {inject: ['$cookies']}); +}, ['$cookies'], EAGER_PUBLISHED); diff --git a/src/widgets.js b/src/widgets.js index 90f6837d..c9dfab99 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -253,7 +253,7 @@ angularWidget('ng:include', function(element){      this.directives(true);    } else {      element[0]['ng:compiled'] = true; -    return function(element){ +    return extend(function(xhr, element){        var scope = this, childScope;        var changeCounter = 0;        function incrementChange(){ changeCounter++;} @@ -266,7 +266,7 @@ angularWidget('ng:include', function(element){          var src = this.$eval(srcExp),          useScope = this.$eval(scopeExp);          if (src) { -          scope.$xhr.cache('GET', src, function(code, response){ +          xhr('GET', src, function(code, response){              element.html(response);              childScope = useScope || createScope(scope);              compiler.compile(element)(element, childScope); @@ -276,7 +276,7 @@ angularWidget('ng:include', function(element){            element.html('');          }        }); -    }; +    }, {$inject:['$xhr.cache']});    }  }); diff --git a/test/InjectorSpec.js b/test/InjectorSpec.js new file mode 100644 index 00000000..ba0f27f7 --- /dev/null +++ b/test/InjectorSpec.js @@ -0,0 +1,71 @@ +describe('injector', function(){ +  var providers; +  var cache; +  var inject; +  var scope; + +  beforeEach(function(){ +    providers = extensionMap({}, 'providers'); +    cache = {}; +    scope = {}; +    inject = createInjector(scope, providers, cache); +  }); + +  it("should return same instance from calling provider", function(){ +    providers('text', function(){ return scope.name; }); +    scope.name = 'abc'; +    expect(inject('text')).toEqual('abc'); +    expect(cache.text).toEqual('abc'); +    scope.name = 'deleted'; +    expect(inject('text')).toEqual('abc'); +  }); + +  it("should return an array of instances", function(){ +    cache.a = 0; +    providers('b', function(){return 2;}); +    expect(inject(['a', 'b'])).toEqual([0,2]); +  }); + +  it("should call function", function(){ +    providers('a', function(){return 1;}); +    providers('b', function(){return 2;}); +    var args; +    function fn(a, b, c, d) { +      args = [this, a, b, c, d]; +    } +    fn.$inject = ['a', 'b']; +    inject(fn, {name:"this"}, 3, 4); +    expect(args).toEqual([{name:'this'}, 1, 2, 3, 4]); +  }); + +  it('should inject providers', function(){ +    providers('a', function(){return this.mi = 'Mi';}); +    providers('b', function(mi){return this.name = mi+'sko';}, {$inject:['a']}); +    expect(inject('b')).toEqual('Misko'); +    expect(scope).toEqual({mi:'Mi', name:'Misko'}); +  }); + +  it('should provide usefull message if no provider', function(){ +    assertThrows("Unknown provider for 'idontexist'.", function(){ +      inject('idontexist'); +    }); +  }); + +  it('should autostart eager services', function(){ +    var log = ''; +    providers('eager', function(){log += 'eager;';}, {$creation: 'eager'}); +    inject(); +    expect(log).toEqual('eager;'); +    expect(scope.eager).not.toBeDefined(); +  }); + + +  it('should return a list of published objects', function(){ +    var log = ''; +    providers('eager', function(){log += 'eager;'; return 'pub'; }, {$creation: 'eager-published'}); +    inject(); +    expect(log).toEqual('eager;'); +    expect(scope.eager).toEqual('pub'); + +  }); +});
\ No newline at end of file diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js index 435176b0..e258d5a3 100644 --- a/test/ResourceSpec.js +++ b/test/ResourceSpec.js @@ -162,26 +162,30 @@ describe("resource", function() {    it('should excersize full stack', function(){      var scope = angular.compile('<div></div>'); -    var Person = scope.$resource('/Person/:id'); -    scope.$browser.xhr.expectGET('/Person/123').respond('\n{\nname:\n"misko"\n}\n'); +    var $browser = scope.$inject('$browser'); +    var $resource = scope.$inject('$resource'); +    var Person = $resource('/Person/:id'); +    $browser.xhr.expectGET('/Person/123').respond('\n{\nname:\n"misko"\n}\n');      var person = Person.get({id:123}); -    scope.$browser.xhr.flush(); +    $browser.xhr.flush();      expect(person.name).toEqual('misko');    });    it('should return the same object when verifying the cache', function(){      var scope = angular.compile('<div></div>'); -    var Person = scope.$resource('/Person/:id', null, {query: {method:'GET', isArray: true, verifyCache: true}}); -    scope.$browser.xhr.expectGET('/Person/123').respond('[\n{\nname:\n"misko"\n}\n]'); +    var $browser = scope.$inject('$browser'); +    var $resource = scope.$inject('$resource'); +    var Person = $resource('/Person/:id', null, {query: {method:'GET', isArray: true, verifyCache: true}}); +    $browser.xhr.expectGET('/Person/123').respond('[\n{\nname:\n"misko"\n}\n]');      var person = Person.query({id:123}); -    scope.$browser.xhr.flush(); +    $browser.xhr.flush();      expect(person[0].name).toEqual('misko'); -    scope.$browser.xhr.expectGET('/Person/123').respond('[\n{\nname:\n"rob"\n}\n]'); +    $browser.xhr.expectGET('/Person/123').respond('[\n{\nname:\n"rob"\n}\n]');      var person2 = Person.query({id:123});      expect(person2[0].name).toEqual('misko');      var person2Cache = person2; -    scope.$browser.xhr.flush(); +    $browser.xhr.flush();      expect(person2Cache).toEqual(person2);      expect(person2[0].name).toEqual('rob');    }); diff --git a/test/ScenarioSpec.js b/test/ScenarioSpec.js index ede49a49..730019a2 100644 --- a/test/ScenarioSpec.js +++ b/test/ScenarioSpec.js @@ -43,9 +43,10 @@ describe("ScenarioSpec: configuration", function(){      var url = "http://server/#?book=moby";      var scope = compile("<div>{{$location}}</div>");      var $location = scope.$location; +    var $browser = scope.$inject('$browser');      expect($location.hashSearch.book).toBeUndefined(); -    scope.$browser.setUrl(url); -    scope.$browser.poll(); +    $browser.setUrl(url); +    $browser.poll();      expect($location.hashSearch.book).toEqual('moby');    });  }); diff --git a/test/ScopeSpec.js b/test/ScopeSpec.js index 66e9d489..4a207bf0 100644 --- a/test/ScopeSpec.js +++ b/test/ScopeSpec.js @@ -1,11 +1,27 @@  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(){ +  it('should have $get/$set/$parent', function(){      var parent = {};      var model = createScope(parent);      model.$set('name', 'adam'); @@ -138,40 +154,6 @@ describe('scope/model', function(){      });    }); -  describe('service injection', function(){ -    it('should inject services', function(){ -      var scope = createScope(null, { -        service:function(){ -        return "ABC"; -      } -      }); -      expect(scope.service).toEqual("ABC"); -    }); - -    it('should inject arugments', function(){ -      var scope = createScope(null, { -        name:function(){ -        return "misko"; -      }, -      greet: extend(function(name) { -        return 'hello ' + name; -      }, {inject:['name']}) -      }); -      expect(scope.greet).toEqual("hello misko"); -    }); - -    it('should throw error on missing dependency', function(){ -      try { -        createScope(null, { -          greet: extend(function(name) { -          }, {inject:['name']}) -        }); -      } catch(e) { -        expect(e).toEqual("Don't know how to inject 'name'."); -      } -    }); -  }); -    describe('getterFn', function(){      it('should get chain', function(){        expect(getterFn('a.b')(undefined)).toEqual(undefined); @@ -215,4 +197,27 @@ describe('scope/model', function(){      });    }); +  describe('$new', function(){ +    it('should $new should create new child scope and $become controller', function(){ +      var parent = createScope(null, {exampleService: function(){return '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, {exampleService: function(){return 'Example Service';}}); +      var child = createScope(parent); +      child.$become(temp.InjectController, 10); +      expect(child.localService).toEqual('Example Service'); +      expect(child.extra).toEqual(10); +    }); +  }); +  }); diff --git a/test/ValidatorsTest.js b/test/ValidatorsTest.js index 07f3e488..463e05de 100644 --- a/test/ValidatorsTest.js +++ b/test/ValidatorsTest.js @@ -112,6 +112,9 @@ describe('Validator:asynchronous', function(){      if (self.$element) self.$element.remove();      var oldCache = jqCache;      jqCache = {}; +    if (size(oldCache)) { +      dump(oldCache); +    }      expect(size(oldCache)).toEqual(0);    }); diff --git a/test/directivesSpec.js b/test/directivesSpec.js index 42a4879a..d8f04b29 100644 --- a/test/directivesSpec.js +++ b/test/directivesSpec.js @@ -282,7 +282,7 @@ describe("directives", function(){      });      it('should support nested controllers', function(){ -      temp.ChildGreeter = function() { +      temp.ChildGreeter = function(){          this.greeting = 'hey';          this.$root.childGreeter = this;        }; diff --git a/test/servicesSpec.js b/test/servicesSpec.js index c0101098..6c586d0a 100644 --- a/test/servicesSpec.js +++ b/test/servicesSpec.js @@ -1,13 +1,19 @@  describe("service", function(){ -  var scope, $xhrError, $log, mockServices; +  var scope, $xhrError, $log, mockServices, inject, $browser, $browserXhr, $xhrBulk, $xhr, $route;    beforeEach(function(){      $xhrError = jasmine.createSpy('$xhr.error');      $log = {}; -    scope = createScope(null, angularService, { +    scope = createScope({}, angularService, {        '$xhr.error': $xhrError,        '$log': $log      }); +    inject = scope.$inject; +    $browser = inject('$browser'); +    $browserXhr = $browser.xhr; +    $xhrBulk = scope.$inject('$xhr.bulk'); +    $xhr = scope.$inject('$xhr'); +    $route = scope.$inject('$route');    });    afterEach(function(){ @@ -38,7 +44,7 @@ describe("service", function(){        function warn(){ logger+= 'warn;'; }        function info(){ logger+= 'info;'; }        function error(){ logger+= 'error;'; } -      var scope = createScope(null, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}, $document:[{cookie:''}]}); +      var scope = createScope({}, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}, $document:[{cookie:''}]});        scope.$log.log();        scope.$log.warn();        scope.$log.info(); @@ -49,7 +55,7 @@ describe("service", function(){      it('should use console.log if other not present', function(){        var logger = "";        function log(){ logger+= 'log;'; } -      var scope = createScope(null, angularService, {$window: {console:{log:log}}, $document:[{cookie:''}]}); +      var scope = createScope({}, angularService, {$window: {console:{log:log}}, $document:[{cookie:''}]});        scope.$log.log();        scope.$log.warn();        scope.$log.info(); @@ -58,7 +64,7 @@ describe("service", function(){      });      it('should use noop if no console', function(){ -      var scope = createScope(null, angularService, {$window: {}, $document:[{cookie:''}]}); +      var scope = createScope({}, angularService, {$window: {}, $document:[{cookie:''}]});        scope.$log.log();        scope.$log.warn();        scope.$log.info(); @@ -182,49 +188,47 @@ describe("service", function(){        function BookChapter() {          this.log = '<init>';        } -      BookChapter.prototype.init = function(){ -        log += 'init();'; -      };        var scope = compile('<div></div>').$init(); -      scope.$route.when('/Book/:book/Chapter/:chapter', {controller: BookChapter, template:'Chapter.html'}); -      scope.$route.when('/Blank'); -      scope.$route.onChange(function(){ +      var $route = scope.$inject('$route'); +      $route.when('/Book/:book/Chapter/:chapter', {controller: BookChapter, template:'Chapter.html'}); +      $route.when('/Blank'); +      $route.onChange(function(){          log += 'onChange();';        });        scope.$location.parse('http://server#/Book/Moby/Chapter/Intro?p=123');        scope.$eval(); -      expect(log).toEqual('onChange();init();'); -      expect(scope.$route.current.params).toEqual({book:'Moby', chapter:'Intro', p:'123'}); -      expect(scope.$route.current.scope.log).toEqual('<init>'); -      var lastId = scope.$route.current.scope.$id; +      expect(log).toEqual('onChange();'); +      expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', p:'123'}); +      expect($route.current.scope.log).toEqual('<init>'); +      var lastId = $route.current.scope.$id;        log = '';        scope.$location.parse('http://server#/Blank?ignore');        scope.$eval();        expect(log).toEqual('onChange();'); -      expect(scope.$route.current.params).toEqual({ignore:true}); -      expect(scope.$route.current.scope.$id).not.toEqual(lastId); +      expect($route.current.params).toEqual({ignore:true}); +      expect($route.current.scope.$id).not.toEqual(lastId);        log = '';        scope.$location.parse('http://server#/NONE');        scope.$eval();        expect(log).toEqual('onChange();'); -      expect(scope.$route.current).toEqual(null); +      expect($route.current).toEqual(null); -      scope.$route.when('/NONE', {template:'instant update'}); +      $route.when('/NONE', {template:'instant update'});        scope.$eval(); -      expect(scope.$route.current.template).toEqual('instant update'); +      expect($route.current.template).toEqual('instant update');      });    });    describe('$resource', function(){      it('should publish to root scope', function(){ -      expect(scope.$resource).toBeTruthy(); +      expect(scope.$inject('$resource')).toBeTruthy();      });    });    describe('$xhr', function(){ -    var log, xhr; +    var log;      function callback(code, response) {        expect(code).toEqual(200);        log = log + toJson(response) + ';'; @@ -232,27 +236,26 @@ describe("service", function(){      beforeEach(function(){        log = ''; -      xhr = scope.$browser.xhr;      });      it('should forward the request to $browser and decode JSON', function(){ -      xhr.expectGET('/reqGET').respond('first'); -      xhr.expectGET('/reqGETjson').respond('["second"]'); -      xhr.expectPOST('/reqPOST', {post:'data'}).respond('third'); +      $browserXhr.expectGET('/reqGET').respond('first'); +      $browserXhr.expectGET('/reqGETjson').respond('["second"]'); +      $browserXhr.expectPOST('/reqPOST', {post:'data'}).respond('third'); -      scope.$xhr('GET', '/reqGET', null, callback); -      scope.$xhr('GET', '/reqGETjson', null, callback); -      scope.$xhr('POST', '/reqPOST', {post:'data'}, callback); +      $xhr('GET', '/reqGET', null, callback); +      $xhr('GET', '/reqGETjson', null, callback); +      $xhr('POST', '/reqPOST', {post:'data'}, callback); -      xhr.flush(); +      $browserXhr.flush();        expect(log).toEqual('"third";["second"];"first";');      });      it('should handle non 200 status codes by forwarding to error handler', function(){ -      xhr.expectPOST('/req', 'MyData').respond(500, 'MyError'); -      scope.$xhr('POST', '/req', 'MyData', callback); -      xhr.flush(); +      $browserXhr.expectPOST('/req', 'MyData').respond(500, 'MyError'); +      $xhr('POST', '/req', 'MyData', callback); +      $browserXhr.flush();        var cb = $xhrError.mostRecentCall.args[0].callback;        expect(typeof cb).toEqual($function);        expect($xhrError).wasCalledWith( @@ -262,45 +265,45 @@ describe("service", function(){      it('should handle exceptions in callback', function(){        $log.error = jasmine.createSpy('$log.error'); -      xhr.expectGET('/reqGET').respond('first'); -      scope.$xhr('GET', '/reqGET', null, function(){ throw "MyException"; }); -      xhr.flush(); +      $browserXhr.expectGET('/reqGET').respond('first'); +      $xhr('GET', '/reqGET', null, function(){ throw "MyException"; }); +      $browserXhr.flush();        expect($log.error).wasCalledWith("MyException");      });      describe('bulk', function(){        it('should collect requests', function(){ -        scope.$xhr.bulk.urls["/"] = {match:/.*/}; -        scope.$xhr.bulk('GET', '/req1', null, callback); -        scope.$xhr.bulk('POST', '/req2', {post:'data'}, callback); +        $xhrBulk.urls["/"] = {match:/.*/}; +        $xhrBulk('GET', '/req1', null, callback); +        $xhrBulk('POST', '/req2', {post:'data'}, callback); -        xhr.expectPOST('/', { +        $browserXhr.expectPOST('/', {            requests:[{method:'GET',  url:'/req1', data: null},                      {method:'POST', url:'/req2', data:{post:'data'} }]          }).respond([            {status:200, response:'first'},            {status:200, response:'second'}          ]); -        scope.$xhr.bulk.flush(function(){ log += 'DONE';}); -        xhr.flush(); +        $xhrBulk.flush(function(){ log += 'DONE';}); +        $browserXhr.flush();          expect(log).toEqual('"first";"second";DONE');        });        it('should handle non 200 status code by forwarding to error handler', function(){ -        scope.$xhr.bulk.urls['/'] = {match:/.*/}; -        scope.$xhr.bulk('GET', '/req1', null, callback); -        scope.$xhr.bulk('POST', '/req2', {post:'data'}, callback); +        $xhrBulk.urls['/'] = {match:/.*/}; +        $xhrBulk('GET', '/req1', null, callback); +        $xhrBulk('POST', '/req2', {post:'data'}, callback); -        xhr.expectPOST('/', { +        $browserXhr.expectPOST('/', {            requests:[{method:'GET',  url:'/req1', data: null},                      {method:'POST', url:'/req2', data:{post:'data'} }]          }).respond([            {status:404, response:'NotFound'},            {status:200, response:'second'}          ]); -        scope.$xhr.bulk.flush(function(){ log += 'DONE';}); -        xhr.flush(); +        $xhrBulk.flush(function(){ log += 'DONE';}); +        $browserXhr.flush();          expect($xhrError).wasCalled();          var cb = $xhrError.mostRecentCall.args[0].callback; @@ -315,29 +318,29 @@ describe("service", function(){      describe('cache', function(){        var cache; -      beforeEach(function(){ cache = scope.$xhr.cache; }); +      beforeEach(function(){ cache = scope.$inject('$xhr.cache'); });        it('should cache requests', function(){ -        xhr.expectGET('/url').respond('first'); +        $browserXhr.expectGET('/url').respond('first');          cache('GET', '/url', null, callback); -        xhr.flush(); -        xhr.expectGET('/url').respond('ERROR'); +        $browserXhr.flush(); +        $browserXhr.expectGET('/url').respond('ERROR');          cache('GET', '/url', null, callback); -        xhr.flush(); +        $browserXhr.flush();          expect(log).toEqual('"first";"first";');          cache('GET', '/url', null, callback, false); -        xhr.flush(); +        $browserXhr.flush();          expect(log).toEqual('"first";"first";"first";');        });        it('should first return cache request, then return server request', function(){ -        xhr.expectGET('/url').respond('first'); +        $browserXhr.expectGET('/url').respond('first');          cache('GET', '/url', null, callback, true); -        xhr.flush(); -        xhr.expectGET('/url').respond('ERROR'); +        $browserXhr.flush(); +        $browserXhr.expectGET('/url').respond('ERROR');          cache('GET', '/url', null, callback, true);          expect(log).toEqual('"first";"first";'); -        xhr.flush(); +        $browserXhr.flush();          expect(log).toEqual('"first";"first";"ERROR";');        }); @@ -350,12 +353,12 @@ describe("service", function(){        });        it('should keep track of in flight requests and request only once', function(){ -        scope.$xhr.bulk.urls['/bulk'] = { +        scope.$inject('$xhr.bulk').urls['/bulk'] = {            match:function(url){              return url == '/url';            }          }; -        xhr.expectPOST('/bulk', { +        $browserXhr.expectPOST('/bulk', {            requests:[{method:'GET',  url:'/url', data: null}]          }).respond([            {status:200, response:'123'} @@ -363,12 +366,12 @@ describe("service", function(){          cache('GET', '/url', null, callback);          cache('GET', '/url', null, callback);          cache.delegate.flush(); -        xhr.flush(); +        $browserXhr.flush();          expect(log).toEqual('"123";"123";');        });        it('should clear cache on non GET', function(){ -        xhr.expectPOST('abc', {}).respond({}); +        $browserXhr.expectPOST('abc', {}).respond({});          cache.data.url = {value:123};          cache('POST', 'abc', {});          expect(cache.data.url).toBeUndefined(); @@ -380,12 +383,12 @@ describe("service", function(){    describe('$cookies', function() { -    var scope; +    var scope, $browser;      beforeEach(function() { -      var browser = new MockBrowser(); -      browser.cookieHash['preexisting'] = 'oldCookie'; -      scope = createScope(null, angularService, {$browser: browser}); +      $browser = new MockBrowser(); +      $browser.cookieHash['preexisting'] = 'oldCookie'; +      scope = createScope(null, angularService, {$browser: $browser});      }); @@ -393,19 +396,19 @@ describe("service", function(){          function(){        expect(scope.$cookies).toEqual({'preexisting': 'oldCookie'}); -      // access internal cookie storage of the browser mock directly to simulate behavior of  +      // access internal cookie storage of the browser mock directly to simulate behavior of        // document.cookie -      scope.$browser.cookieHash['brandNew'] = 'cookie'; -      scope.$browser.poll(); +      $browser.cookieHash['brandNew'] = 'cookie'; +      $browser.poll();        expect(scope.$cookies).toEqual({'preexisting': 'oldCookie', 'brandNew':'cookie'}); -      scope.$browser.cookieHash['brandNew'] = 'cookie2'; -      scope.$browser.poll(); +      $browser.cookieHash['brandNew'] = 'cookie2'; +      $browser.poll();        expect(scope.$cookies).toEqual({'preexisting': 'oldCookie', 'brandNew':'cookie2'}); -      delete scope.$browser.cookieHash['brandNew']; -      scope.$browser.poll(); +      delete $browser.cookieHash['brandNew']; +      $browser.poll();        expect(scope.$cookies).toEqual({'preexisting': 'oldCookie'});      }); @@ -414,13 +417,13 @@ describe("service", function(){        scope.$cookies.oatmealCookie = 'nom nom';        scope.$eval(); -      expect(scope.$browser.cookies()). +      expect($browser.cookies()).          toEqual({'preexisting': 'oldCookie', 'oatmealCookie':'nom nom'});        scope.$cookies.oatmealCookie = 'gone';        scope.$eval(); -      expect(scope.$browser.cookies()). +      expect($browser.cookies()).          toEqual({'preexisting': 'oldCookie', 'oatmealCookie': 'gone'});      }); @@ -428,7 +431,7 @@ describe("service", function(){      it('should ignore non-string values when asked to create a cookie', function() {        scope.$cookies.nonString = [1, 2, 3];        scope.$eval(); -      expect(scope.$browser.cookies()).toEqual({'preexisting': 'oldCookie'}); +      expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'});        expect(scope.$cookies).toEqual({'preexisting': 'oldCookie'});      }); @@ -438,21 +441,21 @@ describe("service", function(){        scope.$cookies.undefVal = undefined;        scope.$eval(); -      expect(scope.$browser.cookies()).toEqual({'preexisting': 'oldCookie'}); +      expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'});      });      it('should remove a cookie when a $cookies property is deleted', function() {        scope.$cookies.oatmealCookie = 'nom nom';        scope.$eval(); -      scope.$browser.poll(); -      expect(scope.$browser.cookies()). +      $browser.poll(); +      expect($browser.cookies()).          toEqual({'preexisting': 'oldCookie', 'oatmealCookie':'nom nom'});        delete scope.$cookies.oatmealCookie;        scope.$eval(); -      expect(scope.$browser.cookies()).toEqual({'preexisting': 'oldCookie'}); +      expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'});      }); @@ -485,13 +488,13 @@ describe("service", function(){      it('should serialize objects to json', function() {        scope.$cookieStore.put('objectCookie', {id: 123, name: 'blah'});        scope.$eval(); //force eval in test -      expect(scope.$browser.cookies()).toEqual({'objectCookie': '{"id":123,"name":"blah"}'}); +      expect($browser.cookies()).toEqual({'objectCookie': '{"id":123,"name":"blah"}'});      });      it('should deserialize json to object', function() { -      scope.$browser.cookies('objectCookie', '{"id":123,"name":"blah"}'); -      scope.$browser.poll(); +      $browser.cookies('objectCookie', '{"id":123,"name":"blah"}'); +      $browser.poll();        expect(scope.$cookieStore.get('objectCookie')).toEqual({id: 123, name: 'blah'});      }); @@ -499,7 +502,7 @@ describe("service", function(){      it('should delete objects from the store when remove is called', function() {        scope.$cookieStore.put('gonner', { "I'll":"Be Back"});        scope.$eval(); //force eval in test -      expect(scope.$browser.cookies()).toEqual({'gonner': '{"I\'ll":"Be Back"}'}); +      expect($browser.cookies()).toEqual({'gonner': '{"I\'ll":"Be Back"}'});      });    }); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index 80acc928..8f6ccaea 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -476,7 +476,7 @@ describe("widget", function(){        scope.childScope = createScope();        scope.childScope.name = 'misko';        scope.url = 'myUrl'; -      scope.$xhr.cache.data.myUrl = {value:'{{name}}'}; +      scope.$inject('$xhr.cache').data.myUrl = {value:'{{name}}'};        scope.$init();        expect(element.text()).toEqual('misko');      }); @@ -487,7 +487,7 @@ describe("widget", function(){        scope.childScope = createScope();        scope.childScope.name = 'igor';        scope.url = 'myUrl'; -      scope.$xhr.cache.data.myUrl = {value:'{{name}}'}; +      scope.$inject('$xhr.cache').data.myUrl = {value:'{{name}}'};        scope.$init();        expect(element.text()).toEqual('igor');  | 
