I'm newbie in testing of Cordova app, so could you please give an advice about what is "best practice" in my situation?
Situation: I have a module factory:
angular
.module('app.services')
.factory('UtilsService', UtilsService);
function UtilsService() {
var service = {
isWindows: isWindows,
isAndroid: isAndroid
};
return service;
function isWindows() {
return /windows/i.test(device.platform);
}
function isAndroid() {
return /android/i.test(device.platform);
}
}
and a simple test for isWindows method:
describe('Util Service Tests', function() {
var utilSvc;
beforeEach(function() {
module('app');
});
beforeEach(function () {
inject(function($injector) {
utilSvc = $injector.get('UtilsService');
});
});
it('should detect windows', function () {
expect(utilSvc.isWindows).toBe(true);
});
});
I run tests with Chitzpah runner and get an error:
'device' is undefined
I've found the possible solution like chrome-cordova extension, but it doesn't work in my case (or I'm doing something wrong with it). So what should I do here? Mock calls to device method? If yes, how to do that?
Thanks in advance!
Have you tried using the Cordova browser platform, that can be added with the CLI:
cordova platform add browser
This provides some support for using Cordova APIs / plugins in the browser, but the plugins you're using need to support that platform usually with a JavaScript fallback to whatever their native functionality would do on an actual mobile platform such as iOS or Android. There's a good blog post covering the browser platform here. I'm not clear on how well maintained this platform is but it might be what you're looking for.
Related
I am working on the E2E tests for an Ionic v1 app written in Angular 1.x + with Component oriented pattern (Webpack + ES6).
I am trying to add a mock module via the browser.addMockModule function but with no success.
I have tried everything, including adding the mock before browser.getetc.
Here's a simple test (in the onPrepare function, but it was in a specific test BeforeAll at an earlier stage, with same result):
browser.addMockModule('myMockModule', () => {
console.log("mock is being executed");
return;
});
browser.pause();
browser.driver.get('http://localhost:8100');
The actual code I am trying to implement is supposed to ovveride an existing module of my application.
console.log('beforeAll --> proof-of-delivery');
browser.addMockModule('myOverridenModule', () => {
console.log('beforeAll -->addMockModule proof-of-delivery');
angular.module('myOverridenModule', ['ui.router'])
.run( ($state, $rootScope) => {
console.log('myOverridenModule override');
$rootScope.$on('$stateChangeStart', (event, toState) => {
console.log('toState test ', toState);
});
});
});
browser.pause();
browser.driver.get('http://localhost:8100');
Any suggestion on what could possibly be wrong? On a side note I have already checked also the actualChrome console logs and the terminal ones. No logs from the module anywhere at all (but I can see the log immediately before invoking the function).
Thanks for any help you can give in resolving such an issue. My stress will be grateful.
It looks to me like your problem is that you are using
browser.driver.get('http://localhost:8100');
this is wrapped browser instance and not the protractor browser instance so any mockModules defined will be ignored.
If you use
browser.get('http://localhost:8100');
your mockModules should be executed.
I am trying to implement AdMob to an app. I have installed cordova-plugin-admob and am trying to load $cordovaAdMob into controller as stated in official documentation Cordova AdMob, but I get unknown provider error. I figured that maybe it doesn't work in browser, but same happens if I run it on mobile.
If needed, here is controller code, but it's AdMob empty since I haven't passed even that first issue.
.controller('newsCtrl', ['$state', 'Injection', '$scope', '$http', 'SERVER', 'thumbSERVER', '$cordovaAdMob',
function ($state, Injection, $scope, $http, SERVER, thumbSERVER, $cordovaAdMob) {
Injection.ResourceFactory.getResource($http, SERVER, 'news')
.then(function (response) {
$scope.news = response.data.news;
}, function (error) {
});
$scope.thumbnailPath = thumbSERVER;
}])
EDIT:
cordova.js is added automatically when creating new platform (I have installed android) and it is referenced in index.html by default. If I inject it, I get error
Error: [$injector:nomod] Module 'ngCordova' is not available!
I have ended up using the AdMob from this link, and following the "Quick start" section and conforming it to my needs, instead of "Installation" section which is obvieusly missing something
I have a set of services which represent a backend logic, that is called by different angular controllers.
During development however I want to call these services directly, in order to test them in isolation, from the browser Javascript console.
How this can be done?
Say there is
app.service('service1', function() {
this.sayHello = function() {
return "Hello"
};
});
Now from Javascript console,
app.somethingToGetService('service1').sayHello()
?
You can get injector for module and from it get service:
angular.injector(['ng', 'myApp']).get('service1').sayHello()
I am developing a mobile application using Cordova and AngularJS. How do I restrict bootstrapping of AngluarJS before Cordova device ready. Basically I don't want to use any of AngularJS controllers before device ready.
Manually bootstrap your Angular app:
Remove your ng-app attribute from your HTML code, so Angular doesn't start itself.
Add something like this to you JavaScript code:
document.addEventListener("deviceready", function() {
// retrieve the DOM element that had the ng-app attribute
var domElement = document.getElementById(...) / document.querySelector(...);
angular.bootstrap(domElement, ["angularAppName"]);
}, false);
Angular documentation for bootstrapping apps.
I'm using the following solution, which allows AngularJS to be bootstrapped when running with Cordova as well as when running directly in a browser, which is where much of my development takes place. You have to remove the ng-app directive from your main index.html page since that's what the manual bootstrapping is replacing.
UPDATE: I've since switched to the following method, which I think is cleaner. It works for Ionic as well as vanilla Cordova/PhoneGap. It should be the last bit of JavaScript to run - perhaps inside a script tag before the /body tag.
angular.element(document).ready(function () {
if (window.cordova) {
console.log("Running in Cordova, will bootstrap AngularJS once 'deviceready' event fires.");
document.addEventListener('deviceready', function () {
console.log("Deviceready event has fired, bootstrapping AngularJS.");
angular.bootstrap(document.body, ['app']);
}, false);
} else {
console.log("Running in browser, bootstrapping AngularJS now.");
angular.bootstrap(document.body, ['app']);
}
});
Here's the older solution I used:
// This is a function that bootstraps AngularJS, which is called from later code
function bootstrapAngular() {
console.log("Bootstrapping AngularJS");
// This assumes your app is named "app" and is on the body tag: <body ng-app="app">
// Change the selector from "body" to whatever you need
var domElement = document.querySelector('body');
// Change the application name from "app" if needed
angular.bootstrap(domElement, ['app']);
}
// This is my preferred Cordova detection method, as it doesn't require updating.
if (document.URL.indexOf( 'http://' ) === -1
&& document.URL.indexOf( 'https://' ) === -1) {
console.log("URL: Running in Cordova/PhoneGap");
document.addEventListener("deviceready", bootstrapAngular, false);
} else {
console.log("URL: Running in browser");
bootstrapAngular();
}
If you run into problems with the http/https detection method, due to, perhaps, loading a Cordova app into the phone from the web, you could use the following method instead:
function bootstrapAngular() {
console.log("Bootstrapping AngularJS");
// This assumes your app is named "app" and is on the body tag: <body ng-app="app">
// Change the selector from "body" to whatever you need
var domElement = document.querySelector('body');
// Change the application name from "app" if needed
angular.bootstrap(domElement, ['app']);
}
// This method of user agent detection also works, though it means you might have to maintain this UA list
if (navigator.userAgent.match(/(iOS|iPhone|iPod|iPad|Android|BlackBerry)/)) {
console.log("UA: Running in Cordova/PhoneGap");
document.addEventListener("deviceready", bootstrapAngular, false);
} else {
console.log("UA: Running in browser");
bootstrapAngular();
}
Note that you still need the same bootstrapAngular function from the first example.
Why manually bootstrap AngularJS with Cordova/PhoneGap/Ionic?
Some people getting here might not know why you would want to do this in the first place. The issue is that you could have AngularJS code that relies on Cordova/PhoneGap/Ionic plugins, and those plugins won't be ready until after AngularJS has started because Cordova takes longer to get up and running on a device than the plain old Javascript code for AngularJS does.
So in those cases we have to wait until Cordova/PhoneGap/Ionic is ready before starting up (bootstrapping) AngularJS so that Angular will have everything it needs to run.
For example, say you are using the NG-Persist Angular module, which makes use of local storage for saving data on a browser, iOS Keychain plugin when running on iOS, and the cordova-plugin-file when running on Android. If your Angular app tries to load/save something right off the bat, NG-Persist's check on window.device.platform (from the device plugin) will fail because the mobile code hasn't completed startup yet, and you'll get nothing but a white page instead of your pretty app.
If you are using Ionic, this solution works for browsers and devices. Credit to romgar on this thread.
window.ionic.Platform.ready(function() {
angular.bootstrap(document, ['<your_main_app']);
});
Still need to remove ng-app from your DOM element.
This solution became more robust when I used:
angular.element(document).ready(function () {
var domElement = document.getElementById('appElement');
angular.bootstrap(domElement, ["angularAppName"]);
});
UPDATE
My suggestion was to put the above within the appropriate deviceready function, e.g.:
document.addEventListener("deviceready", function() {
angular.element(document).ready(function () {
var domElement = document.getElementById('appElement');
angular.bootstrap(domElement, ["angularAppName"]);
});
}, false);
On using the solution from TheHippo:
document.addEventListener("deviceready", function() {
// retrieve the DOM element that had the ng-app attribute
var domElement = document.getElementById(...) / document.querySelector(...);
angular.bootstrap(domElement, ["angularAppName"]);
}, false);
It doesn't work in the browser because "cordova.js" gets resolved by the Cordova or Phonegap building process and is not available in your localhost or emulated testing environment.
Thus the "deviceready" event is never fired. You can simply fire it manually in your browsers console.
var customDeviceReadyEvent = new Event('deviceready');
document.dispatchEvent(customDeviceReadyEvent);
Also make sure, that the bootstrap of angular gets triggered after setting all of you angular modules/controllers/factories/directives etc.
In most cases you probably don't need to block loading your angular app until after deviceready (mind that it can take several seconds for deviceready to fire if you have a lot of plugins).
Instead you can use something like this lib (https://github.com/arnesson/angular-cordova) which solves the deviceready issues for you by automatically buffering calls and then execute them after deviceready has been fired.
Anybody know if the angularJS animations work with requireJS? ng-animate isn't recognized when I use requireJS modules. If anyone know how to get it working can you explain what the best approach is? I should add that I am indeed using the angularJS version 1.1.4
AngularJS is MVW framework and requireJS is AMD loader. So the problem is in your module complatibility or setup or something else and not in requireJS.
I just grabbed this from one of my abandoned angular apps - but seems to work just firing it up now.
Hope it helps. Oh I should mention this is javascript based animation using jquery (fadeIn and fadeout).
var myApp = angular.module('apps', ['ngSanitize']);
myApp.animation('animate-enter', function () {
return {
setup: function (element) {
var viewId = element.parent().attr('id');
$("#" + viewId).hide();
},
start: function (element) {
var viewId = element.parent().attr('id');
$("#" + viewId).fadeIn(500, function () {
});
}
}
});