I am building a GUI for an app whose API is still being worked on. I have an idea of how it will look but it's not functional yet. I have to mimic its behaviour until it's ready.
I'm trying to do this with $httpBackend. I set up my installation with Yeoman.
Attempt to Install
I'm running Angular v1.2.6.
The documentation gives me three ways of installing it:
Google CDN at //ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-mocke2e.js
Bower via bower install angular-mocke2e#X.Y.Z
code.angularjs.org: //code.angularjs.org/X.Y.Z/angular-mocke2e.js
Where X.Y.Z is my version number.
Thing is none of those work. Google gives 404, and won't let me travel up the directories. Bower says no package available, and a 404 for code.angularjs.org. So I browsed code.angularjs.org and found that for 1.2.6, there is no anguler-mock
Anyway I did find a file at https://code.angularjs.org/1.2.6/angular-mocks.js which seems to have $httpBackendProvider defined in it.
When I went back to my Yeoman install - it looks like I already had angular-mocks.js installed.
So, question 1: Is this what I'm looking for to use $httpBackend?
Attempt to Use
So I try to start using it in my project:
// Gotta manually run the app to check cookies
app.run(['$cookies', '$location', '$rootScope', '$httpBackend', function($cookies, $location, $rootScope, $httpBackend){
// Some stuff....
console.log($httpBackend);
}]);
And now my app won't start. I get the following error:
But the app does show me the contents of $httpBackend. I thought that maybe I should put it into a different module, but I don't know.
So question 2: Is it normal that my app won't load once I throw $httpBackend into the app.run() call?
And question 3: Should I be putting my $httpBackend stuff into a different module while I'm testing?
And I guess lastly is Is this even the best way for me to test the API?
You can use $httpBackend to mock your services like so:
$httpBackend.whenGET(/\/api\/foo\/bar/).respond({some:'thing'});
Your app isn't loading because it wasn't expecting a request for your partials. You can avoid that by doing something like this:
$httpBackend.whenGET(/^views\/.*/).passThrough();
It would be good to break these out into individual modules so you can exclude them before deployment.
As far as it being the best solution, it depends on your needs. I would propose integrating some build tools (Grunt, Express, Protractor, etc.) that include a local node server for testing locally. Then you could just use actual services for testing, as proposed by #Ronald91.
Going through a similar situation like this on a project I am working on. Never utilized httpbackend for this but we mocked out the backend services with a MongoDB instance and in our app.js file we set up the routing as followed:
app.get( '/ui/orders/:orderId/details', function( req, res ){
mongoclient.connect( mongoUrl, function(err, db){
if( err ) throw err;
var collection = db.collection('order-details');
console.log( req.query);
collection.findOne( { orderId : req.params.orderId}, function(err, docs){
if( err ) throw err;
console.log( "Docs...");
console.log( docs );
db.close();
res.send( docs );
} );
});
});
The service call we use to utilize this routing is
ourApp.factory('orderDetails', function($resource, $routeParams) {
return function(){
return $resource('/ui/orders/:orderId/:subSystem', {orderId: $routeParams.orderId});
};
});
This is a potential answer to the "Attempt To Install" query.
Yes, angular-mocks.js is what you want. The file contains multiple modules useful for mocking. You don't have to use all of them.
For the specific case you mentioned (and the issue I'm trying to solve too, which brought me here):
include the file you found
add the following dependency to your main app module, you should be able to mock back-end requests.
var yourApp = angular.module('app', ['ngMockE2E']);
You can use the mocks module in unit tests and in application development.
Related
I'm working on a project that needs the backend to be mocked while the frontend implementation is being made.
I have a gulp structure that loads /**/*.mock.js files only for tests and while serving the source for development. I use this .mock.js files to mock test data and services and to intercept http calls for backendless development. The file looks like this:
(function() {
'use strict';
var mockResponseData = {
'mock': 'data'
};
angular
.module('module.name')
.value('mockResponseData', mockResponseData)
.config(config)
.run(run);
/** #ngInject */
function config($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
}
/** #ngInject */
function run($httpBackend) {
$httpBackend.whenPOST(/\/api\/path\/$/)
.respond(function() {
return [200, mockResponseData];
});
$httpBackend.whenGET(/^\w+.*/).passThrough();
$httpBackend.whenPOST(/^\w+.*/).passThrough();
$httpBackend.whenPUT(/^\w+.*/).passThrough();
$httpBackend.whenDELETE(/^\w+.*/).passThrough();
}
})();
As you can see, I already have the .passThrough() applied (which is the common solution for the Unexpected request issue) and it works just fine when just one .mock.js file like this exists. After creating the second file, the Unexpected request errors start to appear:
Error: Unexpected request: GET 'path/to/template.html'
After trying some things, I realized that the problem could be with the way I'm injecting $httpBackend. To avoid it from being injected in the dist files and to keep the project structure modular, I have to inject it via $provide instead of directly in the module's definition, in each module that needs it. Which is done in the config block of the code above.
If the $provide.decorator(...) line is removed from all but one .mock.js files, everything works fine again (except that the run block from the files with the line removed would start to complain about the non-existent $httpBackend, but this is not the issue here).
So, any idea of what this could be?
Thanks in advance!
P.S.: I can't miss the modularity structure and the .mock.js files cannot be included in the dist build.
So, I've solved this a while ago and now I'm answering here for future reference.
The basic problem is that I was injecting the $httpBackend service using the $provide.decorator() method, which according to the documentation, works like this:
Register a service decorator with the $injector. A service decorator intercepts the creation of a service, allowing it to override or modify the behavior of the service. The object returned by the decorator may be the original service, or a new service object which replaces or wraps and delegates to the original service.
Injecting the service like this was necessary to avoid injecting it when it wouldn't be used, but somehow, if you decorate this same service twice, AngularJS get confused and starts to throw the errors described in the question.
So, the solution is to create a .mock.js file for the main module. This way it will inject the service only once and avoid the problem:
(function() {
'use strict';
angular
.module('mainModuleName')
.config(config);
/** #ngInject */
function config($provide) {
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
}
})();
Please note that you can still add more decorators to the service as follows:
$provide.decorator('$httpBackend', function($delegate, $injector) {
// Your decorator...
});
As long as you don't inject angular.mock.e2e.$httpBackendDecorator more than once.
This is my code inside a Mean.IO package. The controller takes in a number from the URL and then passes it to a factory.
This bit of code is giving me and Unkown Provider error for $routeParams.
angular.module('mean.rotor-tablet').controller('taskListController',
function($scope,$location,$routeParams,dataFactory){
console.log("SAD");
$scope.partid=$routeParams.id;
$scope.part=dataFactory.getPart($scope.partid)
$scope.tasklist=dataFactory.getTaskList($scope.partid)
$scope.goToTask=function (task_index){
$location.path('task/'+$scope.partid+'/'+task_index);
}
})
The exact same code was working fine on an AngularJS application I was running on the LAMP stack. When I added this to Mean IO however I got this error. (in case it's important I created a new package and this is in a file called controllers.js in the controllers folder)
PS I'm a n00b to Mean.IO. The reason I chose to mention Mean.IO specifically is because the problem seems endemic to it and not to AngularJS in general
Given
3 Node.js projects Main - Framework - Repositories
Main has the two other projects connected via npm link.
In a test i wrapped the require in a method. I've got some problems resolving linked projects (details see below)
Simplified code looks like this:
module.export.resolve = function(file){
[...]//Some more logik to handle relative pathes
return require(file)
}
This works fine in most scenarios. I also worked out to get handled with relatives pathes (looking up for caller and apply pathes based on this path)
Now this is in Project Framework which is linked (npm link) to Project Main. Project main has also Project Repositories linked.
Now in Project Main i have:
require('ProjectRepositories/foo') // Works as expected
myRequire.resolve('ProjectRepositories/foo') // Returns MODULE_NOT_FOUND "Cannot find module 'ProjectRepositories/foo'
I assume the problem is that Repositories Project ist not linked in the Framework Project. But is there an other way than linking them ?
I'd prefer to have less dependencies. Any hints on that?
You are absolutely correct in that the reason why the Project Framework resolve does not work is because the requireFn being used from within that project only knows about the modules installed in that framework. This is because when you require a javascript file, node evaluates the script within the context of the module, and not the context of the current project (this is how dependency modules' requires work when from your top-level script).
What you can do, however, is provide a way for the framework resolver to use a user-specified require function to do its work, once it has transformed the paths.
module.exports.resolve = function(file, resolver) {
//Some more logik to handle relative pathes
resolver = typeof resolver == 'function' ? resolver : require;
return resolver(file)
}
Now in your code, you could do
myRequire.resolve('ProjectRepositories/foo', require);
So now your Project Main require will be used to resolve the file.
You can also take this a step further if you want and have the module be stateful and remember the resolver it's supposed to use.
var _requireFn = require;
module.exports = {
resolve: resolve,
setRequireFn: setRequireFn
};
function resolve(path) {
return _requireFn(path);
}
function setRequireFn(requireFn) {
_requireFn = requireFn;
}
On another note, I would be careful about using the term resolve because in node that's semantically used for looking up the correct file path to be required, a la require.resolve.
Finally, in terms of minimizing dependencies, I'd recommend including your subprojects in npm using github repos. This has worked pretty well for me in the past, unless your two subrepos are in a constant state of flux. See the install docs for more info.
I'm completely new to sails, node and js in general so I might be missing something obvious.
I'm using sails 0.10.5 and node 0.10.33.
In the sails.js documentation there's a page about tests http://sailsjs.org/#/documentation/concepts/Testing, but it doesn't tell me how to actually run them.
I've set up the directories according to that documentation, added a test called test/unit/controllers/RoomController.test.js and now I'd like it to run.
There's no 'sails test' command or anything similar. I also didn't find any signs on how to add a task so tests are always run before a 'sails lift'.
UPDATE-2: After struggling a lil bit with how much it takes to run unit test this way, i decided to create a module to load the models and turn them into globals just as sails does, but without taking so much. Even when you strip out every hook, but the orm-loader depending on the machine, it can easily take a couple seconds WITHOUT ANY TESTS!, and as you add models it gets slower, so i created this module called waterline-loader so you can load just the basics (Its about 10x faster), the module is not stable and needs test, but you are welcome to use it or modify it to suit your needs, or help me out to improve it here -> https://github.com/Zaggen/waterline-loader
UPDATE-1:
I've added the info related to running your tests with mocha to the docs under Running tests section.
Just to expand on what others have said (specially what Alberto Souza said).
You need two steps in order to make mocha work with sails as you want. First, as stated in the sails.js Docs you need to lift the server before running your test, and to do that, you create a file called bootstrap.test.js (It can be called anything you like) in the root path (optional) of your tests (test/bootstrap.test.js) that will be called first by mocha, and then it'll call your test files.
var Sails = require('sails'),
sails;
before(function(done) {
Sails.lift({
// configuration for testing purposes
}, function(err, server) {
sails = server;
if (err) return done(err);
// here you can load fixtures, etc.
done(err, sails);
});
});
after(function(done) {
// here you can clear fixtures, etc.
sails.lower(done);
});
Now in your package.json, on the scripts key, add this line(Ignore the comments)
// package.json ....
scripts": {
// Some config
"test": "mocha test/bootstrap.test.js test/**/*.test.js"
},
// More config
This will load the bootstrap.test.js file, lift your sails server, and then runs all your test that use the format 'testname.test.js', you can change it to '.spec.js' if you prefer.
Now you can use npm test to run your test.
Note that you could do the same thing without modifying your package.json, and typying mocha test/bootstrap.test.js test/**/*.test.js in your command line
PST: For a more detailed configuration of the bootstrap.test.js check Alberto Souza answer or directly check this file in hist github repo
See my test structure in we.js: https://github.com/wejs/we-example/tree/master/test
You can copy and paste in you sails.js app and remove we.js plugin feature in bootstrap.js
And change you package.json to use set correct mocha command in npm test: https://github.com/wejs/we-example/blob/master/package.json#L10
-- edit --
I created a simple sails.js 0.10.x test example, see in: https://github.com/albertosouza/sails-test-example
Given that they don't give special instructions and that they use Mocha, I'd expect that running mocha from the command line while you are in the parent directory of test would work.
Sails uses mocha as a default testing framework.
But Sails do not handle test execution by itself.
So you have to run it manually using mocha command.
But there is an article how to make all Sails stuff included into tests.
http://sailsjs.org/#/documentation/concepts/Testing
I want to use mocha for node.js. The last test framework I used was Rspec from Ruby on Rails so I'm trying to do it in the same way but I get cnfused by the huge framework and all the libraries I could use.
I'm following the official get started but it doesn't explains how organize the tests.
http://visionmedia.github.io/mocha/#installation
Now, I'm reading that I can use the following libraries:
https://github.com/visionmedia/should.js - Something to test model instances.
https://github.com/LearnBoost/expect.js - Minimalistic BDD assertion toolkit based on should.js
http://chaijs.com/ - Looks big, includes should, expect and another lib
https://github.com/visionmedia/better-assert - Better c-style assertions using callsite for self-documenting failure messages. (I actually don't understand the purpose so far, looks not better than others)
https://github.com/rjanicek/mocha.js-haxe - Looks to be used browser side, but mocha also said that it's running browser side.
And I know there are more, this is just the list I saw on mocha official website.
For what I can understand, it looks like chai is the one to use with mocha, what do you think about that?
And, so far, I never saw anything to help me to decide where write the tests (okay, in /test/, of course) and how organize everything.
I'm also use the great sails.js framework (based on express) and pomelo.js for different projects, I need to use the same kind of tests on both frameworks, so I'm looking for a general architecture and libraries that I can use on both (so, something not specific to sails.js but usable directly from any other framework)
This is how I plan to organize my tests, do you think that's a correct architecture?
The main issue with node is that there are a lot of frameworks, plugins, libraries and I dont know what's the best choice, node.js is really huge with a big community and that's really difficult to have an overview of all the possibilities.
How do you deal with your tests?
I found the blog post Unit Testing Sails.js Applications With Mocha helpful in regards to setting up and organizing tests.
However, because I'm using Sails version 0.10.5, I decided to clean up the Grunt configuration a bit. I added a file named mocha.js in the tasks/config/ folder with the following code:
module.exports = function(grunt) {
grunt.config.set('mochaTest', {
test: {
options: {
reporter: 'spec'
},
src: ['tests/**/*.spec.js']
}
});
grunt.loadNpmTasks('grunt-mocha-test');
};
I then registered the task by creating a file named test.js inside of tasks/register. Inside this file, I added the following code.
module.exports = function (grunt) {
grunt.registerTask('test', [
'mochaTest'
]
);
};
You can then run grunt test to see the results.
Create a file named test.js inside your test folder
for testing assertion best option is something like chai or should or expect, for testing rest api or sending http request you can use supertest. At first include all the library inside the test file
"use strict"
var should = require('should');
var assert = require('assert');
var request = require('supertest');
Now for business logic testing include the file you need. Say I have a file named LoginService inside api/services you can include it by following
var loginService = require('../api/services/LoginService');
Now you can start testing your test block will look like something similar
describe('Sample Test', function(){
var url = "http://localhost:1337/";
before(function(done){
//Anything that needed to be done before executing;
done();
});
it("Should test rest api", function(done){
var email = {'email':'sample#email.com'};
//Calling rest api with email as a part of req body
request(url)
.post('api/v1/email/isvalid')
.send(email)
// end handles the response
.end(function(err, res) {
if (err) {
throw err;
}
// Check response
res.should.have.status(200) ;
done();
});
});
it("Should test business logic", function(done){
loginService.someFunction(someParameter, function callback(data){
//do your logic test here
done();
});
});
});
Hope this helps.