Using chance.js inside AngularJS end to end tests - angularjs

I'm trying to generate some random data for my e2e tests. Seems that the only library I found was chance.js. But can't make it works. This is what I've tried so far:
describe('In the login page', function () {
var chance = new Chance(); // ReferenceError: Chance is not defined
}
Then adding
beforeEach(function(){
browser.executeScript(
function() {
return chance;
}).then(function(_chance){
chance = _chance; //It returns an object, but can't use any of the methods.
});
});
But if I try
beforeEach(function(){
browser.executeScript(
function() {
return chance.email(); //Note this line here
}).then(function(_chance){
chance = _chance; //It returns an email
});
});
Thats all I have so far... any clue/idea?

First, install chance.js in your project:
npm install chance --save-dev
This installs chance.js as a node module in your project. Then include it in your spec and instantiate:
var chance = require('../node_modules/chance').Chance();
Then call in your spec. For example:
it('should add a new friend', function() {
var friendName = chance.string()
friendPage.addFriend(friendName);
expect(friendPage.inResults(friendName)).toBeTruthy();
});
Hope that helps...

Okay first you need to download chance.js and add that file to your html directory
Second add script src="chance.js" in a proper script tag your section
Within another script tag you should be able to use any of the functions that are listed on the website
working jsfiddle: http://jsfiddle.net/c96x2cpa/
fiddle js code:
alert(chance.bool());
alert(chance.character());
alert(chance.floating());

It was easy at the end :)
You just need to install chance as a node module.
npm install chance
Then require the node in the spec
// Load Chance
var Chance = require('chance');
And use it where ever you want
chance.email()
Enjoy!

Related

Gulp Task Breaking on Angular Files

