Cordova + Angular: How to test? - angularjs

I've just recently started fooling around with Cordova for a mobile App. For now the code base is quite small. I've also used AngularJS to drive my javascript. Now that I have reached a stable state, I would like to investigate ways to unit test the code I just wrote. Thing is, I'm not finding any useful resource for the pair. Angular suggests either Karma (unit) or Protractor (scenarios), but I'm finding quite hard to bootstrap them both with a Cordova App, since this is not supposed to run inside the browser, but within some kind of container where cordova can be loaded. Are there already some good test-driven approaches in the open source market regarding test driven development of hybrid apps?

I think that correct approach would be to have cordova.mocks.js included in tests that will mock out cordova dependencies. And then unittest as usual.

I think there is no way at the moment to test the parts of cordova that would call functionality from plugins.
But you could use Karma or Protractor as you would in the browser (eventually with some mocks for cordova and cordova plugins), which require some additional if conditionals to run the app without a physical device
Ie if (window.cordova && cordova.plugins.thePluginExample) { /* Code that uses plugins [...] */ }

You can use "phonegap server" even if you're using cordova, also you can run on the device with cordova run <platform> --device.
You can track issues on the CLI output of both methods.

To help others who get here with the same question as I did...
You probably don't need to bootstrap with Cordova. Use mocks as stand-ins.
Since Cordova attaches to window, you can write your app code to inject $window and mock cordova with with standard mocking.
Example with mocha / chai:
/**
* Test case for AngularJS module that does something when platform = 'ios'
*/
describe('platform = "ios"', function() {
var $window;
beforeEach('inject', inject(function(_$window_) {
$window = _$window_;
$window.cordova = {
platformId: 'ios',
}
}));
it('verifies cordova mock platform = "ios"', function() {
expect($window.cordova.platformId).to.equal('ios');
});
it('does something', function() {
// ...
});
});

Related

Is it possible to use Jasmine without Karma for testing Angular/Node based Nw.js apps?

I've read ton's of tutorials, but I must admit that this testing stuff is still very confusing to me. I have a Nw.js app which (of course) uses NodeJS and also Angular. I've installed the Jasmine test framework globally via npm and wrote an example test which starts with the following lines, and placed it in the spec sub-directory:
describe ( 'Test for my controller', function () {
beforeEach ( module ('module_under_test') );
... and so on ...
});
When running the test by typing jasmine on the cmd line (from the root folder of the app), I get the following error message:
TypeError: module is not a function
I know that I have to include the Angular library somehow. But where? In a normal browser application, it is included in the HTML <script> tag, but I don't have this possibility. I also know that I could write a HTML file, which shows the Jasmine result page after tests have finished, but I would prefer to start Jasmine on the cmd line.
First I thought about adding the angular library to the "helpers" entry in jasmine.json. But it didn't work. The documentation of this file is unfortunately very poor. In the Angular documentation and tutorials it is always mentioned to use Karma. But my understanding is that Karma is only useful for testing with browsers, since it spawns an own webserver. This does not make sense in my case.
Would be great if somebody could give me a hint, thanks!

Usage of spec.js file in AngularJS

This might sound a stupid question, but I want to know its answer. What is the spec.js file in AngularJS and what is its use? Is it used for testing purpose?
EDIT- Below is the code of file phone-detail.component.spec.js
'use strict';
describe('phoneDetail', function() {
// Load the module that contains the `phoneDetail` component before each test
beforeEach(module('phoneDetail'));
// Test the controller
describe('PhoneDetailController', function() {
var $httpBackend, ctrl;
var xyzPhoneData = {
name: 'phone xyz',
images: ['image/url1.png', 'image/url2.png']
};
beforeEach(inject(function($componentController, _$httpBackend_, $routeParams) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData);
$routeParams.phoneId = 'xyz';
ctrl = $componentController('phoneDetail');
}));
it('should fetch the phone details', function() {
jasmine.addCustomEqualityTester(angular.equals);
expect(ctrl.phone).toEqual({});
$httpBackend.flush();
expect(ctrl.phone).toEqual(xyzPhoneData);
});
});
});
Use of spec.js is for writing you unit test cases for your angular application.
We write test cases in angular using Jasmine & Karma.
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, Node.js projects, or anywhere that JavaScript can run.
https://github.com/jasmine/jasmine
Karma is essentially a tool which spawns a web server that executes source code against test code for each of the browsers connected. The results of each test against each browser are examined and displayed via the command line to the developer such that they can see which browsers and tests passed or failed.
https://karma-runner.github.io/1.0/index.html
Question - What is the spec.js file in AngularJS ?
Answer - AngularJS uses Jasmine as a testing framework and tests written in Jasmine are called specs. Filename written related to Jasmine must be .spec.ts, the filename extension convention is adhered by configuration of
karma( the test runner tool ).
Question - what is its use? Is it used for testing purpose?
Answer - Karma the test runner gets the specifications for testing from this file. yes, it is used for testing :)
Reference https://angular.io/guide/testing

