How to work with third-party libraries when doing unit-testing? - angularjs

I'm a newbie when it comes to unit-testing, I've tried to do a unit-test with Karma and Jasmine from an app that already existed.
Basically the app has a lot of dependencies from different third-party libraries being used. So when I tried to create a unit-test a stumbled upon a lot of errors from Karma/Jasmine. One of them is the screenshot below:
From the screenshot, I'm getting an unknown provider: socketFactoryProvider, which I've traced down and found out that it belongs to the btford.socket-io module. So what I've did was to have a code like this to mock the dependencies:
// Set the app module
beforeEach(function () {
angular.module('btford.socket-io', []);
module('opensportsAdmin');
});
But I'm still getting an error (based on the screenshot).
So my question is, how can you work with third-party libraries for your unit-test? I'm kind of new and didn't find any articles that can help me with my problem.
Here's a reference to my code.

The best practice is to use one internal module for your app and one module for dependencies.
detailed explanation and example here:
Truly mocking providers

Related

Not able to use c8y.ui functionality on top of cumulocity's hello-core-api example application

I'm trying to use functionality provided c8y.ui module (http://resources.cumulocity.com/documentation/jssdk/latest/#/core/c8y.ui) in an application I'm building on top of Cumulocity's hello-core-api application (https://bitbucket.org/m2m/cumulocity-examples/src/0fbc406e849ecba3a01526ebef8d4d8bb1f7f374/hello-core-api).
However when I inject a dependancy from the c8y.ui module to my controller I get the following error message (when trying to inject c8yAlert as dependancy)
angular.js:9997 Error: [$injector:unpr] Unknown provider: c8yAlertProvider <- c8yAlert
Any ideas on how I could get the c8y.ui module working too?
Unfortunately, c8y.ui is not included in Smart apps toolkit. However you can use one of alert/notification javascript libraries out there (see here).
Edit: Nevermind, apparently it's included.
Basically, you are not supposed to use c8yAlert in Smart apps toolkit. Most of the stuff in c8y.ui rely on custom Cumulocity DOM, styles and combination of them in a particular way. If you need to display alerts/notifications, you should rely on 3rd party libraries.
c8yAlert is documented because you can use it in a Cumulocity plugin code.

Breeze Angular Service Not Configuring Breeze to Angular Promises

