AngularJS $provider and $injector and bootstrapping - angularjs

I've been trying to get into the nitty-gritty with angular DI and really the bootstrap process at large, and I am a bit confused as to where things really happen. In my mind, the events are in this order.
App starts.
$provider registers service providers.
In the config phase, the providers can be configured.
Now is where I am lost.
The $injector, now having access to all the configured providers from $provide, calls the constructor functions (the $get function in each provider) to instantiate service instances.
Also, if that process is correct, how does the $injector handle cases where a service depends on another service?

Services are only instantiated at the moment when they are needed, rather than during Angular's initiation. For example, if you have a controller that isn't activated yet and it depends on services which haven't yet been used, those services will be instantiated and injected whenever that controller becomes active (like changing to a view that uses it). From then on, the same instance of each service will be used.
The same is true of services that depend on other services. All dependencies of anything are resolved before it is instantiated, so if a dependency has dependencies, the same process is applied (all of that dependency's dependencies will be instantiated first, and so on).
If a circular dependency is found (service foo has a dependency that depends on service foo), Angular will throw an exception and the functionality of those services will have to be refactored into different services that will not have this kind of circular chain.

Related

Selectively Mock Services when Testing Angular with Karma

While there have been many questions around mocking an individual Angular service in Karma, I am having an issue with making my mocks more ubiquitous throughout testing my application.
In my current setup, I have a module called serviceMocks that includes a factory with a mock of each service in the application.
Contrived example:
angular.module('serviceMocks',['ngMock'])
.factory('myServiceOne', function() {...})
.factory('myServiceTwo', function($httpBackend,$q) {...})
This works great when testing controllers and directives which may use one or more services as a dependency. I include my app's module and the serviceMocks module within my testfile, and each service is properly substituted.
beforeEach(module('myApp'));
beforeEach(module('serviceMocks'));
it('properly substitutes mocks throughout my tests', function() {...});
However, when testing a service itself I cannot include the serviceMocks module, as the service I am testing is substituted by its mock making the tests useless. However, I would still like all other services mocked as a service may depend on one or more services for its execution.
One way I thought of doing this was to make my service mocks globally available, perhaps by attaching an object to window that holds the mocks. I could then include the mocks individually when testing services like so:
beforeEach(module('myApp', function($provide) {
$provide.value('myServiceOne',window.mocks.myServiceOneMock);
$provide.value('myServiceTwo',window.mocks.myServiceTwoMock);
});
However this approach did not work, because some of the mocks use $q or other angular services to function properly, and these services are not properly injected when simply attaching the factory object to the window.
I am looking for a way to test services while having a single location to define mocks for all services. Possibilities I imagine but have been unable to succeed with:
A) Have the serviceMocks module's .run() block run before the
config stage for myApp's module. (In which case I could attach
each service to the window as the angular dependencies would be
properly injected, and inject each as shown above)
B) Be able to override the service that I'm testing with its actual implementation in the test files of each service
C) Otherwise be able to define and access these mocks globally, while still ensuring each mock has access to certain angular services such as $q.
The question contains a clue to the answer. If serviceMocks module causes design issues, using it is a mistake.
The proper pattern is to have one module per unit (mocked service in this case). ngMock is not needed, it is loaded automatically in Jasmine tests. The modules can be used one by one:
beforeEach(module('app', 'serviceOneMock', 'serviceTwoMock'));
Or joined together:
angular.module('serviceMocks', ['serviceOneMock', 'serviceTwoMock'])
There are not so many cases when serviceMocks module should exist at all. Just because a decision which services should be mocked and which should not is made for each describe block.
Most times mocked services are individual for current spec or depend on local variables. In this case the services are mocked in-place:
var promiseResult;
beforeEach(module('app'));
beforeEach(module({ foo: 'instead of $provide.value(...)' });
beforeEach(($provide) => {
$provide.factory('bar', ($q) => {
return $q.resolve(promiseResult);
}
});
...
Doing this in dedicated serviceOneMock, etc. modules may require mocked services to be refactored any moment it becomes obvious they are too generic and don't suit the case well.
If mocked service is used more than once in specs with slightly different behaviour and results in WET tests, it is better to make a helper function that will generate it for current spec rather than hard-coding it to serviceOneMock, etc. modules.

Configuring shared services across multiple modules in AngularJS

My app is following John Papa's styleguide for AngularJS applications:
The styleguide emphasizes using a strongly modular approach to the design of the app. My question is about multiple configurations and their effect on shared services.
Suppose I have a main module like this:
angular.module("app", ["app.feature1"])
.config(function() {
// do some configuration here
console.log("app configured");
});
And a feature module that configures a shared angular service, let's say the $http service:
angular.module("app.feature1", [])
.config(function($http) {
// configure the $http service
console.log("feature1 configured");
});
Is my understanding correct, that the configuration by "feature1" will carry over to the main module, since the $http service is a singleton and therefore shared across modules? Or do I have to configure the $http service in the main module instead, because each module has it's own $http service instance?
Edit: I can confirm that dependency configs are carried over and are executed first. See David's jsfiddle example.
As a matter of best practice, you should configure services as early as possible, which is typically your main module (the app root), and preferably only once to avoid overlapping changes.
Since $http is a singleton (as you mentioned), any changes via configuration will be propagated throughout the application every time you inject $http.
It's also worth mentioning that configuration to services is First In First Out, meaning that if you have two configuration changes, the last-accessed configuration will be the one that is persisted to the service since the previous configuration will be overwritten if they are changing identical components of the service.
In your case, yes, the change to $http in your module will be extended to your main application and any other modules using $http.
Finally, in light of the comments, child dependency configs are resolved before parent configs, as demonstrated by this simple fiddle:
http://jsfiddle.net/maqzo6fv/
HTML:
<div ng-app="app"></div>
JS:
angular.module("app", ["app.feature1"])
.config(function() {
alert('main config');
});
angular.module("app.feature1", [])
.config(function() {
alert('child config');
});
The child config will call alert before main on every load.

AngularJS invokeQueue and configBlocks

AngularJs Source code deep dive - What does invokeQueue and configBlocks do during angularjs bootstrapping? I see they are passed to arguments for runInvokeQueue function inside loadModules.
configBlocks stores the list of services instantiated during module configuration:
angular.module("ng")._configBlocks[0][0]
invokeQueue stores the list of methods invoked after the module is loaded:
var foo = angular.module("ng");
foo.constant(alert)
foo._invokeQueue[0]
foo._invokeQueue[0][2][0]
The module definition is situated at the first lines of AngularJS source. As the documentation says, the life span of every module operation can be divided into two phases. The config phase and the run phase. The object exposed by calling the angular.module() constructor provides us with these two methods. The functionality of the run method is pretty obvious out of the source. It simply puts the config function passed to the private list of run blocks. The config method, on the contrary, is not so obvious. Here is, what the config method does:
The invokeLater private method inserts the combination of provider and its method to the internal module queue to be invoked later during the injector instantiation. The modules would be totally useless, if it weren't for the injector. The CreateInjector function is the concrete implementation and it has the private method loadModules.
The loadModules function does, among other, the kickoff of modules which are passed to it. It returns one array of all the run blocks of all modules which are dependent on each other. The injector calls them through its invoke method. Last but not least, the loadModules function, during its iteration through all dependent modules, calls their functions stored at _invokeQueue and _configBlock respectively. The run blocks are called in the last position. This means all services and methods of the modules are already exposed and ready for use. On the contrary, the config method only works with providers exposed by the module. The constructors of the providers are stored in the _invokeQueue of the module.
Two injectors
The first injector, that is not exposed publicly, is an injector of providers. The second one is an instance injector. The instance injector asks the provider cache for the constructors needed. Then it calls the proper part of the provider and creates an instance. The instance injector searches in the provider cache before asking for the provider injector. The module.provider method exposes the provider injector's provider method, which at a closer look says a lot about the life cycle of services.
Even other parts of angular constructs, like directives and controllers, are registered as providers in the provider's cache. The $compileProvider itself is then registered like any other provider through $provide.provider method. As a matter of fact, module.factory, module.service and module.provider store an instance in the provider cache as a first step. But it is an instance injector that we have at our disposal. The instance injector asks the provider cache as a first step and then calls the invoke method, which takes care of the dependencies.
References
Modules and injector
Configuring a Provider
fix(injector): invoke config blocks for module after all providers
Loading an AngularJS controller dynamically

Is there a way to specify a standard or default set of dependencies for every AngularJS module?

I'm new to AngularJS and have created some services, however a lot of these require some 'standard' dependencies
e.g. Logging ($log),
a shared data service (pub/sub service for sending messages between controllers), an error handling service etc.
Is there a way to specify that all my services will have these 'standard' dependencies, to avoid having a very long list of dependencies for controllers like this:
["$scope", "$http", "$log", "SharedDataService", "SharedErrorBusService"...
If so is this even sensible - for example could it create difficulties for automated testing?
When your controller declares so many dependencies it is a sign that your controller has too many responsibilities. Angular has other mechanisms for cross cutting features like http interceptors or delegates that could be useful in your case.

.config, .run, AppCtrl - where to put routes?

I wanted to find out the difference between the .config and .run functions in AngularJS. I was using my .config for setting up routes, but I did have some $on's for watching route change start and success events.
I then moved some of this code to .run as I was having some dependency injection problems in .config.
I finally moved some of this to a CommonAppController which I have set on my <body>.
I also had 2 .config's and it seemed to be running ok, but surely this isn't right?
Can anyone give a little insight on which method to use?
Configuration blocks and run blocks get executed at different points in the application bootstrap, and have different injection locals at their disposal. Here's a summary of what you can find in the AngularJS documentation.
Configuration blocks (registered with module.config()) get executed during provider registration, and can only be injected providers and constants (see module.provider() and module.constant()). This is typically where you would configure application-wide stuff, such as the $routeProvider. Stuff that needs to be configured before the services are created.
Run blocks (registered with module.run()) get executed after the injector has all the providers. Now, all instances and constants can be injected. This is typically where you would configure services, $rootScope, events and so on.
You can have multiple of either, and they are executed in the order they were registered to the module. Some people prefer to register a configuration block before every group of controllers to register the routes to these controller, for example.
The .config block is executed during the provider registration and configuration phase. It' a module level block.
The.run block is executed after the config block. It's used to inject services and constants.

Resources