1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
var HOST = 'localhost';
var PORT = 80;
var API = "/api/user/create";
var tobi = require('tobi'),
vows = require('vows'),
assert = require('assert');
var newbie = function() { return tobi.createBrowser(PORT, HOST) };
// -------------------------------------------------------------
// Macros.
// -------------------------------------------------------------
var macroPostOnlyApiChecks = function(url) {
return {
'GET': {
topic: function() {
var browser = newbie();
browser.get(url, this.callback);
},
'should fail.': function(res, $) {
res.should.not.have.status(200);
}
},
'Empty POST': {
topic: function() {
var browser = newbie();
browser.post(url, this.callback);
},
'should fail.': function(res, $) {
res.should.not.have.status(200);
}
}
};
};
var macroCreateUserOk = function(suite) {
return {
'Create user': {
topic: function() {
var browser = newbie();
var data = { signupUsername: '', };
data = JSON.stringify(data);
browser.post('/api/user/create', data, this.callback);
},
'should succeed.': function(res, $) {
res.should.have.status(200);
console.log(res);
// Pass created user credentials back to
// the calling suite for later use.
if (suite) {
}
}
}
};
};
// -------------------------------------------------------------
// User API Test Suite
//
// Run me with: vows api.user.create.vows.js --spec
// -------------------------------------------------------------
var suite = vows.describe('User API Test Suite');
// Batches are executed sequentially.
// Contexts are executed in parallel.
suite.addBatch(macroPostOnlyApiChecks(API));
suite.addBatch(macroCreateUserOk());
suite.export(module);
|
Testing REST API with LearnBoost’s Tobi + Vows.js
I've been looking for a clean, framework-independent way of doing white-box API testing using Node.js. For a long while, the things that popped up when doing a quick scan of the Node Package Manager package lists weren't ticking all of the right boxes: zombie.js is going for a full browser simulation but doesn't provide a simple Browser.post() method (you have to use selectors to find the form.submit button and then fire a click() on it), Node's native http.Client is too low-level and doesn't do cookies, and various other http request wrappers weren't quite cutting it either.
I think I've found a solution for this particular version of the problem:
LearnBoost's Tobi combined with Vows.js is letting me do clean REST API testing, with a minimum of hassle, and all the built-in sugar-coated goodness of should.js fluent assertions.
For example:
Future steps then include using the macros to help set up other tests that require a valid user, etc. Overall, this is the most straightforward solution I've yet found for the problem of testing a REST API while also faking a session.
Thanks for this. One thing your post does not mention is that it doesn’t seem possible to access $ from the callback. It’s always undefined in my testing and afaik it’s an incompatibility between vows and tobi.
That is odd. I didn’t have much of a use for Sizzle selectors, though, since the tests were operating 100% on JSON object responses.
I found a solution where ‘$’ works as expected.
See: https://github.com/cloudhead/vows/issues/74
My gist at the bottom gives a tobi example.
Take Care !!! One need to set the headers (esp. ‘content-type’) in the options before using browser.post(…).
In the code (line#46) below the data is a misnomer !! it should be options.
browser.post(‘/api/user/create’, data, this.callback);
I too had problems accessing $ in the callback (vows 0.5.8). Vows likes callbacks to be in the style of callback(err, res, $) clearing other parameters if err is set. I’m now using a wrapper function to add a null err parameter:
browserGet = function(that, url) {
var browser = tobi.createBrowser(3000, ‘localhost’);
browser.get(url, function (res, $) {
that.callback(null, res, $);
});
return browser;
};
and call browserGet(this, ‘/foo’) in the vows topic function.