I am trying to get my second spec to fail but it won't. I am returning a statusCode 203 from my server, and the test receives it as 203, but for some reason the expect block still does not throw an error. What is going on here?
spec.js
var chai = require('chai');
var expect = chai.expect;
var request = require('request');
var localServerUri = 'http://127.0.0.1:3000/';
describe('server http routing', function(done){
it('should receive a status code 200 after GET request', function() {
request(localServerUri + 'pull', function (error, response, body) {
expect(response.statusCode).to.be.at(200);
done();
});
});
it('should receive a status code 201 after POST request', function() {
request.post({url:localServerUri + 'push', form: {key:'value'}}, function(err, response, body) {
//why wont this fail?
console.log(response.statusCode === 201);
expect(response.statusCode === 201).to.be.true;
done();
});
});
});
app.js
var express = require('express');
var app = express();
app.get('/pull', function (req, res) {
res.send('works');
});
app.post('/push', function(req, res) {
res.status(203);
res.send('works');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at port', host, port);
});
You need to pass done into the it blocks, not describe.
var chai = require('chai');
var expect = chai.expect;
var request = require('request');
var localServerUri = 'http://127.0.0.1:3000/';
describe('server http routing', function(){
it('should receive a status code 200 after GET request', function(done) {
request(localServerUri + 'pull', function (error, response, body) {
expect(response.statusCode).to.be.at(200);
done();
});
});
it('should receive a status code 201 after POST request', function(done) {
request.post({url:localServerUri + 'push', form: {key:'value'}}, function(err, response, body) {
expect(true).to.be.true;
done();
});
});
});
It's pretty simple. The callbacks you pass to both of your it calls should be function (done) {... instead of function () {.... Right now, Mocha thinks these tests are synchronous, so it does not wait for them to complete.
The callback you pass to describe takes a done parameter but this is useless.
Related
I try to fetch data from different HTTP sources but I wasn't able to handle the asynchronous mode even with async...
var express = require('express');
var app = express();
var https = require("https");
var timer = require("./my_modules/timer/timer.js");
var http = require('http');
var bodyParser = require('body-parser');
var async = require('async');
var request = require('request');
//These are my source from API.
//Output is a Json file
var sources = {
cnn: 'https://newsapi.org/v1/articles?source=cnn&sortBy?&apiKey=c6b3fe2e86d54cae8dcb10dc77d5c5fc',
bbc: 'https://newsapi.org/v1/articles?source=cnn&sortBy?&apiKey=c6b3fe2e86d54cae8dcb10dc77d5c5fc',
guardian: 'https://newsapi.org/v1/articles?source=cnn&sortBy?&apiKey=c6b3fe2e86d54cae8dcb10dc77d5c5fc',
othersource: "otherurls..."
};
//I want to push the JSON object in this array
var resultArray = [];
//I setup a https GET request
var getJson = function(url) {
https.get(url, (res) => {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
result = JSON.parse(body);
//push isn't working...
resultArray.push(result);
});
}).on('error', function(e) {
console.log('Got an error', e);
});
}
app.set('port', (process.env.PORT || 5000));
app.listen(
app.get('port'), () => {
console.log('We are live on port: ', app.get('port'));
getJson(sources.cnn);
});
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.setHeader('Content-Type', 'text/plain');
res.status(404).send('Page not found !');
res.status(503).send('Page not found, error 503');
});
console.log("resultArray:" + resultArray);
//resultArray = empty...
What should I do to push the result into my Array?
I couldn't find a way to set up a working callback function to push results into the Array.
Since you're already using the request package, have you tried something as simple as:
request({
url: sources.cnn,
json: true
}, function(error, response, body) {
var articles = body.articles;
// or by case, depending on what you want
// resultArray = resultArray.concat(articles);
resultArray.push({
cnn: articles
});
console.log(resultArray);
});
instead of writing your own getJson function?
Thanks Roby, your request is much clearer !
I have carefully read this really clear and helpful article : https://github.com/maxogden/art-of-node#callbacks
I think I got the logic :
//main function
function getJson(url, callback){
request({
url: url,
json: true,
callback:callback //added this
}, function(error, response, body) {
var articles = body.articles;
callback(articles);
});
}
//this callback function will be passed to the main function as the 2nd parameter
//it's possible to access "resultArray" ONLY from this function
var result = function(e){
resultArray.push(e);
console.log(resultArray);
};
//url and callback are passed as parameter
getJson(sources.cnn, result);
Thanks for the help
I'm looking to change requestHandler.value to 5 for my functional styled tests.
When running the suite, creating 1000 documents in the db is not really an option, so is it possible to change it's value programmatically before running the suite and then reset it afterwards? I can create 5 documents in db before the test to work with.
Of coarse I can stub countDocumentsInDb() in unit tests to return what I need, but I've simplified logic below for the sake of the question.
app.js:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var requestHandler = require('./lib/requestHandler.js');
var PORT = 4000;
app.route('/validate')
.get(function(req, res) {
requestHandler.process(req, res);
});
if (!module.parent) {
server.listen(PORT, function(err) {
if (err) {
return;
}
});
}
module.exports = app;
requestHandler.js:
var requestHandler = {
value: 1000,
process: function(req, res) {
numberOfDocumentsInDb = countDocumentsInDb();
if (numberOfDocumentsInDb === this.value) {
res.send(true);
} else {
res.send(false);
}
}
};
module.exports = requestHandler;
FVT style test ..
var Promise = require('promise');
var request = require('supertest');
var chai = require('chai');
chai.should();
var server = require('../../app.js');
describe('app.js', function() {
describe('/validate', function() {
it('should return true if number of documents in db matches pre-defined value', function(done) {
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
});
});
});
You can play with the require.cache, that will allow you to modify the values of requestHandler.
Is just an example I hope you get the idea.
- In the before each modify the require cache and set your test values
-In the after each set back the original values
-Please notice that the const server = require('./app.js'); is inside the test, so it will take the cache vales
e.g.
describe('test with cache', function(){
require('./requestHandler');
let originalValues;
beforeEach(function() {
originalValues = require.cache[ require.resolve('./requestHandler') ].exports;
require.cache[ require.resolve('./requestHandler') ].exports = {
value:5,
process: function(req, res) {
//other stuff
}
};
});
afterEach(function() {
require.cache[ require.resolve('./requestHandler') ].exports = originalValues;
});
it('should pass', function(){
const server = require('./app.js');
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
expect(true).to.be.true;
});
});
I would like to be able to read data received by the ascii command sent.
Below is the code that sends command to my lock controller
var express = require('express');
var router = express.Router();
var SerialPort = require('serialport');
/* GET home page */
router.get('/', function(request, response){
SerialPort.list(function (err, ports) {
ports.forEach(function(port) {
console.log(port.comName);
console.log(port.pnpId);
console.log(port.manufacturer);
});
});
var port = new SerialPort("COM5", {
baudRate: 38400
});
port.on('open', function() {
// NodeJS v4 and earlier
port.write(new Buffer('status1', 'ascii'), function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
console.log('message written');
});
});
// open errors will be emitted as an error event
port.on('error', function(err) {
console.log('Error: ', err.message);
});
});
// Important
module.exports = router;
In the doc, it mentions the use of parsers to try and read data, https://github.com/EmergingTechnologyAdvisors/node-serialport#serialportparsers--object but I am not sure how to implement it, and I would want to execute after the command status1 has been written.
Essentially logs the response of the command succesfully written to the console
There are some peculiarities.
You can open port on application start and reconnect on port close or open port on each request. It defines how work with data flow. If you send request to port then answer can contain data of previous requests (more than one). You can ignore this problem (if answer is short and request interval is enough large) or send request with assign id and search answer with this id.
SerialPort.list(function (err, ports) {
ports.forEach(function(port) {
console.log(port.comName, port.pnpId, port.manufacturer); // or console.log(port)
});
});
router.get('/', function(req, res){
function sendData(code, msg) {
res.statusCode = 500;
res.write(msg);
console.log(msg);
}
var port = new SerialPort("COM5", {
baudRate: 38400
});
port.on('open', function() {
port.write(Buffer.from('status1', 'ascii'), function(err) {
if (err)
return sendData(500, err.message);
console.log('message written');
});
});
var buffer = '';
port.on('data', function(chunk) {
buffer += chunk;
var answers = buffer.split(/\r?\n/); \\ Split data by new line character or smth-else
buffer = answers.pop(); \\ Store unfinished data
if (answer.length > 0)
sendData(200, answer[0]);
});
port.on('error', function(err) {
sendData(500, err.message);
});
});
module.exports = router;
I have a route I that in order to get all the data needs to access the API server multiple times (according to the data that was given).
Now I need to add a third access to the server and it's getting rather unreadable.
The following code is working, but I have a feeling I'm not doing it right (promises?) - couldn't figure out what exactly is recommended in this case
The code: (stripped down to emphasise the point)
router.get('/', function(req, main_response) {
http.get(FIRST_API_COMMAND, function (res) {
var moment_respose_content = '';
res.on("data", function (chunk) {
moment_respose_content += chunk;
});
res.on('end',function(){
if (res.statusCode < 200 || res.statusCode > 299) {
main_response.send('error in getting moment');
return;
}
var response = JSON.parse(moment_respose_content );
if (response.success)
{
var data = response.data;
//doing something with the data
http.get(SECOND_API_COMMAND, function (res) {
res.on("data", function (chunk) {
comment_respose_content += chunk;
});
res.on('end',function(){
var response = JSON.parse(comment_respose_content);
if (response.success)
{
var comments = response.data;
main_response.render('the page', {data: data});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting comments');
});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting moment');
});
});
You can write a middleware for each remote action, and then use those middlewares before the get handler, so the get handler can simply access their results. (Promises can help if you need to start subsequent requests before waiting for earlier ones to finish, but that situation is rare.)
For example, using express middleware to fetch each remote data independently:
var request = require('request');
var express = require('express');
var app = express();
var router = express.Router();
/* middleware to fetch moment. will only run for requests that `router` handles. */
router.use(function(req, res, next){
var api_url = 'https://google.com/';
request.get(api_url, function(err, response, body) {
if (err) {
return next(err);
}
req.moment_response = response.headers["date"];
next();
});
});
/* middleware to fetch comment after moment has been fetched */
router.use(function(req, res, next){
var api_url = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
request.get(api_url, function(err, response, body){
if (err) {
return next(err);
}
req.comment_response = parseInt(body);
next();
});
});
/* main get handler: expects data to already be loaded */
router.get('/', function(req, res){
res.json({
moment: req.moment_response,
comment: req.comment_response
});
});
/* error handler: will run if any middleware called next() with an argument */
router.use(function(error, req, res, next){
res.status(500);
res.send("Error: " + error.toString());
});
app.use('/endpoint', router);
app.listen(8000);
Often the remote data you want to fetch is based on some parameter of the main request. In this case you would want to use req.param() instead of App.use() to define the data-loading middleware.
I'm using something very similar to the following to execute a series of API tests using Mocha. This is great, but it requires making a separate API call for each test. I want to use the same API call and run multiple tests against that response. I've been reading that you can use before to do it, but none of the examples around the web actually show it working with API calls?
var chai = require('chai');
var request = require('request');
var async = require('async');
var assert = chai.assert,
expect = chai.expect,
should = chai.should();
describe('/', function () {
it('should return 200', function (done) {
request.get('http://localhost:8000', function (err, res, body) {
res.should.have.status(200);
done();
});
});
it('should say "Hello, world!"', function (done) {
request.get('http://localhost:8000', function (err, res, body) {
body.should.have.property('type', 'aType');
done();
});
});
});
You could do this with a before function like so...
var chai = require('chai');
var request = require('request');
var async = require('async');
var assert = chai.assert,
expect = chai.expect,
should = chai.should();
describe('/', function () {
var firstRequest;
before(function(done) {
request.get('http://localhost:8000', function(err, res, body) {
firstRequest = {
err:err,
res:res,
body:body
};
done();
});
});
it('should return 200', function (done) {
firstRequest.res.should.have.status(200);
done();
});
it('should say "Hello, world!"', function (done) {
firstRequest.body.should.have.property('type','aType');
done();
});
});
However, unless you have a really good reason to do this, I think you're better off just combining the tests.
var chai = require('chai');
var request = require('request');
var async = require('async');
var assert = chai.assert,
expect = chai.expect,
should = chai.should();
describe('/', function () {
it('should return 200 and say "Hello, world!"', function (done) {
request.get('http://localhost:8000', function (err, res, body) {
res.should.have.status(200);
body.should.have.property('type', 'aType');
done();
});
});
});
If the test fails Mocha will report the specific reason why it failed even though there are two assertions.