How can I run common code in tests using Karma + Jasmine + AngularJS?

I'm using Karma to run my unit tests against an AngularJS application. The problem is that I use the ui-router plugin, and the fact that it makes some XHR requests to run the templates forces me to mock those requests. Therefore, I see myself repeating this for every test file:
beforeEach(function($templateCache) {
$templateCache.put('templates/layout.html', '');
$templateCache.put('templates/dashboard/index.html', '');
$templateCache.put('templates/session/login.html', '');
});
How can I run this piece of code for all my unit tests? I tried googling, but no luck. Also, should I be doing this in some other way? Please share your opinions.
Thank you all.
You should look into ng-html2js-preprocessor:
https://github.com/karma-runner/karma-ng-html2js-preprocessor
It will batch up all your templates into a template cache module (that uses $templateCache under the hood) that you can use:
describe('SOMETHING', function() {
beforeEach(module('templates'));

Using Google Maps api V3 with angular and browserify

I am trying to use the Google Maps Javascript Api V3 inside a Angular + browserify app.
I do not use bower.
Previously I was doing that with requirejs, and a plugins on git hub millermedeiros/requirejs-plugins called async.
I was able to load gmaps like this (most of the time, sometimes requirejs was still requireing gmaps too early.
// load gmap as an amd module
define(['config'], function(config){
define('gmaps', ['async!http://maps.google.com/maps/api/js?v=3&sensor=false&libraries=places&key=' + config['google-map-api-key']],
function(){
return window.google.maps;
}
);
});
Browserify is kind of new, I don't see much documentation at this moment, do you guys have any recommendation ?
To include CommonJS incompatible scripts have a look at Browserify-shim transform:
https://github.com/thlorenz/browserify-shim

Unable to use Cordova Plugin

I have an AngularJS app that I want to deploy as an app to mobile devices. I had heard about Cordova (and its AngularJS counterpart ngCordova). I will be using multiple Cordova plugins. The first one I'm trying is to detect if the user is online or not. To do that, I'm using the cordova-network-informtion plugin in the following controller via ngCordova:
'use strict';
myApp.controller('MyController', function($scope, $cordovaNetwork) {
$scope.isOnline = null;
$scope.init = function() {
// Detect if the user is on a network
console.log($cordovaNetwork.isOnline());
$scope.isOnline = $cordovaNetwork.isOnline();
console.log($scope.isOnline);
};
$scope.init();
});
When the init function gets called, I see the following in the console:
Object {getNetwork: function, isOnline: function, isOffline: function}
TypeError {stack: (...), message: "Cannot read property 'type' of undefined"}
That type error is printed thanks to global error handler. Either way, it is a result of calling $scope.isOnline = $cordovaNetwork.isOnline();. I don't understand what I'm doing wrong.
I believe the root cause is that I'm not referencing cordova.js in any way. All of the examples I see reference cordova.js. However, when I look at the package, I only see vendor specific implementations of Cordova. For instance:
cordova.windowsphone.js
cordova.android.js
cordova.ios.js
That makes sense from a deployment perspective. However, I'm still trying to do development in my browser. For that reason, I was thinking I could use ngCordova. I also thought there would be a generic cordova.js that served as an abstraction. However, I don't see one. Can someone please help me get over this hump? I sincerely appreciate it.
Your problem is, like you mentioned in your last paragraph, that you are trying to use Cordova Plugins within your browser.
This is not possible because here is no phonegap abstraction layer for your browser.
So i think you have some opportunities:
The most reliable would be to deploy it every time on your device an test it there.
Yes i know, that always takes a few seconds and is not the best if you are trying a lot of different thinks.
Another option could be to create your own mocked $cordovaNetwork in ngCordovaMocks.
Example:
angular.module('ngCordovaMocks', [])
.factory('$cordovaNetwork', [function () {
return {
getNetwork: function () {
return "Edge"
},
isOnline: function () {
return true;
},
isOffline: function () {
return false
}
}
}]);
In the app.js you then include your ngCordovaMocks instead of ngCordova and all services will be mocked ( Be sure, that only your mocked services will be available and not all ngCordova functionalities).
angular.module('myApp', ['ngCordovaMocks']);
Yes, this is a lot of work and you have to change it before your deployment. And don't forget: It's just a mock for local development. It's essential to test it on your device with the ngCordova module and cordova device connection.
Another option would be to use the Ripple Emulator , which offers some Cordova features in your browser. But i don't know if the connection is a supported one.
But then you have to integrate the cordova.js file to your index.html.
I don't what the differences between the vendor specific files are, but you should download the plain and neutral cordova.js and include it.
First off, ngCordova isn't the counterpart to cordova.js. ngCordova is a set of extensions that are meant to be used on top of Cordova. You still have to use Cordova in your app to be able to deploy your app to mobile devices.
I would recommend taking a look at ionicframework.com. The makers of ngCordova also built Ionic and it will provide you with all of the tools that you would need to be able to build out a mobile app with angular.js.

Resources