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-http
Usage
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 await
ed, yield
ed, 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.getResponse
http.post
==> http.postResponse
http.put
==> http.putResponse
http.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: object
Default: {}
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: object
Default: {}
The payload data to be sent to the server. Leave json
as true
to automatically stringify as JSON.
Type: object
Default: {}
The request headers to send.
params
Type: object
Default: {}
An alias of qs
.
qs
Type: object
Default: {}
The query string to append to the URL. See this example.
json
Type: boolean
Default: true
Whether or not the response body should be parsed as JSON.
transform
Type: function
Default: 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');
t.deepEqual(res, {expected: 'output'});
});
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'});
});
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'});
});
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'};
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);
});
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'
};
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.jsonEquals
t.jsonContains
t.jsonStructure
t.responseOk
t.responseNotOk
t.responseCode
t.responseType
t.headersEqual
t.headersContain
An ideal test setup may look like this:
test(async t => {
t.responseOk(await get(url));
});
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
License
MIT © Luke Edwards et al