Skip to content

Added timeout option and improve error messages #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 66 additions & 32 deletions lib/api-easy.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ exports.describe = function (text) {
this.port = port || 80;
this.secure = options.secure || false;
this.auth = options.auth;
this.timeout = options.timeout || 0;

//
// **TODO _(indexzero)_:** Setup `this.options` here (i.e. options for the SUITE, not the REQUEST)
Expand Down Expand Up @@ -191,6 +192,10 @@ exports.describe = function (text) {
var args = Array.prototype.slice.call(arguments);
return this._request.apply(this, ['post'].concat(args));
},
options: function (/* [uri, data, params] */) {
var args = Array.prototype.slice.call(arguments);
return this._request.apply(this, ['options'].concat(args));
},
put: function (/* [uri, data, params] */) {
var args = Array.prototype.slice.call(arguments);
return this._request.apply(this, ['put'].concat(args));
Expand Down Expand Up @@ -221,25 +226,29 @@ exports.describe = function (text) {
// low memory consumption
//
fs.readFile(filepath[0], function (err, fileData) {
var multipart = outgoing.multipart = [];
if(data && data.length){
Object.keys(data[0]).forEach(function(key){
var value = data[0][key];
multipart.push({
'Content-Disposition': 'form-data; name="' + key + '"',
body: value
if (err) {
callback(err);
} else {
var multipart = outgoing.multipart = [];
if(data && data.length){
Object.keys(data[0]).forEach(function(key){
var value = data[0][key];
multipart.push({
'Content-Disposition': 'form-data; name="' + key + '"',
body: value
});
});
}

multipart.push({
'content-type': 'application/octet-stream',
'Content-Transfer-Encoding': 'binary',
'Content-Disposition': 'form-data; name="' + filePartName + '"; filename="' + filename + '"',
'body': fileData
});
}

multipart.push({
'content-type': 'application/octet-stream',
'Content-Transfer-Encoding': 'binary',
'Content-Disposition': 'form-data; name="' + filePartName + '"; filename="' + filename + '"',
'body': fileData
});

request(outgoing, callback);
request(outgoing, callback);
}
});
});

Expand Down Expand Up @@ -268,40 +277,50 @@ exports.describe = function (text) {
});

context = this._currentTest(this.current);

// When using a custom test assertion function, both the assertion function
// and a description are required or else we have no key in the JSON structure to use.
if (text && !test || test && !text) {
throw new Error('Both description and a custom test are required.');
}


var withDebugInfo = function withDebugInfo(fun) {
return function(err, res, body) {
try {
return fun(err, res, body);
} catch (e) {
throw new Error(e.toString() + '\n\nContext:\n' + context.debugInfo.method.toUpperCase() + ' ' + context.debugInfo.uri + '\n\n' + context.debugInfo.stacktrace);
}
};
};

// Setup the custom test assertion if we have the appropriate arguments.
if (text && test) {
context[text] = function (err, res, body) {
assert.isNull(err);
context[text] = withDebugInfo(function (err, res, body) {
assert.ifError(err);
test.apply(context, arguments);
};
});
}

// Setup the response code test assertion if we have the appropriate arguments.
if (code) {
context['should respond with ' + code] = function (err, res, body) {
assert.isNull(err);
context['should respond with ' + code] = withDebugInfo(function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, code);
};
});
}

// Setup the JSON response assertion if we have the appropriate arguments.
if (result) {
context['should respond with ' + JSON.stringify(result).substring(0, 50)] = function (err, res, body) {
context['should respond with ' + JSON.stringify(result).substring(0, 50)] = withDebugInfo(function (err, res, body) {
//
// Pass any and all errors from parsing and asserting
// the JSON returned to the underlying `vows` suite.
//
assert.isNull(err);
assert.ifError(err);
var testResult = JSON.parse(body);
assert.deepEqual(testResult, result);
};
});
}

return this;
Expand Down Expand Up @@ -424,7 +443,7 @@ exports.describe = function (text) {
port = this.port && this.port !== 80 ? ':' + this.port : '',
outgoing = clone(this.outgoing),
fullUri, context;

//
// Update the fullUri for this request with the passed uri
// and the query string parameters (if any).
Expand Down Expand Up @@ -467,14 +486,27 @@ exports.describe = function (text) {
outgoing.uri += this.auth ? this.auth + '@' : '';
outgoing.uri += this.host + port + fullUri;
outgoing.method = method;
outgoing.timeout = this.timeout;

//
// Create the description for this test. This is currently static.
// **Remark _(indexzero)_**: Do users care if these strings are configurable?
//
this.current = ['A', method.toUpperCase(), 'to', fullUri].join(' ');
context = this._currentTest();


var debugInfo = {
uri: outgoing.uri,
method: outgoing.method,
stacktrace: new Error('original stacktrace').stack
};

if (context[this.current]) {
console.log('\nWARNING: A previous test has been overwritten. Is that what you intended?\n' +
'(Hint: To avoid that error, use "next" to start a new batch)\n\n' +
'Context: ' + this.current + '\n\n' + debugInfo.stacktrace);
}

//
// Add the topic for the specified request to the context of the current
// batch used by this suite.
Expand All @@ -495,7 +527,9 @@ exports.describe = function (text) {
requestImpl(outgoing, this.callback);
else
request(outgoing, this.callback);
}
},

debugInfo: debugInfo
};

//
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "api-easy",
"description": "Fluent (i.e. chainable) syntax for generating vows tests against RESTful APIs.",
"version": "0.3.8",
"version": "0.4.0",
"author": "Nodejitsu Inc. <[email protected]>",
"maintainers": [
"indexzero <[email protected]>"
Expand All @@ -19,20 +19,20 @@
"dependencies": {
"pkginfo": "0.3.x",
"request": "2.x.x",
"vows": "0.7.x",
"vows": "0.8.x",
"qs": "0.5.x"
},
"devDependencies": {
"director": "~1.0.3",
"formidable": "1.0.2",
"mkdirp": "0.2.x"
"director": "~1.2.8",
"formidable": "1.0.17",
"mkdirp": "0.5.x"
},
"main": "./lib/api-easy",
"scripts": {
"test": "vows test/*-test.js --spec"
},
"engines": {
"node": ">= 0.4.3"
"node": ">= 0.10.0"
}
}