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.
Related
I am trying to understand the use case of end() function while writing the API test script in mocha and Chai. Also at the same time, I am confused about whether I shall use the done() function here or not and also what is the exact difference between .end() and .done().
Here's the code:
describe("Suite", () => {
it('Post Test case', (done) => {
request('https://reqres.in')
.post('/api/users')
.send({
"name": "morpheus",
"job": "leader"
})
.set('Accept', 'application/json')
.expect(200,'Content-Type', /json/)
.then((err,res) => {
console.log(JSON.stringify(err))
console.log(JSON.stringify(res.body))
console.log(JSON.stringify(" "))
})
done();
});
it('Put Test case', (done) => {
request('https://reqres.in')
.put('/api/users/2')
.send({
"name": "morpheus",
"job": "zion residents"
})
.expect(200)
.end((err, res) => {
console.log(JSON.stringify(err))
console.log(JSON.stringify(res.body))
console.log(JSON.stringify(" "))
})
done();
})
})
You are mixings things a little bit.
end is a method of the expressjs framework and it ends the server response.
done is a parameter of mocha test function. You call this parameter when you are finished with your asynchronous test to let the mocha know that your asynchronous code is done executing, and it can move on to another test.
And in your case, you need them both.
Goal:
I am trying to test my authentication RESTful API. The tools i am using are NodeJS with the modules: Mocha, Supertest(.agent) and chai(.assert).
What i tried:
var users = [ new User("admin", "secretPass"), new User("guest", "Pass")];
describe('request some protected data', function(){
users.forEach(function(user){
before(function(){
agent.post('/login').send({ user.username, user.key })
.end(function(err, res) {
}
}
it('get data', function(done){
agent.get('/data').send({ user.username, user.key })
.end(function(err, res) {
// assertions on data
}
}
}
}
The problem:
Using something similar to the snippet above results in multiple before functions being executed at once and after that all the tests(it).
So agent will always be logged in as the last user in users.
I tried to replace before with beforeEach and place it above users.forEach, but then user will be out of scope.
Can anyone provide me with a small snippet of code that will explain a suitable solution for my problem?
You need to tell Mocha that your before function is asynchronous, by accepting a done parameter and calling it when logging in has completed, e.g.
before(function(done){
agent.post('/login').send({ user.username, user.key })
.end(function(err, res) {
// I assume you're logged in here...
done();
}
}
Of course, you'll also want to add the required error handling etc. You'll probably want to create a new describe block for each user too, otherwise all of the login calls will run before any user tests happen, e.g.
users.forEach(function(user){
describe("user X tests", function() { // <-- NEW
before(function(){
agent.post('/login').send({ user.username, user.key })
.end(function(err, res) {
}
}
it('get data', function(done){
agent.get('/data').send({ user.username, user.key })
.end(function(err, res) {
// assertions on data
}
}
}); // <- NEW
}
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?
I'm working on some tests for strongloop/loopback APIs using supertest and mocha. One of the standard endpoints is Model/update. Update is actually a form of PersistedModel.updateAll which takes in a query and then posts to all entries that match the query. This is a picture of what a successful request looks like in the explorer:
Notice from the picture that the request URL is mainly just a query string, and that it returns 204. I know from the superagent docs that you can submit querys with a post. However I'm having a lot of trouble duplicating this with my tests.
Here are my require statements:
var request = require('supertest');
var app = require('../server');
var assert = require('chai').assert;
var chance = require('chance').Chance();
Here are my tests
describe('/api/Points/update', function(){
var updatedZip = "60000";
it('should grab a Point for a before reference', function(done) {
json('get', '/api/Points/' +addID )
.end(function(err, res) {
assert.equal(res.body.zipcode, addZip, 'unexpected value for zip');
done();
});
});
it('should update the Point w/ a new zipcode', function(done) {
var where = {"zipcode": "60035"};
var data ={"zipcode": updatedZip};
request(app)
.post('/api/Points/update')
.query({"where": {"zipcode": "60035"}})
.send({
data : data
})
.end(function(err, res) {
assert.equal(res.status, 204, 'update didnt take');
done();
});
});
it('should check to see that the Point was updated', function(done) {
json('get', '/api/Points/' +addID )
.end(function(err, res) {
assert.equal(res.body.zipcode, updatedZip, 'updated zip was not applied');
done();
});
});
The first test passes, meaning that it returned a 204 as the status of the request however it fails the second test meaning that even though it found the query acceptable it didn't actually apply the update. I've tried a number of different formulations but none of them have worked. Please let me know how I could possibly simulate this! Thanks in advance for your help!
describe("Company Controller", function() {
var apiUrl;
beforeEach(function(done) {
apiUrl = "http://localhost:3001";
done();
});
it('should register a client without error and return an API key', function(done) {
request({
uri: apiUrl + '/api/v1/company',
method: 'POST',
json: true,
form: {
name: 'My Company'
}
}, function(err, res, body) {
should.not.exist(err);
res.statusCode.should.eql(200);
body.status.should.eql('ok');
should.exist(body.company.api_key);
done();
});
});
it('should generate a new API key for a company', function(done) {
// NEED THE client_id generated in the previous test
});
after(function(done) {
Company.remove().exec();
done();
});
});
How do I get the client_id in the next test?
Generally speaking, making tests with side effects is a brittle practice. Do this often enough, you'll start to encounter some very difficult-to-debug errors where your test suite fails even though every test runs in isolation, and the error messages won't be any help. Ideally every test should "leave the campground" in the same state that it found it.
If you're really insistent on doing this, you could of course set a global variable. Some other options include:
Merging the two tests. Yes, this violates a principle of Single-Assertion-Per-Test that some people hold, but I think the Avoid-Side-Effects principle trumps that one.
Put the registration in the beforeEach function. Yes, by doing this you'll be registering multiple clients per test suite run. This is still my preferred approach.
You should use a stub. For example sinonjs. This way you use a fake function to test another. You don't need to use beforeEach and afterEach if you only need to stub the function once you can define it inside the it function.
describe("Company controller", function() {
describe("dependantFunction()", function() {
var stub;
beforeEach(function() {
stub = sinon.stub(module, 'targetFunction');
stub.onCall(0).callsArgWith(1, ...some valid results...);
stub.onCall(1).callsArgWith(1, ...some expected error...);
stub.throws();
});
afterEach(function() {
stub.restore();
});
it("should do something", function() {
var result;
module.targetfunction(null, result);
dependantfunction(result);
....your tests here....
});
it("should do something else", function() {
...
});
});
});