I'm trying to setup a node-jasmine test for the first time. Currently I'm just trying to setup a simple test to see that getting the index returns status 200.
It seemed to be working but I noticed no matter what I change the status number to it never fails, for example expecting status 666, but I don't get a failure:
const request = require("request")
const helloWorld = require("../app.js")
const base_url = "http://localhost:3002/"
describe("Return the index page", function() {
describe("GET /", function() {
it("returns status code 200", function() {
request.get(base_url, function(error, response, body) {
expect(response.statusCode).toBe(666)
done()
})
})
})
})
Which returns:
Finished in 0.009 seconds
1 test, 0 assertions, 0 failures, 0 skipped
When I expected a failure here.
You need to include the done callback as a parameter to the test function.
Eg:
it("returns status code 200", function(done) {
request.get(base_url, function(error, response, body) {
expect(response.statusCode).toBe(666)
done();
})
})
Without this, the test is completing before the asynchronous request returns.
While it looks like you found your answer, I came here with a similar problem. My problem was that the request was failing, and the assertion was never reached. Once I added an error catch like below, I found my problem!
I'm new to Jasmine, but it seems odd that an exception generated inside your test wouldn't be more visible or apparent, so if anyone has feedback on how to better handle, let me know.
const request = require("request")
const helloWorld = require("../app.js")
const base_url = "http://localhost:3002/"
describe("Return the index page", function() {
describe("GET /", function() {
it("returns status code 200", function() {
request.get(base_url, function(error, response, body) {
if (error)
console.log("Something borked: ", error);
expect(response.statusCode).toBe(666)
done()
})
})
})
})
Related
I'm having a very strange error where my http requests aren't sending at all. Once I send the request it just stops executing. I'm ingesting a CSV file through a ReadStream and sending requests inside the emitter listening blocks. If I try to send the request outside the emitters it can send fine, but I need to POST data from the file so it has to be sent within them (unless there's a way to export the data I don't know about.
Code:
const buffer = multipart.parse(event, true).fileName.content;
const file = stream.Readable.from(buffer);
let events;
file.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => {
events = parseEvents(event, results);
console.log("sending request");
request({method: 'POST', url: 'https://httpbin.org/anything', json: {hello: 'world'}}, function (err, response, body) {
console.log(err);
console.log(response);
console.log(body);
});
console.log("finished request");
})
.on('error', error => {
console.log(error);
});
Before you say, I've also tried all kinds of requests. Using got, Axios, and request I've done awaits and tried to process it that way. I actually can get the promise but if I await it nothing happens. It's also not stuck in an infinite loop or anything because when put in a for loop it tries it every time and just always returns nothing.
For more info: The console gets the "sending request" log and then "finished request" and that's it. If I go the promise route, it doesn't even log the "finished request".
Per the documentation, url is not an option for http.request(), nor is json:
https://nodejs.org/dist/latest-v16.x/docs/api/http.html#httprequestoptions-callback
This seems like an async issue. After you fire your request, your code executes the next line rather than waits for the response and thats why you see the logs for sending and finished. Not sure how you implemented the promise solution before, and without seeing the rest of your code it would be hard to debug but I assume something like this should work.
return new Promise((resolve, reject) => {
file.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => {
events = parseEvents(event, results);
console.log("sending request");
request({method: 'POST', url: 'https://httpbin.org/anything', json: {hello: 'world'}}, function (err, response, body) {
console.log(err);
console.log(response);
console.log(body);
resolve(body);
});
console.log("finished request");
})
.on('error', error => {
reject(error);
console.log(error);
})
});
Then wherever you are returning the promise to you can call .then(() => { //do stuff })
When running mocha tests using npm run test, is it possible to have the contents of the response body printed whenever a test fails with an error?
chai.request(server)
.post('/')
.set('X-Access-Token', testUser.accessToken)
.send(fields)
.end((error, response) => {
console.log(response.body); // log this!
response.should.have.status(201); // if this fails!
done();
});
});
In other words, could the afterEach function have access to error and response for each test?
afterEach(function(error, response) {
if (error) console.log('afterEach', response.body);
});
We have useful error messages coming down in the response, so we find ourselves pasting that console.log line into the failing test to debug. It'd be nice to always see the response.body on each error.
OP here - I came up with an answer and figured I'd leave it here until someone comes up with a better one.
The reason it's not ideal is that it requires a single line in each test, which updates a shared variable currentResponse with that test's response. But if your tests span many files, you can maintain a global variable in your setup script:
// you can use a global variable if tests span many files
let currentResponse = null;
afterEach(function() {
const errorBody = currentResponse && currentResponse.body;
if (this.currentTest.state === 'failed' && errorBody) {
console.log(errorBody);
}
currentResponse = null;
});
And then each of your tests would update the current response, so we can log it in the afterEach, in the event that it fails.
describe('POST /interests', () => {
it('400s if categoryName field is not present in the category', done => {
const fields = [
{ language: 'en' },
];
chai.request(server)
.post('/interests')
.set('X-Access-Token', testUser.accessToken)
.send(fields)
.end((error, response) => {
currentResponse = response; // update it here
response.should.have.status(400);
done();
});
});
And this will output the response whenever there's an error, so you can see what the server returned.
Recently I have been struggling with a problem that rose up because of NodeJS's asynchronous nature.
I have a situation where I try to issue a request to one server, and if it does not work (because of a timeout for example), I "replace" it - by issuing a request to another server to supply me the data, and continue the code execution.
Right now, what actually happens is that once the catch method is being called, I am not sure how to "Go back" to the same place it stopped at, and continue the .then (Promise) chain.
Of course I can write code after the .catch and watch it being executed, but 2 things would probably happen:
1. This code will run asynchronously "without waiting".
2. I'll have to replicate large chunks of code, over and over, while nesting them inside each other, using promises and catch blocks, which will elevate the "Promises-chaining-hell", and which is obviously, or probably, not the correct way to achieve.
A short description of what I am trying to achieve:
const options1 = {
method: 'GET',
timeout: 1500,
uri: 'https://www.example.com/'
}
const options2 = {
method: 'GET',
timeout: 1500,
uri: 'https://www.example.com/'
}
const options3 = {
method: 'GET',
timeout: 1500,
uri: 'https://www.example.com/'
}
//Code before
request(options1)
.then(function (response) {
//Server 1 is working - execute what's inside .then
request(options3)
.then(function (response) {
//Got the data from server 1 or 2, doesn't matter, now get the required data from server 3
})
.catch(function (err) {
//Timeout has been thrown, show an error and continue
console.log('Server 3 error occured, continuing.');
});
})
.catch(function (err) {
//Timeout has been thrown, show an error and continue
request(options2)
.then(function (response) {
})
.catch(function (err) {
//Server 2 doesn't work either, abord and notify the user
console.log('Server 2 error occured, continuing.');
});
console.log('Server 1 error occured, continuing.');
});
Should I use an outside function, in-order to define those "recovery routes"?
Thank you.
You just return a promise to then(){} scope, and rest is taken care by the promises. So, as you yourself said, you can attach a "then" block after the catch, and write post execution code their, but you need to return a promise to the parent, which takes care of the chaining and consecutive calling of attached callbacks.
Something like this:
//Code before
request(options1)
.then(function (response) {
console.log("Success 1")
//Server 1 is working - execute what's inside .then
return request(options3)
.then(function (response) {
//Got the data from server 1 or 2, doesn't matter, now get the required data from server 3
console.log("Success 3")
})
.catch(function (err) {
//Timeout has been thrown, show an error and continue
console.log('Server 3 error occured, continuing.');
});
})
.catch(function (err) {
console.log("Failed 1")
//Timeout has been thrown, show an error and continue
return request(options2)
.then(function (response) {
console.log("Success 2")
})
.catch(function (err) {
console.log("Failed 1")
//Server 2 doesn't work either, abord and notify the user
console.log('Server 2 error occured, continuing.');
});
})
.then( ()=>{
console.log("Post execution")
} )
Hope it helps.
You can validate by throwing an error inside then block along with a timeout, and force the catch block to execute.
You should create a common function for what happens when the 1st / 2nd request succeeds. This function can be called in both the cases without code duplication.
request(options1)
.then(function (response) {
//Server 1 is working - execute what's inside .then
return request3(response);
})
.catch(function (err) {
//Timeout has been thrown, show an error and continue
return request(options2)
.then(function (response) {
return request3(response);
});
});
function request3() {
// return a promise here
}
I'm new to BDD and for some reason my code always seem to be passing although I haven't yet written any code. Can somebody please explain why this is happening?
Project setup:
I have a project folder with package.json and a test section with the following declared: ".node_modules/.bin/jasmine-node" and a folder called spec with the following code file:
var request = require("request");
describe("Web Server Test", function() {
it("GET /", function(done) {
request.get("http://localhost/", function(error, request, body) {
expect(body).toContain("Hello, World!");
});
done();
});
});
This is the output I get:
C:\Users\\OneDrive\Documents\Websites\Projects\Node\project>npm
test spec/app_spec.js
Project#0.0.0 test
C:\Users\\OneDrive\Documents\Websites\Projects\Node\project
jasmine-node "spec/app_spec.js"
.
Finished in 0.031 seconds 1 test, 0 assertions, 0 failures, 0 skipped
the done callback must be called inside request callback...
it("GET /", function(done) {
request.get("http://localhost/", function(error, request, body) {
expect(body).toContain("Hello, World!");
// THIS IS ASYNC
done();
});
});
I have the following route (express) for which I'm writing an integration test.
Here's the code:
var q = require("q"),
request = require("request");
/*
Example of service wrapper that makes HTTP request.
*/
function getProducts() {
var deferred = q.defer();
request.get({uri : "http://localhost/some-service" }, function (e, r, body) {
deferred.resolve(JSON.parse(body));
});
return deferred.promise;
}
/*
The route
*/
exports.getProducts = function (request, response) {
getProducts()
.then(function (data) {
response.write(JSON.stringify(data));
response.end();
});
};
I want to test that all the components work together but with a fake HTTP response, so I am creating a stub for the request/http interactions.
I am using Chai, Sinon and Sinon-Chai and Mocha as the test runner.
Here's the test code:
var chai = require("chai"),
should = chai.should(),
sinon = require("sinon"),
sinonChai = require("sinon-chai"),
route = require("../routes"),
request = require("request");
chai.use(sinonChai);
describe("product service", function () {
before(function(done){
sinon
.stub(request, "get")
// change the text of product name to cause test failure.
.yields(null, null, JSON.stringify({ products: [{ name : "product name" }] }));
done();
});
after(function(done){
request.get.restore();
done();
});
it("should call product route and return expected resonse", function (done) {
var writeSpy = {},
response = {
write : function () {
writeSpy.should.have.been.calledWith("{\"products\":[{\"name\":\"product name\"}]}");
done();
}
};
writeSpy = sinon.spy(response, "write");
route.getProducts(null, response);
});
});
If the argument written to the response (response.write) matches the test passes ok. The issue is that when the test fails the failure message is:
"Error: timeout of 2000ms exceeded"
I've referenced this answer, however it doesn't resolve the problem.
How can I get this code to display the correct test name and the reason for failure?
NB A secondary question may be, could the way the response object is being asserted be improved upon?
The problem looks like an exception is getting swallowed somewhere. The first thing that comes to my mind is adding done at the end of your promise chain:
exports.getProducts = function (request, response) {
getProducts()
.then(function (data) {
response.write(JSON.stringify(data));
response.end();
})
.done(); /// <<< Add this!
};
It is typically the case when working with promises that you want to end your chain by calling a method like this. Some implementations call it done, some call it end.
How can I get this code to display the correct test name and the reason for failure?
If Mocha never sees the exception, there is nothing it can do to give you a nice error message. One way to diagnose a possible swallowed exception is to add a try... catch block around the offending code and dump something to the console.