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.
Related
I'm using mocha for node.js functional testing.
There are several files in my test.
How can I run a piece of code for only one time before all tests start?
For example, I may have to set up a docker container before all tests start.
Is it possible to do this with mocha?
The before hook runs 1 time for every test file. This doesn't meet my needs.
You can have 'root' level hooks, if you put them outside of any describe blocks. So you can put your relevant code in any files inside of the test folder.
before(function() {
console.log('before any tests started');
});
See the docs: http://mochajs.org/#root-level-hooks
Mocha 8 introduces the concept of root hook plugins. In your case, the relevant ones are beforeAll and afterAll, which will run once before/after all tests, so long you tests run in serial.
You can write:
exports.mochaHooks = {
beforeAll(done) {
// do something before all tests run
done();
},
};
And you'll have to add this file using the --require flag.
See docs for more info.
There is a very clean solution for this. Use --file as parameter in your mocha command. It works like a global hook for your tests.
xargs mocha -R spec --file <path-to-setup-file>
A setup file can look like this:
'use strict';
const mongoHelper = require('./mongoHelper.js');
console.log("[INFO]: Starting tests ...");
// connect to database
mongoHelper.connect()
.then(function(connection){
console.log("[INFO]: Connected to database ...");
console.log(connection);
})
.catch(function(err){
console.error("[WARN]: Connection to database failed ...");
console.log(err);
});
Unfortunately I have not found a way to use async/await in this setup files. So I think you may have to be conent with using "old" promise and callback code.
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
Let's say I have some tests that require jQuery. Well, we don't have to make believe, I actually have the tests. The test themselves are not important, but the fact they depend on jQuery is important.
Disclaimer: this is node.js so you cannot depend on global variables in your solution. Any dependency must be called into the file with require.
On the server we need this API (to mock the window object required by server-side jquery)
// somefile.js
var jsdom = require("jsdom").jsdom;
var window = jsdom().parentWindow();
var $ = require("jquery")(window);
// my tests that depend on $
// ...
On the client we need a slightly different API
// somefile.js
// jsdom is not required obviously
// window is not needed because we don't have to pass it to jquery explicitly
// assume `require` is available
// requiring jquery is different
var $ = require("jquery");
// my tests that depend on $
// ...
This is a huge problem !
The setup for each environment is different, but duplicating each test just to change setup is completely stupid.
I feel like I'm overlooking something simple.
How can I write a single test file that requires jQuery and run it in multiple environments?
in the terminal via npm test
in the browser
Additional information
These informations shouldn't be necessary to solve the fundamental problem here; a general solution is acceptable. However, the tools I'm using might have components that make it easier to solve this.
I'm using mocha for my tests
I'm using webpack
I'm not married to jsdom, if there's something better, let's use it !
I haven't used phantomjs, but if it makes my life easier, let's do it !
Additional thoughts:
Is this jQuery's fault for not adhering to an actual UMD? Why would there be different APIs available based on which env required it?
I'm using karma to run my unit tests from the command line directly (CI too, with gulp).
Karma uses phantomjs to run the tests inside of a headless browser, you can configure it to run in real browsers too.
Example of karma configuration inside of gulp:
// Run karma tests
gulp.task("unit", function (done) {
var parseConfig = require("karma/lib/config").parseConfig,
server = karma.server,
karmaConfig = path.resolve("karma.conf.js"),
config = parseConfig(karmaConfig, {
singleRun: true,
client: {
specRegexp: ".spec.js$"
}
});
server.start(config, done);
});
In case of my tests it takes approx. 10 seconds to run 750 tests, so it's quite fast.
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.
I am writing a single page JavaScript application using Backbone and Backbone.Marionette. I am using AMD modules and RequireJS to help organize my code and manage dependencies. I am also using Mocha as my testing framework for TDD/BDD.
Everything was working fine until I wanted to introduce stubs, mocks, and spies using Sinon.JS. After a lot of searching, I came across a page on test frameworks in the RequireJS wiki and Squire.js, which seemed like it would suit my needs well. However, when I try to use Squire.js to load a module, Mocha suddenly reports global leaks for the module's dependencies. There are no leaks reported if I load the module directly using Require.JS.
For example, the following test code does not cause Mocha to report any leaks:
define(['app/app'], function(app) {
describe('App', function() {
it('Should define a \'header\' region', function() {
expect(app.headerRegion).to.exist;
});
it('Should define a \'main\' region', function() {
expect(app.mainRegion).to.exist;
});
});
return {
name: "App"
};
});
However, converting the code to use Squire.js as follows causes Mocha to report leaks for jQuery, Backbone, and Marionette (dependencies of app.js):
define(['Squire'], function(Squire) {
describe('App', function() {
var testContext = {};
beforeEach(function(done) {
testContext.injector = new Squire();
testContext.injector.require(['app/app'], function(app) {
testContext.app = app;
done();
});
});
it('Should define a \'header\' region', function() {
expect(testContext.app.headerRegion).to.exist;
});
it('Should define a \'main\' region', function() {
expect(testContext.app.mainRegion).to.exist;
});
});
return {
name: "App"
};
});
What am I doing wrong? I am totally baffled that Mocha does not report a leak with RequireJS but does with Squire.js. I also tried some of the other solutions I found in another StackOverflow question on mocking RequireJS dependencies, such as the custom function and testr.js, prior to Squire.js and had similar results. To date, I've been unable to find an example that uses Mocha, RequireJS, and Sinon.JS all together.
I've placed my current code base on GitHub in case there is some critical information that I have left out or something. The test in question can be found in test\spec\test.app.js.
Any assistance is greatly appreciated. I'd very much like to get past monkeying with my test setup and on to actually working on my app. Thanks in advance.
After thinking this through further, I realized that this is actually expected behavior and a side-effect of the timing of when app.js is loaded for testing.
My tests are loaded via RequireJS in a require statement shown below
require([
'spec/test.smoketest',
'spec/test.app'
], runMocha);
where runMocha is simply a function that simply calls mocha.run().
It occurred to me that the way Mocha most likely detects global leaks is to compare what is registered globally before and after each test is run. In the first example above, where leaks are not reported, jQuery, Backbone, and Marionette are loaded by RequireJS before mocha.run() is called as part of loading the test.app.js module. On the other hand, jQuery, Backbone, and Marionette are loaded as part of the tests themselves in the second example.
Thus, the first configuration does not report any leaks because jQuery, Backbone, and Marionette are already registered globally before mocha.run() is called. The second configuration reports leaks because they are registered during the tests.
Now that I understand what's going on and that this is expected, I'm comfortable configuring Mocha to allow these global objects. This can be done in the Mocha configuration as shown below:
mocha.setup({
ui: "bdd",
globals:["_", "$", "jQuery", "Backbone", "Marionette"]
});