I have the gulp task set up and running to create an Angular app, and it runs without error and creates the files correctly, but when I load the page on a browser, I get following error messages.
Is there some step or some plugin I'm missing to get the Angular files to all "work"? I've used the angularFilesort() and ngAnnotate() plugins already.
var bower = gulp.src(bower_files)
.pipe(concat("bower-expanded.js"))
.pipe(gulp.dest(paths.prod))
.pipe(rename("bower.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
// gather and compress the app's js files
var app = gulp.src(paths.source + "app/**/*.js")
.pipe(angularFilesort())
.pipe(concat("app-expanded.js"))
.pipe(ngAnnotate({
add: true,
single_quotes: true
}))
.pipe(gulp.dest(paths.prod))
.pipe(rename("app.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
The errors are
TypeError: (intermediate value)(...) is not a function
(function(angular) {
which points to these lines of code
(function(angular) {
'use strict';
/**
* Called with an array this acts like map, otherwise it acts like _.mapValues
* in lodash.
* #return {Array|Object} The same type as the input argument.
*/
var mapValues = function(obj, callback) {
if (angular.isArray(obj))
The other error is
Error: [$injector:modulerr] Failed to instantiate module app due to:
[$injector:modulerr] Failed to instantiate module angularSpinner due to:
[$injector:nomod] Module 'angularSpinner' is not available!
You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.4.4/$injector/nomod?p0=angularSpinner
I notice you're not running ngAnnotate on your bower components, but you are running uglify on them. This could be causing your problem.
Try:
var bower = gulp.src(bower_files)
.pipe(concat("bower-expanded.js"))
.pipe(ngAnnotate({
add: true,
single_quotes: true
}))
.pipe(gulp.dest(paths.prod))
.pipe(rename("bower.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
As an aside, it's not an awesome idea to concatenate all of your dependencies into a single file. The browser can handle asynchronously loading multiple JS files and will do so much faster than loading a single, massive JS file.
After reading through various answers in SO the first error usually refers to a forgotten ; in the lines prior to the error.
You can configure the concat task to use ; as a seperator for js files to avoid this.
On the second I agree with #ShaunScovil, also using the .min files provided from each bower package is safer.
You can make use of this main-bower-files package to set this up depending of the env and automate the process of building one or more files of all bower dependencies.
This same thing happens with GruntJS and I recently learned how to fix it. Make sure all of your angular js controllers, directive and filters have proper includes on them.
Example wont work:
angular.module('uniApp').directive('autoFocus', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(attrs.autoFocus,
function (newValue) {
$timeout(function () {
element.focus();
});
}, true);
};
});
Notice on the above how the $timeout is not properly included?
Example will work:
angular.module('uniApp').directive('autoFocus',['$timeout', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(attrs.autoFocus,
function (newValue) {
$timeout(function () {
element.focus();
});
}, true);
};
}]);
Now the $timeout is properly included. Make sure to check this little detail on all controllers, filters, and directives.

Testing code that uses document.body.querySelectorAll

Trying to test a directive that does the following:
var inputs = angular.element(document.body.querySelectorAll('input[ng-model]', elem));
// [code relying on found elements]
Running inside karma/jasmine/phantomjs, this fails because it seems that document returns the document that contains the test, rather than the compiled template. Is there some way to mock this functionality so it works as expected (for my use case) or some other way to query for those elements?
PS: The elements that need to be located are in no known relation to the element that the directive is applied to.
You can use $document instead of document then mock it in your tests.
See Angular js unit test mock document to learn how to mock $document.
The last update in this answer did the trick for me he basically is using the $document service, which is like a wrapper over jQuery and then you can append elements to the body directly and test them:
I'll quote his answer:
UPDATE 2
I've managed to partially mock the $document service so you can use
the actual page document and restore everything to a valid state:
beforeEach(function() {
module('plunker');
$document = angular.element(document); // This is exactly what Angular does
$document.find('body').append('<content></content>');
var originalFind = $document.find;
$document.find = function(selector) {
if (selector === 'body') {
return originalFind.call($document, 'body').find('content');
} else {
return originalFind.call($document, selector);
}
}
module(function($provide) {
$provide.value('$document', $document);
});
});
afterEach(function() {
$document.find('body').html('');
});
Plunker: http://plnkr.co/edit/kTe4jKUnypfe6SbDECHi?p=preview
The idea is to replace the body tag with a new one that your SUT can
freely manipulate and your test can safely clear at the end of every
spec.

Get the current browser name in Protractor test

I'm creating users in some test. Since it is connected to the backend and create real users I need fixtures. I was thinking of using the browser name to create unique user. However, It has proven to be quite difficult to get to it...
Anyone can point me in the right direction?
Another case of rubber ducking :)
The answer was actually quite simple.
in my onPrepare function I added the following function and it works flawlessly.
browser.getCapabilities().then(function (cap) {
browser.browserName = cap.caps_.browserName;
});
I can get access the name in my test using browser.browserName.
This has changed in version of protractor starting from 3.2 (selenium webdriver 2.52)
Now one should call:
browser.driver.getCapabilities().then(function(caps){
browser.browserName = caps.get('browserName');
}
If you want to avoid the a browser, you may want to do this:
it('User should see a message that he has already been added to the campaing when entering the same email twice', function () {
browser.getCapabilities().then(function (capabilities) {
browserName = capabilities.caps_.browserName;
platform = capabilities.caps_.platform;
}).then(function () {
console.log('Browser:', browserName, 'on platform', platform);
if (browserName === 'internet explorer') {
console.log('IE Was avoided for this test.');
} else {
basePage.email.sendKeys('bruno#test.com');
console.log('Mande el mail');
basePage.subscribe.click().then(function () {
basePage.confirmMessage('Contact already added to target campaign');
});
}
});
});

Adding new Module is not working in angularjs

i am trying to add a new Module to my application.
My HTML for index page is
<body ng-app="com.app">
In my app.js
angular.module('mod1', ['ngResource']);
angular.module('mod2', []); //this is module i want to add
var app = angular.module('com.app', ['ngResource','mod1','mod2']);
My Controllers1.js
var Controllers = angular.module('mod1');
Controllers.controller('ctrl1', function($scope,$http) {});
Controllers.controller('ctrl2', function($scope,$http) {}); //function for module 2
when i try to add this ctrl2 to my "controllers1.js" it works , but if i add this in my other js say "controllers2.js", its not working .
My controllers2.js is
'use strict';
var mymodule = angular.module('mod2');
mymodule.controller('ctrl2', function() {
console.debug("Testing...");
});
summary of my question is : when i try to add my ctrl2 function to new module, its not working and on firefox console i am getting error
Error: Argument 'ctrl2' is not a function, got undefined
assertArg#http://localhost:8080/tm-webapp/resources/lib/angular.js:1039
assertArgFn#http://localhost:8080/tm-webapp/resources/lib/angular.js:1050
#http://localhost:8080/tm-webapp/resources/lib/angular.js:4802
update#http://localhost:8080/tm-webapp/resources/lib/angular.js:14198
Scope.prototype.$broadcast#http://localhost:8080/tm-webapp/resources/lib/angular.js:8307
updateRoute/<#http://localhost:8080/tm-webapp/resources/lib/angular.js:7463
qFactory/defer/deferred.promise.then/wrappedCallback#http://localhost:8080/tm-webapp/resources/lib/angular.js:6846
qFactory/defer/deferred.promise.then/wrappedCallback#http://localhost:8080/tm-webapp/resources/lib/angular.js:6846
qFactory/ref/<.then/<#http://localhost:8080/tm-webapp/resources/lib/angular.js:6883
Scope.prototype.$eval#http://localhost:8080/tm-webapp/resources/lib/angular.js:8057
Scope.prototype.$digest#http://localhost:8080/tm-webapp/resources/lib/angular.js:7922
Scope.prototype.$apply#http://localhost:8080/tm-webapp/resources/lib/angular.js:8143
done#http://localhost:8080/tm-webapp/resources/lib/angular.js:9170
completeRequest#http://localhost:8080/tm-webapp/resources/lib/angular.js:9333
createHttpBackend/</xhr.onreadystatechange#http://localhost:8080/tm-webapp/resources/lib/angular.js:9304
I am stuck here for a long, kindly help me i shall be very thankful.
Regards,
Make sure that in your file loader (script tags, requirejs, whatever) Controllers1.js is right next to controllers2.js.
PS: some operating systems / webservers (e.g. the server inside karma on windows) are case sensitive. So try to use same case for your files (either upper or lower).
You can try this plunker http://plnkr.co/edit/tKIPDQ54JDexB7LAJpDR to see if it works in the way you want.

Loading a mock JSON file within Karma+AngularJS test

I have an AngularJS app set up with tests using Karma+Jasmine. I have a function I want to test that takes a large JSON object, converts it to a format that's more consumable by the rest of the app, and returns that converted object. That's it.
For my tests, I'd like you have separate JSON files (*.json) with mock JSON content only--no script. For the test, I'd like to be able to load the JSON file in and pump the object into the function I'm testing.
I know I can embed the JSON within a mock factory as described here: http://dailyjs.com/2013/05/16/angularjs-5/ but I really want the JSON to not be contained within script--just straight JSON files.
I've tried a few things but I'm fairly noob in this area. First, I set up my Karma to include my JSON file just to see what it would do:
files = [
...
'mock-data/**/*.json'
...
]
This resulted in:
Chrome 27.0 (Mac) ERROR
Uncaught SyntaxError: Unexpected token :
at /Users/aaron/p4workspace4/depot/sitecatalyst/branches/anomaly_detection/client/anomaly-detection/mock-data/two-metrics-with-anomalies.json:2
So then I changed it to just serve the files and not "include" them:
files = [
...
{ pattern: 'mock-data/**/*.json', included: false }
...
]
Now that they're only served, I thought I'd try to load in the file using $http from within my spec:
$http('mock-data/two-metrics-with-anomalies.json')
When I ran the spec I received:
Error: Unexpected request: GET mock-data/two-metrics-with-anomalies.json
Which in my understanding means it expects a mocked response from $httpBackend. So...at this point I didn't know how to load the file using Angular utilities so I thought I'd try jQuery to see if I could at least get that to work:
$.getJSON('mock-data/two-metrics-with-anomalies.json').done(function(data) {
console.log(data);
}).fail(function(response) {
console.log(response);
});
This results in:
Chrome 27.0 (Mac) LOG: { readyState: 4,
responseText: 'NOT FOUND',
status: 404,
statusText: 'Not Found' }
I inspect this request in Charles and it's making a request to
/mock-data/two-metrics-with-anomalies.json
Whereas the rest of the files I've configured to be "included" by Karma are being requested at, for example:
/base/src/app.js
Apparently Karma's setting up some sort of base directory to serve the files from. So for kicks I changed my jquery data request to
$.getJSON('base/mock-data/two-metrics-with-anomalies.json')...
And it works! But now I feel dirty and need to take a shower. Help me feel clean again.
I'm using an angular setup with angular seed. I ended up solving this with straight .json fixture files and jasmine-jquery.js. Others had alluded to this answer, but it took me a while to get all the pieces in the right place. I hope this helps someone else.
I have my json files in a folder /test/mock and my webapp is in /app.
my karma.conf.js has these entries (among others):
basePath: '../',
files: [
...
'test/vendor/jasmine-jquery.js',
'test/unit/**/*.js',
// fixtures
{pattern: 'test/mock/*.json', watched: true, served: true, included: false}
],
then my test file has:
describe('JobsCtrl', function(){
var $httpBackend, createController, scope;
beforeEach(inject(function ($injector, $rootScope, $controller) {
$httpBackend = $injector.get('$httpBackend');
jasmine.getJSONFixtures().fixturesPath='base/test/mock';
$httpBackend.whenGET('http://blahblahurl/resultset/').respond(
getJSONFixture('test_resultset_list.json')
);
scope = $rootScope.$new();
$controller('JobsCtrl', {'$scope': scope});
}));
it('should have some resultsets', function() {
$httpBackend.flush();
expect(scope.result_sets.length).toBe(59);
});
});
The real trick was the jasmine.getJSONFixtures().fixturesPath='base/test/mock';
I had originally set it to just test/mock but it needed the base in there.
Without the base, I got errors like this:
Error: JSONFixture could not be loaded: /test/mock/test_resultset_list.json (status: error, message: undefined)
at /Users/camd/gitspace/treeherder-ui/webapp/test/vendor/jasmine-jquery.js:295
Serving JSON via the fixture is the easiest but because of our setup we couldn't do that easily so I wrote an alternative helper function:
Repository
Install
$ bower install karma-read-json --save
OR
$ npm install karma-read-json --save-dev
OR
$ yarn add karma-read-json --dev
Usage
Put karma-read-json.js in your Karma files. Example:
files = [
...
'bower_components/karma-read-json/karma-read-json.js',
...
]
Make sure your JSON is being served by Karma. Example:
files = [
...
{pattern: 'json/**/*.json', included: false},
...
]
Use the readJSON function in your tests. Example:
var valid_respond = readJSON('json/foobar.json');
$httpBackend.whenGET(/.*/).respond(valid_respond);
I've been struggling to find a solution to loading external data into my testcases.
The above link: http://dailyjs.com/2013/05/16/angularjs-5/
Worked for me.
Some notes:
"defaultJSON" needs to be used as the key in your mock data file, this is fine, as you can just refer to defaultJSON.
mockedDashboardJSON.js:
'use strict'
angular.module('mockedDashboardJSON',[])
.value('defaultJSON',{
fakeData1:{'really':'fake2'},
fakeData2:{'history':'faked'}
});
Then in your test file:
beforeEach(module('yourApp','mockedDashboardJSON'));
var YourControlNameCtrl, scope, $httpBackend, mockedDashboardJSON;
beforeEach(function(_$httpBackend_,defaultJSON){
$httpBackend.when('GET','yourAPI/call/here').respond(defaultJSON.fakeData1);
//Your controller setup
....
});
it('should test my fake stuff',function(){
$httpBackend.flush();
//your test expectation stuff here
....
}
looks like your solution is the right one but there are 2 things i don't like about it:
it uses jasmine
it requires new learning curve
i just ran into this problem and had to resolve it quickly as i had no time left for the deadline, and i did the following
my json resource was huge, and i couldn't copy paste it into the test so i had to keep it a separate file - but i decided to keep it as javascript rather than json, and then i simply did:
var someUniqueName = ... the json ...
and i included this into karma conf includes..
i can still mock a backend http response if needed with it.
$httpBackend.whenGET('/some/path').respond(someUniqueName);
i could also write a new angular module to be included here and then change the json resource to be something like
angular.module('hugeJsonResource', []).constant('SomeUniqueName', ... the json ... );
and then simply inject SomeUniqueName into the test, which looks cleaner.
perhaps even wrap it in a service
angular.module('allTestResources',[]).service('AllTestResources', function AllTestResources( SomeUniqueName , SomeOtherUniqueName, ... ){
this.resource1 = SomeUniqueName;
this.resource2 = SomeOtherUniqueName;
})
this solutions was faster to me, just as clean, and did not require any new learning curve. so i prefer this one.
I was looking for the same thing. I'm going to try this approach. It uses the config files to include the mock data files, but the files are a little more than json, because the json needs to be passed to angular.module('MockDataModule').value and then your unit tests can also load multiple modules and then the value set is available to be injected into the beforeEach inject call.
Also found another approach that looks promising for xhr requests that aren't costly, it's a great post that describes midway testing, which if I understand right lets your controller/service actually retrieve data like in an e2e test, but your midway test has actual access to the controller scope (e2e doesn't I think).
There are Karma preprocessors that work with JSON files also. There is one here:
https://www.npmjs.org/package/karma-ng-json2js-preprocessor
And shameless plug, this is one I developed that has RequireJS support
https://www.npmjs.org/package/karma-ng-json2js-preprocessor-requirejs
You can use the karma-html2js-preprocessor to get the json files added to the __html__ global.
see this answer for details: https://stackoverflow.com/a/22103160/439021
Here is an alternative to Cameron's answer, without the need for jasmine-jquery nor any extra Karma config, to test e.g. an Angular service using $resource :
angular.module('myApp').factory('MyService', function ($resource) {
var Service = $resource('/:user/resultset');
return {
getResultSet: function (user) {
return Service.get({user: user}).$promise;
}
};
});
And the corresponding unit test :
describe('MyServiceTest', function(){
var $httpBackend, MyService, testResultSet, otherTestData ;
beforeEach(function (done) {
module('myApp');
inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
MyService = $injector.get('MyService');
});
// Loading fixtures
$.when(
$.getJSON('base/test/mock/test_resultset.json', function (data) { testResultSet = data; }),
$.getJSON('base/test/mock/test_other_data.json', function (data) { otherTestData = data; })
).then(done);
});
it('should have some resultset', function() {
$httpBackend.expectGET('/blahblahurl/resultset').respond(testResultSet);
MyService.getResultSet('blahblahurl').then(function (resultSet) {
expect(resultSet.length).toBe(59);
});
$httpBackend.flush();
});
});

Resources