We've written a RESTful web API which responds to GET and PUT requests using node.js.
We're having some difficulties testing the API.
First, we used Zombie.js, but it's not well documented so we couldn't get it to make PUT requests:
var zombie = require("zombie");
describe("description", function() {
it("description", function() {
zombie.visit("http://localhost:3000/", function (err, browser, status) {
expect(browser.text).toEqual("A")
});
});
});
After that we tried using a REST-client called restler, which would OK, since we don't need any advanced browser simulation. This fails due to the fact that the request seems to be asynchronous - i.e. the test is useless since it finishes before the 'on success' callback is called:
var rest = require('restler');
describe("description", function() {
it("description", function() {
rest.get("http://www.google.com").on('complete', function(data, response) {
// Should fail
expect(data).toMatch(/apa/i);
});
});
});
We'd grateful for any tips about alternative testing frameworks or synchronous request clients.
For node, jasmine-node from Misko Hevery has asynchronous support and wraps jasmine.
https://github.com/mhevery/jasmine-node
You add a 'done' parameter to the test signature, and call that when the asynchronous call completes. You can also customize the timeout (the default is 500ms).
e.g. from the Github README
it("should respond with hello world", function(done) {
request("http://localhost:3000/hello", function(error, response, body){
done();
}, 250); // timeout after 250 ms
});
jasmine regular also has support for asynchronous testing with runs and waitsFor, or can use 'done' with Jasmine.Async.
I was curious about this so I did a little more research. Other than zombie, you have a couple of options...
You could use vows with the http library like this guy.
However, I think a better approach might be to use APIeasy, which is apparently built on vows. There is an awesome article over at nodejitsu that explains how to use it.
Another interesting idea is to use expresso if you are using express.
Related
Environment: Node.js, Express
Question: When the end of a route is hit does all asynchronous code that has not yet completed stop? I have been experimenting for several hours and this seems to be true but is there a definitive answer?
Example: In the simplified example below when the / route is hit getInfoAndSaveIt is called. This function has a fetch call that will be slow followed by a database save that will also be slow. In the route the program will certainly reach the line res.render('homepage'); before the function has completed. In this case does homepage render and all async code in the function that has not yet completed stop? Or alternately does the async code continue in the background even though the end of the route has been hit?
app.get('/', function(req, res) {
getInfoAndSaveIt();
res.render('homepage');
});
function getInfoAndSaveIt() {
let randomData = fetch('https://www.example.com/data.txt');
User.updateOne({ data: randomData }, { id: 'abc123' });
}
With Node.js, Express when the end of a route is hit does all asynchronous code that has not yet completed stop?
No. Asynchronous code has a mind of its own and has no direct connection to a particular route. For example, imagine you were using some asynchronous code to do some logging. You send the response and then you call some asynchronous code to log some data. That logging will continue on just fine. It has no direct connection to the route. It's just Javascript running in the interpreter.
As for your example:
In this case does homepage render and all async code in the function that has not yet completed stop?
Yes, the homepage will render. Your async code will finish on its own.
Or alternately does the async code continue in the background even though the end of the route has been hit?
Yes, the async code continues on its own.
Try this simple example:
app.get('/', function(req, res) {
setTimeout(() => {
console.log("timer fired");
}, 2000);
res.render('homepage');
console.log("done rendering page");
});
When you hit this route, you will see this in the server logs:
done rendering page
timer fired
As evidence that an asynchronous operation continues after the route is done.
Keep in mind that processing a route in node.js is just another asynchronous operation. It's not some magic process thing or thread thing. It's just an asynchronous operation triggered by the incoming http request. So, there's no magic properties that would go find all asynchronous operations started by this and kill them somehow. That's not how node.js works. It's the opposite. Once you start them, they have a mind of their own and will complete regardless of what else is doing on in the process unless the process crashes or you specifically call process.exit().
code snippet:
describe('GetList', () => {
it('should respond with 200 Success', function* () {
let res = yield api
.get(apiPath)
.set({ })
.expect(200)
.endAsync();
res.body.forEach((item) => {
item.should.have.property('appName');
item.should.have.property('appDomain');
});
I need to write tests in the framework in which the above code is written.
if you can hint what framework it is, maybe I can read api docs and write one myself.
what I have to do is write a test that compares two arrays returned from api calls.
from npm settings it seems it use mocha and istanbul as testing framework.
That looks like Jasmine Behavior-Driven JavaScript.
Perhaps it's Mochajs as it has should.have. Jasmine, at least on the 2.4 documentation doesn't mention the should.have API.
Could you see what's included when this test is executed? Or the package.json file. Likely at the devDependencies.
I'm writing a node.js web service which needs to communicate with another server. So its basically server to server communication. I don't have any previous experience of writing web services so I have very limited knowledge. For unit tests I'm using Mocha.
Now, I intend to test the behavior of my service for a particular scenario when this other server doesn't respond to my GET request and the request is actually timed out. For tests I've created a fake client and server around my web service. My web service now takes request from this fake client and then gets information from another fake server that I created which then returns the response in the expected format. To simulate timeout I don't do response.end() from my route handler. The problem is that Mocha judges it to have failed this test case.
Is there a way I could catch this intentional timeout in Mocha and the test is a success?
As mido22 suggested you should use handle the timeout generated by whatever library you use to connect. For instance, with request:
var request = require("request");
it("test", function (done) {
request("http://www.google.com:81", {
timeout: 1000
}, function (error, response, body) {
if (error && error.code === 'ETIMEDOUT') {
done(); // Got a timetout: that's what we wanted.
return;
}
// Got another error or no error at all: that's bad!
done(error || new Error("did not get a timeout"));
});
});
I have a suite of client-side Mocha tests that currently run with the browser test runner. But I also have a suite of server-side Mocha tests that run with the Node.js command-line test runner.
I know I can run the client-side tests from the command-line in a headless browser like PhantomJS (e.g. like this), but they'd still run separately from the server-side tests.
Is there any way to run the client-side tests as part of the command-line run?
E.g. always run both sets of tests, and have one combined output like "all 100 tests passed" or "2 tests failed" — across both client-side and server-side suites.
I imagine if this were possible, there'd need to be some sort of "proxy" layer to dynamically describe to the command-line runner each browser test, and notify it of each result (maybe even any console.log output too) as the tests ran in the browser.
Does there exist anything that achieves this? I've had a hard time finding anything. Thanks!
I use Zombie for this. There's surely a way to do it with Phantom too. Just write your client-side tests under the same directory as your server-side tests and they'll get picked up by Mocha and executed along with the rest.
I'm not sure whether you need some sample test code but here's some just in case:
var app = require('../server').app; // Spin up your server for testing
var Browser = require('zombie');
var should = require('should');
describe('Some test suite', function () {
it('should do what you expect', function (done) {
var browser = new Browser();
browser.visit('http://localhost:3000', function (err) {
// Let's say this is a log in page
should.not.exist(err);
browser
.fill('#username', 'TestUser')
.fill('#password', 'TestPassword')
.pressButton('#login', function (err) {
should.not.exist(err);
// etc...
return done();
});
});
});
});
Trying to use Firebase as a nodejs module. And i have a problem:
Firebase docs say to code for nodejs the same as for javascript Firebase library.
var newChildRef = myRootRef.push{{name: "Child1"}, function(error){
if(!error){
myModel.addChildto(newChildRef); // Here is calling global var inside a callback!
}
});
In nodejs we need to use async calls to databases. So the standard node way is:
myRootRef.push{{name: "Child1"}, function(newChildRef,error){
if(!error){
myModel.addChildto(newChildRef);
}
});
Please explain how should I code in node js using Firebase, not to spoil an async style.
This was discussed in: https://groups.google.com/forum/#!topic/firebase-talk/eEsFpjE2mmI
The short answer is that it's better to use an inline function for each operation you do. We'll look into improving the API so it's easier to use the same callback for multiple set and push calls.