ava-http v1.0.0
AVA-http
Async HTTP requests.
AVA-http is a wrapper around the Request-Promise library, making it simpler to initiate HTTP requests.
It was made for succint API testing within AVA, but it can be used anywhere.
Installation
npm install --save-dev ava-httpUsage
The generic HTTP methods are included: get, post, put, delete.
Each of these, used within the context of an AVA test, will return a Promise that can be awaited, yielded, or then/catch'd.
Erroneous responses will always return the full Response object and should be caught with .catch().
Successful responses will return the payload (aka, response.body) by default.
If you would also like the full Response object, exchange your method for methodResponse:
http.get==>http.getResponsehttp.post==>http.postResponsehttp.put==>http.putResponsehttp.del==>http.delResponse
API
get(url, options)
url:string
options:object
Returns: Promise
On resolve success, returns payload. On error, returns full Response object.
getResponse(url, options)
url:string
options:object
Returns: Promise
Always returns full Response object.
post(url, options)
url:string
options:object
Returns: Promise
On resolve success, returns payload. On error, returns full Response object.
postResponse(url, options)
url:string
options:object
Returns: Promise
Always returns full Response object.
put(url, options)
url:string
options:object
Returns: Promise
On resolve success, returns payload. On error, returns full Response object.
putResponse(url, options)
url:string
options:object
Returns: Promise
Always returns full Response object.
del(url, options)
url:string
options:object
Returns: Promise
On resolve success, returns payload. On error, returns full Response object.
delResponse(url, options)
url:string
options:object
Returns: Promise
Always returns full Response object.
Options
form
Type:
objectDefault:
{}
An object of key:value pairs of formdata that will be urlencoded before reaching the server.
The request's headers will automatically include 'content-type': 'application/x-www-form-urlencoded'.
This simulates sending an HTML form via normal means.
body
Type:
objectDefault:
{}
The payload data to be sent to the server. Leave json as true to automatically stringify as JSON.
headers
Type:
objectDefault:
{}
The request headers to send.
params
Type:
objectDefault:
{}
An alias of qs.
qs
Type:
objectDefault:
{}
The query string to append to the URL. See this example.
json
Type:
booleanDefault:
true
Whether or not the response body should be parsed as JSON.
transform
Type:
functionDefault:
null
Transform the response into a custom value with which the promise is resolved. See here for info.
AVA
Setup
You must have AVA installed already.
import test from 'ava';
import http from 'ava-http';
test('foo should succeed', t => {
const res = await http.get('http://localhost/posts');
t.true(typeof res === 'object'); // json object by default
t.deepEqual(res, {expected: 'output'}); // deepEqual comparison
});
test('bar should error', t => {
http.post('http://localhost/posts').catch(err => {
t.is(err.statusCode, 400);
t.deepEqual(err.response.body, {error: 'message'});
});
});Examples
Thennables
test('thennable', async t => {
http.get('http://localhost').then(res => {
t.deepEqual(res, {expected: 'output'});
});
});Async Support
test('async/await', async t => {
t.deepEqual(await http.get('http://localhost'), {expected: 'output'});
});Generator Support
test('generator/yield', function * (t) {
t.deepEqual(yield http.get('http://localhost'), {expected: 'output'});
});Response Headers
By default, successful responses will only yield their payloads. If you need/want to test a status code, for example, this will suffice:
test('response headers', async t => {
const res = await http.getResponse('http://localhost');
console.log('these are the headers: ', res.headers);
t.is(res.statusCode, 200);
});Expecting Errors
In order to successfully expect and catch a Response Error, the test must be asserted witin the Promise's .catch().
For more information, please check out Request-Promise's excellent documentation on the Promise API.
test('404 error is thrown', async t => {
http.get('http://localhost').catch(err => t.is(err.statusCode, 404));
});Posting JSON
test('post json object', async t => {
const body = {some: 'data'};
t.deepEqual(await http.post('http://localhost', {body}), {expected: 'output'});
});
// or, to also assert a statusCode...
test('post json object, assert status', async t => {
const body = {some: 'data'};
const res = await http.postResponse('http://localhost', {body});
t.is(res.statusCode, 201);
t.deepEqual(res.response.body, {expected: 'output'});
});Posting as a HTML Form
All data within the form object will be urlencoded, just as any normal <form> would!
test('post like a form', async t => {
const form = {some: 'data'}; // will be urlencoded
t.deepEqual(await http.post('http://localhost', {form}), {expected: 'output'});
});Updating an Item
test('update an item', async t => {
const body = {some: 'data'};
t.deepEqual(await http.put('http://localhost/items/2', {body}), {expected: 'output'});
});Deleting an Item
test('delete an item', async t => {
const res = await http.delResponse('http://localhost/items/2');
t.is(res.statusCode, 200);
});
// expecting an error...
test('delete is unauthorized', async t => {
http.del('http://localhost/items/2').catch(err => t.is(err.statusCode, 401));
});Pass an Authorization Token (eg, JWT)
test('delete is authorized with token', async t => {
const headers = {
'Authorization': 'Bearer 1234567890'
};
t.deepEqual(await http.del('http://localhost/items/2', {headers}), {expected: 'output'});
});Passing Query String Parameters
test('get item with parameters', async t => {
const params = {
token: 'xxxxx xxxxx' // -> uri + '?token=xxxxx%20xxxxx'
};
t.deepEqual(await http.get('http://localhost', {params}), {expected: 'output'});
});Goals
Ideally, AVA-http is the asynchronous, node-equivalent of PHPUnit. This means that similar, custom assertions will be added into AVA's Test class (as opposed to exporting an http wrapper, as it currently stands). Methods will/should be as follows:
t.jsonEqualst.jsonContainst.jsonStructuret.responseOkt.responseNotOkt.responseCodet.responseTypet.headersEqualt.headersContain
An ideal test setup may look like this:
test(async t => {
t.responseOk(await get(url)); // no error
});
test(async t => {
const body = {sent: 'data'};
t.jsonContains(await post(url, {body}), {message: 'success'});
});
test(async t => {
t.jsonEquals(await get(url), {exact: 'match'});
});
test(async => {
t.responseCode(await get(url), 301);
});
test(async => {
t.headersContain(await get(url), {'Cache-Control': 'max-age=21600'});
});TODOs
- Define a complete Micro test server, with routing
- Start-up test server on
test.before() - Cleanup/Remove all
const url = await ...within tests
License
MIT © Luke Edwards et al