Keeping client state when an api with mocha - node.js

My api can be asked to create an object, then later asked to update that same object, so my test file does this...
var foobarId; // this might be a mistake
it("should create a single foobar", function(done) {
server
.post("/foobar?key=value")
.expect("Content-type", /json/)
.expect(200)
.end(function(err, res) {
res.status.should.equal(200);
res.body.should.have.property('key', 'value');
foobarId = res.body._id;
done();
});
});
it("should return a foobar when I get one", function(done) {
server
.get("/foobar/" + foobarId)
.expect("Content-type", /json/)
.expect(200)
.end(function(err, res) {
res.status.should.equal(200);
res.body.should.have.property('key', 'value');
done();
});
});
So is this wrong what I'm trying here? (1) as I get more logic into the test, I risk creating logic errors in the test and needing a test for my test. (2) when the create fails, my console output gets ugly... first, the assertion error that I expect and need telling me the test failed, but then ugly traceback stuff, I think, because foobarId is undefined.
The ugliness makes me think that the good people at mocha (or supertest or wherever) didn't expect me to do what I'm doing.
Is there a right way to write this kind of test?

Related

Test caching with Mocha and Supertest

I have an express app that implements some caching/memoization in a few endpoints (the calls can take several seconds to run, so I save results for various amounts of time depending on the nature of the endpoint). When I'm running the unit tests via Mocha using Supertest, however, each call is taking the longer period of time. How can I actually test that the caching portion of my application is functioning properly?
When I run the node server by itself, I can see the time for each return (e.g. 3979.848 ms for the first, 3.180 ms for the second), and it is working as intended, but the tests aren't behaving the same way.
What do I need to do to test the caching/memoization? Can it be done with these tools? Do I need to utilize some other module?
My code looks like this:
var supertest = require('supertest');
var base_url = 'http://localhost:3000';
var server = supertest(base_url);
describe('big section', function() {
describe('test section', function() {
it('should do a thing', function(done) {
this.timeout(10000);
server
.get('/url1')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if (err) return done(err);
//stuff
done();
});
});
});
describe('test section', function() {
it('should do a similar thing, but faster', function(done) {
this.timeout(10000); //I should be able to reduce this a lot
server
.get('/url1')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if (err) return done(err);
//stuff
done();
});
});
});
});

Mocha: Writing dependent tests

I am using Mocha/Chai framework in NodeJS to write tests. They were supposed to be executed independently. Now the requirement is to execute them on conditions. For example, before you delete an employee make sure that employee is created in database. 'Create' & 'Delete' are two different APIs and although they will be executed separately, in case of 'Delete' I have to first call 'Create' API get the employeeId from its response and then execute 'Delete' for the same employeeId. What is the best way to write nested tests? This is how I write tests separately:
var _customHeaders = {
"authToken": "AVeryLargeStringWithActualToken"
};
describe('POST /Employee/Create', function() {
it('should create a new employee in database.', function(done) {
request
.get('/Employee/Create/')
.set(_customHeaders)
.send({ "firstName": "ABC", "lastName": "XYZ", "departmentId": 123 })
.expect(200)
.expect('Content-Type', 'application/json')
.end(function(err, res) {
expect(res.body.success).to.equal(true);
expect(res.body.message).to.equal('Employee Created!');
done();
});
});
});
describe('POST /Employee/Delete', function() {
it('should delete an employee from database.', function(done) {
request
.get('/Employee/Delete/')
.set(_customHeaders)
.send({ "employeeId": 123 })
.expect(200)
.expect('Content-Type', 'application/json')
.end(function(err, res) {
expect(res.body.success).to.equal(true);
expect(res.body.message).to.equal('Employee Deleted!');
done();
});
});
});
How can I write 'Delete' so that it first creates an Employee and then move forward to delete if 'Create' is successful?
If you need setup before your deletion test, where the necessary Employee is first created, then this should probably be in a 'beforeEach' hook inside your describe block for the deletion test/s. This should be completely separate from the test that actually tests the Employee creation (though common code could be factored out into a helper function). You may even want this setup code to put the employee directory into the database, rather than going through the REST API like the function which actually tests this operation.

Mocha&Chai: Writing assertion

I am writing test cases using mocha and chai for the first time. This is a very simple response returned by my service:
{
"success": true,
"message": "Done"
}
I have written assertion like this:
describe('GET /TestService', function() {
it('should run successfully.', function(done) {
request
.get('/myApp/TestService/')
.expect(200)
.expect('Content-Type', 'application/json')
.end(function(err, res) {
expect(res.body.success).to.equal(true);
expect(res.body.message).to.equal('Done');
});
});
});
When I execute the test it returns:
Uncaught AssertionError: expected undefined to equal true
What is wrong with this? This is my first ever encounter with Mocha and Chai. Maybe I am missing a very basic thing. This is just the first step. Can someone push me forward?

Is it possible to add information to the error message in supertest

I'm utilizing supertest with mocha to test a nodejs express app. Everything is fine expect I'd like a little more descriptive error messages. That's not to say the messages are currently bad, they're not. I'd just like a little more information.
For example:
it('should successfully post my data and return a valid JSON', function(done) {
.post(url)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.send(data)
.expect(201, resultBody)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
If an error should occur, such that the resultBody doesn't match the actual result, it'll print out a nice + expected - actual message. But I would also like to see other information (maybe the authentication or the header).
My current solution is to do the following:
.end(function(err, res) {
if (err) {
console.log(res.headers);
console.log(res.statusCode);
console.log(res.body);
return done(err);
}
done();
});
But the console.log messages appear inline with the "it" messages, before the passing/pending/failing messages and not with the actual error.
Is it possible, without too much extra effort, to put extra information with the error message?
You can fix it using the Language Chains of Chai in expect and should adding Assertion Styles:
var foo = false;
expect(foo, 'foo must be true').to.be.true;
//AssertionError: foo must be true: expected false to be true

supertest test delete method return 404 but restful client works

I use supertest to test my api, the delete endpoint works fine when testing with some restful client such as postman but failed in supertest.
it('should return 200', function (done) {
request(app)
.del('/v1/xxxx/' + id)
.expect('Content-Type', /json/)
.expect(200, done);
});
But it pass the test when I add
it('should return 200', function (done) {
request(app)
.del('/v1/xxxx/' + id)
.send({})
.expect('Content-Type', /json/)
.expect(200, done);
});
Can some one tell me why?
It is unclear from your post what this issue may be exactly. The most likely is that the '/v1/xxxx/' url is incorrect. Could it be '/api/..../v1/xxx/'+id ????
In my own case, that was the issue. AND I can report that supertest works exactly as expect for .del(...) or .delete(....).
I hope this helps someone else that hits this snag.

Resources