I cannot get the Breeze Angular service (http://www.getbreezenow.com/documentation/breeze-angular) to configure Breeze to use Angular promises, i.e., I can never get the useNgPromises() function within breeze.bridge.angular.js to log a message to the console and thus I assume Breeze is never configured to use Angular promises.
My JS files are loaded as follows:
angular.js (v 1.3.14)
angular-route.js (v.1.3.14)
q.js (v 1.1.2) - This is here because I kept getting errors that Q was undefined if I left this out. I don't know if it is necessary to load Q.js if I use Angular promises instead.
breeze.js (v 1.5.3)
breeze.bridge.angular.js (v 1.1.0)
app.js and other app-specific JS files
So far, that satisfies steps #1 and #2 from the "Install It" section of that Breeze page.
Per steps #3 and #4 on that Breeze page and comments in breeze.bridge.angular.js, this is what my app.js looks like:
window.myApp = angular.module("myApp", [
"breeze.angular"
])
.value("breeze", window.breeze)
.config(["$routeProvider", function ($routeProvider) {
// Routing code
}])
.run(['breeze', function (breeze) {}]);
As far as I can tell, that code matches the Example #1 code on that Breeze page and satisfies steps #3 and #4 on that Breeze page.
Then I have some basic views that use controllers and datacontext JS files, the latter of which inject the breeze object as a dependency. To test whether Breeze is actually executing the configuration to work with Angular promises, I edited the breeze.bridge.angular.js file such that the following statement is included as the first line in the useNgPromises() function:
console.log("Using Angular promises!");
When I run my app, I never see that in the console, so I assume the configuration is not happening.
Am I doing something wrong in the setup? If so, what?
You absolutely do NOT need Q.js; the fact that you see errors relating to that library is an indication of a configuration mistake.
I think you found the problem when you added .value("breeze", window.breeze).
That one line wipes out the definition of the breeze service established by the 'breeze.angular' module (defined in breeze.bridge.angular.js), thus preventing the configuration of breeze for $http and $q. Without that configuration, breeze looks for a promises implementation elsewhere ... hence the complaint about missing Q.js. So ... yes ... that line was a disaster.
I wondered where you got the idea for that line. Thanks for referencing the Microsoft ASP Breeze/Angular template documentation. Wow that is old (2013). I'd kill it ... and the other defunct Visual Studio Breeze templates ... if I could (maybe I can). I thought we had made them hard to find. Looks like you found them. How?
That certainly isn't how we teach Breeze + Angular these days.
The "Todo Angular" sample is a far better guide (even if it is a year old).
I resolved the issue by commenting out the line:
.value("breeze", window.breeze)
I had included that line per the "Dependency Injection" section here: http://www.getbreezenow.com/ng-spa-template#module as well as the "Value Recipe" section here: https://docs.angularjs.org/guide/providers, but apparently it does not play well with the Breeze Angular service.
I am not sure exactly why this is the case but my best guess is that the issue was caused by Angular values not being configurable, per this explanation: https://gist.github.com/demisx/9605099, and I assume the Breeze Angular service requires the Breeze object to be configurable and therefore it should not be injected as a dependency for the app via the value recipe.
I should also note that after removing that troublesome line of code, I no longer receive an error indicating that Q.js is required since the Breeze Angular service successfully configures Breeze to use Angular's $q instead.

How can I easily and efficiently see the available components provided by Angular dependencies?

I'm looking at the tutorial here (code reproduced below) but this questions applies in any Angular app.
The question is: When I'm either programming an Angular app or looking at someone else's, I'll often see variables used that don't seem to have been declared anywhere. They seem to come out from nowhere and cause a lot of confusion. Of course these variables end up being factories, services, constants etc in the dependencies specified when the app was created.
For example here:
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider.when('/', {
controller: 'WelcomeController',
template: 'views/welcome.html'
});
})
.config(function(ConnectionProvider) {
ConnectionProvider.setApiKey('SOME_API_KEY');
})
How on Earth, in a large app, would I know that $routeProvider came from ngRoute, or where did ConnectionProvider come from? Also, on the flip side, is there a way to get a quick look at what factories and services are available for use from the dependencies?
Angular has an internal module ng which is initialized at the top of module stack when bootstrapped. In this ng module, internal directive/controller/services are registered. But you cannot view that information as Angular keeps it as private property cacheProvider. The best way is to read the source code though.
For your own module. you can get a little bit more information by angular.module('yourModule')._invokeQueue, everything you defined is kept there with a suffix provider

Lazy loading AngularJS modules with RequireJS

