I am trying to mock data being responded to from an angularjs service using Protractor. I have been able to successfully do this in other applications by using the following technique.
Creating a mock module that is configurable via protractor.addMockModule
var httpBackendMock = function() {
angular.module('mockBackend', ['ngMockE2E', 'MyApp'])
.value('configData', arguments[0])
.run(function($httpBackend,configData) {
console.log('bootstrapped!');
$httpBackend.whenPOST(/.*/).respond(configData.postHeader, configData.postResponse);
});
};
module.exports.httpBackendMock = httpBackendMock;
Then creating a protractor test that looks like this
describe('Mocking an httpbackend', function() {
var sampleData = require('./sampleData/blog/normalLanding.json');
var configObject = require('./utils/backendConfig.json');//passed To addMockModule to be accessed via arguments[0]
var MyMockedBackend = require('./utils/httpBackendMock.js');
var ptor = protractor.getInstance();
configObject.postHeader = 200;
configObject.postResponse = sampleData;
it('Should mock a backnd', function(){
ptor.addMockModule('mockBackend', MyMockBackend.httpBackendMock, configObject);
ptor.get('/blog');
});
});
This worked perfectly for an app that was
The only angular application running on the page
Was bootstrapped via ng-app
However when working with an app that is manually bootstrapped, the app calls and returns the results from the actual service, rather than the desired mocked response. Also, no errors are thrown. For example's sake, I am trying to respond to all POST requests with the same data.
I have protractors rootElement in my configuration file set to the tag the app bootstraps on.
Does anything look particulary wrong with this settup/approach? Or could it be an issue with the order in which protractor executes in relation to calling addMockModule with a manually bootstrapped application?
Here is a link to a github repo which contains a working example of this with the Angular Phonecat Tutorial from the Angular website. The examples are in test/e2e/utils and scenerios.js
Github example
Cheers!
Related
I'm newb to swagger , I have generated javascript-closure-angular-client from swagger-editor.
I want to used javascript-closure-angular-client in my AnuglarJS project. But I can't find any explanation for how to use it with AnuglarJS project.
Can anyone guide me for how to used javascript-closure-angular-client with AnuglarJS project?
I recommend you use swagger-js-codegen
Repository: https://github.com/wcandillon/swagger-js-codegen
And in this repository I explain how to generate the client in this case called clientAngularSwagger.js:
https://github.com/CayetanoHerreraLuisRicardo/swagger-angularjs-client
The next step would be:
To add it to your AngularJS project, do the following:
Add the generated file in the project for example:
<script src="js/models/clientAngularSwagger.js" type="text/javascript"></script>
Inject factory to controller
angular.module('App').controller('test', function ($scope, clientSwagger) {
....
}
and finally do requests to the web service in test controller
//clienSwagger object
$scope.swaggerObject = new clientSwagger("APIurl",false); //the parameter "APIurl" is optional, because in the clientSwagger factory is defined
//paramether to send
$scope.parameters = [];
$scope.parameters["authorization"]="Bearer xxxxxxxx";
$scope.parameters["xparameter"]="xxxx";
$scope.data = [];
//request function http
$scope.BBBObject.herefunctionname($scope.parameters).then(function(res)
{
$scope.data= res.data;
}, function(e) {
console.log(e);
});
I'm working on an AngularJS/Javascript Single Page Application(SAP) that sits behind a custom reverse-proxy, using Keycloak for Single-Sign-On(SSO).
When the user clicks "logout", after doing some other things, the application will execute
window.location = reverseProxyHost + '/logout';
to ensure the user is completely logged-out, not just from this application, but from all applications authorized by the Keycloak SSO.
If we allow this line to execute, Karma complains
Some of your tests did a full page reload!
This Error fails the entire test suite.
It doesn't seem that I can override the window.location object value from the context of my test.
If I create a localContext object and then attempt
with(localContext){
the test will fail because with is incompatible with 'use strict'.
Any ideas how I can ensure the line is being executed with expected results?
Try using $window from angular, and $window.location.replace instead of window.location = "newlocation.com".
Then you shourd be able to mock like this:
var $window = { location: { replace: jasmine.createSpy('replace') } };
module('app', function ($provide) {
$provide.value('$window', $window);
});
I'm already some time in the development using AngularJS, and what I do write works, but know I've come to a point where I would like to run unit tests on my AngularJS code.
I have created a very simple service that will inject a stylesheet onto the page,
see the example code below:
var OfficeSuiteStylesheetInjectorModule = angular.module('OfficeSuiteStylesheetInjectorModule', []);
OfficeSuiteStylesheetInjectorModule.factory('stylesheetInjectorService', ['$q', function($q) {
// Returns the service itself.
return {
inject: function(id, uri) {
var deferred = $q.defer();
// Embed the stylesheet into the page, but only when it's non-existing.
if (!angular.element('#' + id).length) {
var link = StylesheetFactory.Create(id, uri);
{
link.onload = deferred.resolve;
angular.element('head').append(link);
}
return deferred.promise;
}
}
}
}]);
It's not a big service, it's just dependend on $q for promises so that I can run additional logic when the stylesheet has been embedded in the page.
Now, I'm using Jasmine (I'm quite new to this) for testing my JavaScript code and I would like to test this module.
I have a skeleton:
// Tests for the angular 'StylesheetInjectorService'.
describe('StylesheetInjectorService', function() {
var stylesheetInjectorService = {};
// This code is executed before every test.
beforeEach(function() {
// Tells jamine that the module we're working on is the 'OfficeSuiteStylesheetInjectorModule'.
angular.module('OfficeSuiteStylesheetInjectorModule');
});
// Ensures that it injects a stylesheet element into the page.
it('Should inject a stylesheet element into the page.', function() {
// How to test here that the stylesheet is injected?
});
});
});
How can I inject te service in the page and ensures that the stylesheet is loaded?
Edit: Loading service now works:
beforeEach(module('OfficeSuiteStylesheetInjectorModule'));
// This code is executed before every test.
beforeEach(function() {
// Inject the required dependencies into the page.
inject(function($injector) {
stylesheetInjectorService = $injector.get('stylesheetInjectorService');
});
});
The same question is still open however. How to test if a stylesheet was embedded in the page?
Any help is highly appreciated.
Kind regards
To write a spec for the attachment of a stylesheet to angular.element('head') I would change the logic a bit to attach it to $document.head.
If you dont want to do that, I would recommend that you change your service into a directive seeing as how injecting a script element, is manipulating the DOM. That way you would kill two birds with one stone, as you would need to inject $compile to test your directive (which would enable you to $compile a custom head element to boot). But this is slightly "over the top" for now.
Implementation:
if (!angular.element('#' + id).length) {
var link = StylesheetFactory.Create(id, uri);
link.onload = deferred.resolve;
$document.head.append(link);
return deferred.promise;
}
}
beforeEach:
/**
* Sorry, this was previously $location which was just
* such a silly mistake.
*/
var $timeout;
beforeEach(function () {
inject(function ($injector) {
$timeout = $injector.get('$timeout');
});
});
it:
it('attaches the stylesheet to $document.head', function () {
styleSheetInjectorService.inject('someId', '/path/to/some/stylesheet');
$timeout.flush(); // flush promises
expect(angular.element($document.head).lastChild[0].nodeName).to.eq('LINK');
});
Something along those lines should get you up and running. Bare in mind that the spec I wrote uses the chai#expect style assertions, and the mocha test framework. Edit the syntax to fit Jasmine if you mean to copy-paste.
I had this doubt a while ago.
To inject your controllers and services into your tests you need to use a tool called Angular Mocks. Here's some official reference about it.
I sugest you use it together with the Karma enviroment.
Here's a great Getting Started tutorial:
https://www.airpair.com/angularjs/posts/unit-testing-angularjs-applications
This other one is for the Ionic Framework, but can still aplly to your case
Hope it can help.
I'm very new to Javascript and Protractor. Still trying to get my head around simple syntax so forgive me if I'm way off base here.
So our angular app, has a module with a factory that generates toast messages. I'd like to disable all toast messages during my E2E testing. We have a function within the factory to disable toasts. Here's some simplified code.
//the module
var module = angular.module('toast',[]);
//the factory
module.factory('tf',[function tf(){
//factory code
//the function within the module's factory
moduleFactory.enable = function(enable){
isEnabled = enable;
};
}]);
My question is, can I access that function in protractor to turn that to false?
I've been searching around and it seems that mocking is how to do it. Something similar to how you disable angular animations.
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
$animate.enabled(false);
}]);
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
However, I'm struggling with the syntax on accessing the factory's function within the module...Any help would be appreciated.
I believe I've found the solution for anyone else that may have a similar issue.
Using the executeScript function of protractor.
browser.executeScript(function()
{
return angular.element(document).injector().get('toastFactory').enableToasts(false);
});
I am an Ember noob and am trying to get it to work; however I am confused about the App.initialize() method.
It throws errors (it can't find the object App) if I use the following code:
App = Ember.Application.extend()
App.initialize()
However if I use the following code; it says initialize is being called twice.
App = Ember.Application.create()
App.initialize()
What is the best way to do this?
The Application no longer provides the initialize method. Instead you should use Application#deferReadiness and Application#advanceReadiness combined.
Example extracted from Ember's source code:
App = Em.Application.create();
App.deferReadiness();
jQuery.getJSON("/auth-token", function(token) {
App.token = token;
App.advanceReadiness();
});
Additionally, check the sample in jsfiddle:
window.App = Em.Application.create();
App.deferReadiness();
window.setTimeout(function() {
Em.TEMPLATES["application"] = Em.Handlebars.compile('<h1>App</h1> this is a template');
App.advanceReadiness();
}, 1500);
First, You have to understand the difference between create() and extend(). Easy way to understand is extend() method just extends the class of Ember.Application but create() method creates the instance of Ember.Application(). While creating the instance it runs the constructor. There are 3 ways to create the Ember.App and run it.
1
var App= Ember.Application.extend()
App.initialize()
2.
var App = Ember.Application.create()
This initialises as soon as u create object.
3
var App= Ember.Application.extend()
App.create()
To understand Ember Objects more go through this link. Understanding Ember.Object
Just create your application and let Ember initialize it.
All you need to do is:
App = Ember.Application.create()
The App will not be initialized immediately. It waits, at least, for DOM readiness and for the rest of your classes to be defined (by waiting until control is returned to the browser from the currently executed JavaScript).
If you want to defer it for other reasons, do something like this:
App.deferReadiness();
$.getJSON("/boot", function() { App.advanceReadiness(); });
This will wait to boot the app until the /boot Ajax call returns.
Just have a look here how to do this stuff:
http://emberjs.com/documentation/#toc_creating-a-namespace
How to bootstrap:
window.App = Ember.Application.create();
Without ever using ember.js, I would suggest that create and initialize both do initialization, that's why you get the latter error telling you it's inited twice.
And your first version is trying to extend the Application object, that is you create new functionality.
Ember "create" method accepts either no arguments, or an object containing values to initialize the newly instantiated object with, so you might also go like this below:
var appConfig = {
Token: token;
};
App = Ember.Application.create(appConfig);