expect (js) not working inside superagent (js) - node.js

I'm trying to do TDD for the Rest APIs that I've been creating. New to NodeJS.
I've created a Rest API, and on the response I want to perform all the expect checks. To make an HTTP request I'm using SuperagentJS (also tried RequestJS).
Here is how my code looks like (Snippet only, not whole code)
var expect = require("chai").expect;
var request = require("superagent");
describe("Creation of New Entity", function(){
it("Create a New Entity", function(){
request
.get("http://localhost")
.end(function(err, httpResponse){
expect("1234").to.have.length(3);//equals(500);
expect(200).to.equals(200);
});
});
});
No matter what I try, mocha always gives successful result. (All test cases passed)
Please tell what I'm missing here. What should I do to implement test cases on httpRespnse. I'm sure that request is working fine, because whenever I use console.log(httpResponse.text), it is returning the default apache home page.

All networking in node.js is asynchronous, therefore you must use the mocha asynchronous flavor of it("Create a New Entity", function(done) { and call the done callback when your test is done.
var expect = require("chai").expect;
var request = require("superagent");
describe("Creation of New Entity", function(){
it("Create a New Entity", function(done){
request
.get("http://localhost")
.end(function(err, httpResponse){
expect(err).not.to.exist();
expect("1234").to.have.length(3);//equals(500);
expect(200).to.equals(200);
done()
});
});
});

Related

How can I use nock.js to mock node-webshot requests?

What is proper way to mock requests sent by node Webshot during a test using nock.js?
I tried following code to capture mocked response of http://example.com/foo.html as foo.png but the mock doesn't seem to work.
const nock = require("nock");
const webshot = require("webshot");
describe("mock webshot request", function(){
this.timeout(20000);
beforeEach(function(){
nock("http://example.com").persist().get("/foo.html").reply(200, "<h1>Foo</h1>");
});
afterEach(function () {
nock.cleanAll();
});
it("captures mocked response", function(done){
webshot("http://example.com/foo.html", "foo.png",function(err) {
nock.isDone();
if(!err) done();
});
});
});
Edit:
The solution was to pass mocked response body to Webshot rather than url:
webshot("<h1>Foo</h1>", ...
Nock expects the http request to happen in the same process.
Note: node-webshot is a wrapper for PhantonJS which run in another process.
In your case Nock is setup in one process, but the http request happens in another process. So you cannot mock http request done by node-webshot like the way your are currently doing.
What you need is support for mocking http request built into node-webshot i.e you will have to add this feature to node-webshot if it doesn't have it.

http.request callback not called in mocha and chai unit test

I'm trying to unit test a simple http REST client using mocha and chai libraries for Node.js with this code:
var chai = require('chai');
var asrt = require('chai').assert;
var client = require('../index');
describe('#Do successful', function () {
it('should pass when schema, host and port are provided', function () {
client.do('http:', 'localhost', '8080', '', function (result) {
console.log("starting assertions");
asrt.isAbove(result.items.length,0);
// ... other assertions
});
});
});
when I run the test with npm test, the test "passes" but the line that logs "starting assertions" is never printed, because the client.do function callback is never called, but I see that the server properly received the request and responded.
I'm obviously missing something, but I can't understand what in particular. Please notice that:
1) a very similar piece of code used in a non-test file produces the expected outcome (which is: the callback is called and the result data if filled with the response data).
2) Again, I'm testing a client, not a server, so I suppose I shuldn't use the done() function (but I tried as well, and didn't work).
Have you any hint on how to fix this? Thanks
Assuming that client.do is asynchronous because what you described is inline with the test executing, firing of asynchronous request, and not waiting for the response.
In this case the solution IS to use an asynchronous test with the done parameter:
var chai = require('chai');
var asrt = require('chai').assert;
var client = require('../index');
describe('#Do successful', function () {
it('should pass when schema, host and port are provided', function (done) {
client.do('http:', 'localhost', '8080', '', function (result) {
console.log("starting assertions");
asrt.isAbove(result.items.length,0);
// ... other assertions
// TEST WAITS FOR TIMEOUT OR UNTIL done() IS CALLED
done();
});
});
});

Sails.js and Mocha: Using supertest to create a new model

I'm currently setting up testing infrastructure for my Sails app, and it was going smoothly until I tried testing API requests with supertest.
I'm trying to test some of my controller methods (that I implemented instead of using the default blueprint routes), but it seems like the API request isn't even going through. The reason I think this is because I can run npm test and this code will run fine, but if I change the POST path to /datamodel/create5, where create5() does NOT exist as a controller method, it still runs fine... In both cases, a DataModel model is NOT created. I've included some code below.
This is what my code looks like:
var request = require('supertest');
var assert = require('assert');
var async = require('async');
var stubs = require('../stubs.js');
describe('DataModel', function() {
var testDataModel;
var dataModelParams = stubs.dataModelStub(); // simply returns a JSON dictionary
describe('#create()', function() {
describe('data model import', function() {
it('should import a new data model.', function (done) {
var agent = request.agent(sails.hooks.http.app);
agent
.post('/datamodel/create')
.send(dataModelParams)
.expect(302)
.end(function (err, res) {
if (err) {
throw new Error(err);
}
console.log(res.dataModel);
DataModel.find().exec(function (err, dataModels) {
console.log(dataModels); // should return an array of 1 model but returns empty array instead
done();
});
});
});
});
});
Snippet of my controller code:
create: function(req, res) {
DataModel.create(req.params.all(), function dataModelCreated(err, dataModel) {
if (err) {
sails.log.debug(err);
}
FlashService.success(req, 'Successfully imported a new data model.');
fs.ensureDirSync(path.join(sails.config.paths.DATASET_EXTRACT_PATH, dataModel.fileSafeName));
fs.ensureDirSync(path.join(sails.config.paths.DATASET_DOWNLOAD_ROOT, 'non_pii', dataModel.fileSafeName));
fs.ensureDirSync(path.join(sails.config.paths.DATASET_DOWNLOAD_ROOT, 'pii', dataModel.fileSafeName));
fs.ensureDirSync(path.join(sails.config.paths.DATASET_ENCRYPT_PATH, dataModel.fileSafeName));
return res.redirect('/admin/manage_data_models');
});
}
Note that the create function runs correctly in practice when my app is launched. Any suggestions as to why my test isn't working properly? I'm using sails-memory for the tests if that helps.
I figured it out. I needed to authenticate my agent first (by making a call to the login route) before any of these calls would make it through.
Essentially:
var agent = request.agent(sails.hooks.http.app);
agent.post('YOUR_LOGIN_ROUTE').end(done);
// do your tests
Hmm, don't you need to pass something that looks like the sails app to supertest? There's an example here that shows what you need to do. Look at the before function in the second answer:
How to test controller using mocha in Sails?

Are the req and res objects somehow accessible globally in NodeExpress?

req.session.username = user.username;
I'm using supertest to test route handling. In my log in handling code I have the following if a user logs in successfully -
req.session.username = user.username;
But in the supertest call back function I don't have access to the req object.
request(app)
.post('/login')
.send({username: 'dummy_username', password: 'valid_password'})
.end(function(err, res){
if (err) { return done(err); }
expect(err).toBe(null);
expect(res.status).toEqual(200);
done();
});
I would like to add in something like expect(req.session.username).toBe('dummy_username') but obviously I can't I do this when req is not available to me. So is there a way of referencing the req object?
Supertest is for testing the responses only, since testing the request (and the server-side manipulations thereof) would be testing implementation details instead of behavior. supertest isn't the right tool for this job. You can write pure unit tests for some of your server side functions, OR you can have the /login route include the user's information in the response body (which is typical) and have supertest verify that information matches what was in the request.

How to mock request and response in nodejs to test middleware/controllers?

My application has several layers: middleware, controllers, managers. Controllers interface is identical to middlewares one: (req, res, next).
So my question is: how can I test my controllers without starting the server and sending 'real' requests to localhost. What I want to do is to create request, response instances as nodejs does and then just call controllers method.
Something like this:
var req = new Request()
var res = new Response()
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)
Any advice is highly appreciated. Thanks!
P.S. the reason why I want to do this is that at the end I would like to test whether the response object contains correct variables for the jade views.
There's a semi decent implementation at node-mocks-http
Require it:
var mocks = require('node-mocks-http');
you can then compose req and response objects:
req = mocks.createRequest();
res = mocks.createResponse();
You can then test your controller directly:
var demoController = require('demoController');
demoController.login(req, res);
assert.equal(res.json, {})
caveat
There is at time of writing an issue in this implementation to do with the event emitter not being fired.
Since JavaScript is a dynamically typed language you can create mock objects and passing them to your controllers as follow:
var req = {};
var res = {};
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)
If your controller needs a particular piece of data or functionality from your request or response object you'll need to provide such data or functionality in your mocks. For example,
var req = {};
req.url = "http://google.com"; // fake the Url
var res = {};
res.write = function(chunk, encoding) {
// fake the write method
};
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)
I would try using dupertest for this. It's a node module I created for the very purpose of easy controller testing without having to spin up a new server.
It keeps the familiar syntax of node modules like request or supertest, but again, without the need to spin up a server.
It runs a lot like Hector suggested above, but integrates with a test framework like Jasmine to feel a little more seamless.
An example relating to your question may look like:
request(controller.get_user)
.params({id: user_id})
.expect(user, done);
Or the more explicit longhand version:
request(controller.get_user)
.params({id: user_id})
.end(function(response) {
expect(response).toEqual(user);
done();
});
Note: the examples assume user_id and user are defined somewhere, and that the controller grabs and returns a user based on id.
Edit: reading your response to an answer above, I will admit the downside currently is that this module does not integrate a more robust mock request or response object by default. dupertest makes it super easy to extend and add properties to both req and res, but by default they are pretty bare.
If you want to use the real req and res objects, you have to send real requests to the server. However this is much easier than you might think. There are a lot of examples at the express github repo. The following shows the tests for req.route
var express = require('../')
, request = require('./support/http');
describe('req', function(){
describe('.route', function(){
it('should be the executed Route', function(done){
var app = express();
app.get('/user/:id/edit', function(req, res){
// test your controllers with req,res here (like below)
req.route.method.should.equal('get');
req.route.path.should.equal('/user/:id/edit');
res.end();
});
request(app)
.get('/user/12/edit')
.expect(200, done);
})
})
})
A bit old post, but I would like to give my 2 cents. The approach you want to take depends on whether you are doing unit testing or integration testing. If you are going down the route of using supertest, that means you are running the actual implementation code and that means you are doing integration testing. If that's what you want to do this approach is fine.
But if you are doing unit testing, you would mock req and res objects (and any other dependencies involved). In the below code (non-relevant code removed for brevity), I am mocking res and giving just a mock implementation of json method, as that's the only method I need for my tests.
// SUT
kids.index = function (req, res) {
if (!req.user || !req.user._id) {
res.json({
err: "Invalid request."
});
} else {
// non-relevent code
}
};
// Unit test
var req, res, err, sentData;
describe('index', function () {
beforeEach(function () {
res = {
json: function (resp) {
err = resp.err;
sentData = resp.kids;
}
};
});
it("should return error if no user passed in request", function () {
req = {};
kidsController.index(req, res);
expect(err).to.equal("Invalid request.");
});
/// More tests....
})
Take a look at node-tdd and the useNock flag. It builds on top of mocha and nock and automatically creates and uses a recording file for each test.
We love that it's so easy to use. Basically just "enable and forget" and focus on writing requests / test cases. If requests for a test change, one still needs to delete or adjust the recording file, but at least it's entirely separate from the code.

Resources