Thanks to the great article from Dan Wahlin, I managed to implement lazy loading of Angular's controllers and services. However, there does not seem to be a clean way to lazy load independent modules.
To better explain my question, assume that I have an app would be structure as below without RequireJS:
// Create independent module 'dataServices' module with 'Pictures' object
angular.module("dataServices", []).factory("Pictures", function (...) {...});
// Create 'webapp' ng-app, with dependency to 'dataServices', defining controllers
angular.module("webapp", ['dataServices'])
.controller("View1Controller", function (...) {...})
.controller("View2Controller", function (...) {...});
Here is the sample app with RequireJS in Plunker:
http://plnkr.co/aiarzVpMJchYPjFRrkwn
The core of the problem is that Angular does not allow adding dependency to ng-app post instantiation. As result, my solution is to use angular.injector to retrieve the instance of Picture object to be used in my View2Controller. See js/scripts/controllers/ctrl2.js file.
This creates 2 problems for me:
The injected services runs outside of angular and therefore all async call must end with $scope.$apply()
Messy code where some object can be injected using standard angular syntax while others require the explicit use of injector.
Have any of you figured out how to lazy load independent module using RequireJS and somehow hook this module in angular so normal angular dependency injection syntax can be used?
Note:
The question is on lazy loading of independent module. One simple solution to this specific example is to create "Pictures" object using cached $providers during ng-app.config but that is not what I am looking for. I am looking for solution that works with 3rd party module such as angular-resource.
I finalized my own implementation called angularAMD and here is the sample site that uses it:
http://marcoslin.github.io/angularAMD/
It handles config functions and out of order module definitions.
Hopefully this can help other looking for something to help them with RequireJS and AngularJS integration.
Take a look at my project in GitHub: angular-require-lazy
This project is intended to demonstrate an idea and motivate discussions. But is does what you want (check expenses-view.js, it loads ng-grid lazily).
I am very interested in comments, ideas etc.
(EDIT) The ng-grid Angular module is lazy loaded as follows:
expenses-view.js is loaded lazily, when the /expenses route is activated
expenses-view.js specifies ng-grid as a dependency, so RequireJs loads ng-grid first
ng-grid is the one that calls angular.module(...)
In order to accomplish this, I replaced (proxied actually) the real angular.module method with my own, that supports laziness. See bootstrap.js and route-config.js (the functions initLazyModules() and callRunBlocks()).
This implementation has its drawbacks that you should be aware of:
Config functions are not implemented (yet). I do not know if it is possible to lazily provide config-time dependencies.
Order matters in definitions. If service A depends on B but A is defined after B in your module, DI wil fail. This is because the lazyAngular proxy executes definitions immediately, unlike real Angular that makes sure dependencies are resolved before executing the definitions.
It looks like the Node.js module ocLazyLoad defines a way of doing this lazy-loading, though I'm not sure how it fares, performance-wise, compared to the methods in the other answers or hard-coding the dependencies. Any info on this would be appreciated. One interesting thing is that the other answers need RequireJS to operate, while ocLazyLoad doesn't.
It looks like ocLazyLoad defines another provider that injects the dependency after the containing module has already been instantiated. It seems to do this by essentially replicating some low-level Angular behavior, like module loading and providing, hence why it looks so complicated. It looks like it adds just about every core Angular module as a dependency: $compileProvider, $q, $injector, ng, and so many more.

basic testacular/jasmine/angular setup and usage

I am new to Jasmine, but would like to do more TDD in Javascript. I've been using the Angular library from Google, and I know that Testacular was specifically created for testing Angular apps.
I have read through both the Jasmine documentation and watched the Testacular setup video, but I can't get the most basic testing to work. Assume I have three files:
modules.js
controller.js
appSpec.js
modules.js has my module definition with a few .factory(...) services and a few .directive(...) custom directives. controller.js houses my controllers for wiring up the modules to the html view.
So far, so good. Next I have added appSpec.js. Let's say I want to use it to test a service in my module called, "Data" that has a method, "getData()" which returns a resource.
In testactular init I have told it to watch all three files. I run Testacular and it tells me it is watching the correct files. Super.
What I don't understand is how I get the Jasmine spec know how to look at the module and controller so that they can be tested. If I simply say:
describe('Data Service', function(){
it ('should retrieve two items from the database', function(){
data = Data.getData() //my angular service
expect(data.length).toBe(2);
});
});
Not surprisingly, it has no idea what Data.getData() is.
It seems obvious that somehow I am supposed to bring my module definition and controllers into the spec before I begin writing suites. It must be so obvious that I don't see in the documentation how people are doing it. Tutorials just seem to start writing specs in the spec.js file and assume all is well.
I have seen other posts here where similar questions are being asked, but admittedly they all have a foundation I seem to be lacking. For example, one post talks about not manually creating an instance of the controller, but rather inject dependencies. Why is he creating a new $rootScope object, how is his module being referenced, etc...
I understand that my question is probably just a lack of basic understanding of the Jasmine framework, but I can't seem to squeeze any more understanding from the Jasmine readme file. Can someone point me to a basic explanation of how this is supposed to work?
Thanks.
Try doing module('myModule') in the jasmine test.
Here are some open source angular projects that have great tests to look at:
angular-app
angular-ui
bootstrap
The way that you include your definitions for your tests is through the karma.config.js file
files = [
JASMINE,
JASMINE_ADAPTER,
'../app/lib/icg/object.js',
'../app/lib/icg/geometry.js',
'../app/lib/icg/ubiquity.js',
'../test/unit/icgUbiquitySpec.js',
'../test/unit/icgObjectSpec.js'
];
Here you define which files get loaded into your browser, the first files that don't include the word 'Spec' are the definitions and the ones that do include are my test files. You need to include your definitions BEFORE your tests so that they are defined before you run the tests, which is why I include all my spec files last.

Resources