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!
Related
I'm using node and supertest for a simple app. I got SQlite3 for the local test database. I did a simple test to get a super inserted into the database. I wanted to reset the database each time a test is run. I'm looking in the docs right now and can't seem to locate it. I figured I would ask here because it seems someone would most likely know the info.
const request = require('supertest');
const server = require('../server');
describe('Authentication', function() {
//database reset here
it('should create a new user /users/registration', function(done) {
request(server)
.post('/users/register')
.send({
username: 'user-name',
email: 'luser-name#gmail.com',
password: '12345'
})
.set('Accept', 'application/json')
.expect(201, done);
});
});
If you want to run any piece of code before each test, you can use beforeEach function in jest
describe('my test', () => {
beforeEach(() => {
// code to run before each test
});
test('test 1', () => {
// code
});
test('test 2', () => {
// code
});
});
So best way to do this is have some logic in your routing functions of your Api
Receive an API request
Check if ['X-MOCK-HEADER'] exists
If it does then route to the mock version of the endpoint
So your mock for create user would always return 201 OK - your mock endpoint would do something like this:
const routes = {
CREATE_USER_OK:() => { return {....} } // make sure these return proper http responses
CREATE_USER_BAD_REQUEST: () { return {...} }
}
return routes[HEADER_VALUE]()
The reason being you're testing the route not the database class in this instance, so you just want to return static data, if you wanna test something else then just change the X-MOCK-HEADER value to whatever you want and add the mock route to return the right http response/code - I'd need to know what the API code looked like to help you on the backend implementation.
If possible stay away from messing with staging databases for testing because down the road you will suffer a LOT of pain as it gradually gets filled with garbage.
Also if you're working with a front end app you can quickly prototype with static data - this is especially useful if you've got a front end team waiting for an API endpoint to say create a login screen.
There's no defined way to reset a sqlite db, just delete the db and recreate.
Sqlite: How do I reset all database tables?
I did this in the file and it works fine
const request = require('supertest');
const server = require('../server');
const knex = require('knex');
const dbConfig = require('../knexfile.js')['test'];
const db = knex(dbConfig);
describe('Authentication', () => {
beforeEach(async () => {
await db('users').truncate();
});
it('should create a new user /users/registration', function(done) {
request(server)
.post('/users/register')
.send({
username: 'user-name',
email: 'luser-name#gmail.com',
password: '12345'
})
.set('Accept', 'application/json')
.expect(201, done);
});
});
actually right now im writing API to create, get, update, and delete data using node js. my code working in a good shape.
i try it using postman to post data, it adding new data to my db.
then i want to use testing unit, named mocha - chai.
this my code :
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('server');
let expect = require("chai").expect;
let should = require("should");
let request = require("superagent");
let util = require("util");
chai.use(chaiHttp);
describe('API Clinic Test', function() {
it('should add a SINGLE clinic on /api/v1/clinic POST', function(done) {
chai.request('http://localhost:5000')
.post('/api/v1/clinic')
.send({'clinic_name': 'Clinic Dummy', 'address': 'Bandung', 'phone':'888 888', 'fax':'888 888'})
.end(function(err, res){
expect(res.status).to.equal(200);
done();
});
});
});
if success it should return code 200.
but when i run mocha, i got this error.
i dont understad. i try using postman, it can added new data.
but why i got return 500 code when i using mocha?
is there something wrong in my codes?
please help me.
thank you.
Make your function asynchronous, testing function pretends to be executed both at the same time due to that some fail.
it('should add a SINGLE clinic on /api/v1/clinic POST', async function(done) {
await chai.request('http://localhost:5000')
.post('/api/v1/clinic')
.send({'clinic_name': 'Clinic Dummy', 'address': 'Bandung', 'phone':'888 888', 'fax':'888 888'})
.end(function(err, res) {
expect(res.status).to.equal(200);
done();
});
First time with TDD. I'm using the duo Chai/Moka after reading some article online for my NodeJS API.
I already made few dumb test to learn how to use those. Now I want test my API so I created a route :
app.get('/hello', function(req, res) {
res.status(200).send('Hello World!')
})
I try a test like this :
var request = require('superagent')
var expect = require('Chai').expect
[...]
describe('When request baseURL/hello', function(){
it('should salute you !', function (done) {
request
.get(baseURL + '/hello')
.expect(200)
.end(function(err, res){
if(err) return done(err)
done()
})
})
})
I have the fail output :
TypeError: request.get(...).expect is not a function
If I comment the expect line everything is working. I try this route with Postman and I have a 200 status code like expected.
I think you're using the wrong test module: you need supertest, not superagent.
Just install the supertest module, change the require line, and try again.
so I've got a model I'm trying to test. It has custom endpoints as well as the standard REST endpoints. I built a suite to test the standard ops. First I posted, then I upserted(a put w/o an id...basically a post), then I got. Finally I deleted the entry created when I posted, and just clean up after myself I put in an after hook to delete the point I had upserted. This worked and it was good.
Then, in the same file I added another suite, this one testing my custom endpoints. Now my hook that was supposed to delete the upserted point failed. This was not good. I tried wrapping my test for delete in a new describe statement, but again it didn't work. Eventually I did away w/ the hook altogether and just sent 2 .del calls and it still didn't work. I'm at my wits end. Please let me know if you can figure out why this isn't working and how to make it work. Thank you in advance!
Here is my code:
var request = require('supertest');
var app = require('../server');
var chai = require('chai');
var chance = require('chance').Chance();
var assert= require('assert');
function json(verb, url) {
return request(app)[verb](url)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect('Content-Type', /json/);
}
describe('Testing standard REST endpoints-(CREATE, GET,PUT, DELETE)', function() {
//This suite tests the CREATE functionality
var ptOneID;
var lat1 =chance.latitude({fixed: 7, min: 41, max: 42});
var lng1 = chance.longitude({fixed:7, min: -88, max:-87});
it('should post a new point', function(done) {
var pt1 = new app.loopback.GeoPoint({lat: lat1, lng: lng1});
json('post', '/api/Points')
.send({
location: pt1,
})
.expect(200)
.end(function(err, res) {
ptOneID= res.body.id;
done();
});
});
//This test preforms a put with out an id-- an upsert
var lat5 =chance.latitude({fixed: 7, min: 41, max: 42});
var lng5 = chance.longitude({fixed:7, min: -88, max:-87});
var ptTwoID
it('should preform an UPSERT since were not specifying ID', function(done) {
var pt5 = new app.loopback.GeoPoint({lat: lat5, lng: lng5});
json( 'put','/api/Points/' )
.send({
location: pt5,
})
.end(function(err, res) {
var updatedPoint = res.body;
ptTwoID = updatedPoint.id;
done();
})
});
it('should return a list of all points', function(done) {
json('get', '/api/Points')
.expect(200)
.end(function(err, res) {
var points = res.body;
assert(Array.isArray(points));
assert.equal(points.length, 2, 'array length incorrect');
done();
});
});
//originally I didnt have the delete tests wrapped in a describe I added it to see if it changed anything
describe('DELETE has its own suite', function() {
//Delete the point
it('should DELETE the Point created by our POST test', function(done){
json('del', '/api/Points/' + ptOneID)
.end(function(err, res) {
assert.equal(res.status, 204, 'delete failed');
done();
})
});
it('should DELETE the Point we upserted',function(done){
json('del', '/api/Points'+ ptTwoID)
.end(function(err, res) {
assert.equal(res.status, 204, 'upsert delete failed');
done();
});
});
it('testing to see if posted point is still there', function(done){
json('get', '/api/Points/' + ptOneID)
.end(function(err, res) {
assert.equal(res.status, 404, 'posted point not deleted unsure emoticon');
done();
})
});
//this part was originally wrapped in an after hook, and worked perfectly until I added the describe for custom endpoints
it('testing to see if upserted point is still there', function(done){
json('get', '/api/Points/' + ptTwoID)
.end(function(err, res) {
assert.equal(res.status, 404, 'upserted pt not deleted unsure emoticon');
done();
})
});
});
});
//This suite tests the beforeSave behavior
describe('Testing Custom endpt', function() {
blah blah blh
});
One last interesting thing: When I try to do the upsert delete, the delete returns a 404, meaning not found, however the get returns a 200 status meaning it was successfully found. Please please let me know what is going on here.
I am having trouble unit testing with Express on a number of fronts, seems to be a lack of documentation and general info online about it.
So far I have found out I can test my routes with a library called supertest (https://github.com/visionmedia/superagent), but what if I have broken my routes and controllers up, how can I go about testing my controllers independently of their routes.
here is my test:
describe("Products Controller", function() {
it("should add a new product to the mongo database", function(next) {
var ProductController = require('../../controllers/products');
var Product = require('../../models/product.js');
var req = {
params: {
name: 'Coolest Product Ever',
description: 'A very nice product'
}
};
ProductController.create(req, res);
});
});
req is easy enough to mockup. res not so much, I tried grabbing express.response, hoping I could just inject it but this hasn't worked. Is there a way to simulate the res.send object? Or am I going the wrong way about this?
When you are testing your routes, you don't actually use the inbuilt functions. Say for example, ProductController.create(req, res);
What you basically need to do is, run the server on a port and send a request for each url. As you mentioned supergent, you can follow this code.
describe("Products Controller", function() {
it("should add a new product to the mongo database", function(next) {
const request = require('superagent');
request.post('http://localhost/yourURL/products')
.query({ name: 'Coolest Product Ever', description: 'A very nice product' })
.set('Accept', 'application/json')
.end(function(err, res){
if (err || !res.ok) {
alert('Oh no! error');
} else {
alert('yay got ' + JSON.stringify(res.body));
}
});
});
});
You can refer to superagent request examples here.