bent
Version:
Functional HTTP client for Node.js w/ async/await.
256 lines (228 loc) • 7.08 kB
JavaScript
/* globals atob, it */
'use strict'
const bent = require('../')
const assert = require('assert')
const tsame = require('tsame')
const { PassThrough } = require('stream')
const http = require('http')
const test = it
const same = (x, y) => assert.ok(tsame(x, y))
const baseurl = 'https://echo-server.mikeal.now.sh/src'
const u = path => baseurl + path
const enc = str => (new TextEncoder()).encode(str).buffer
const dec = str => Uint8Array.from(atob(str), c => c.charCodeAt(0)).buffer
const decode = arr => (new TextDecoder('utf-8')).decode(arr)
test('basic 200 ok', async () => {
const request = bent('string')
const str = await request(u('/echo.js?body=ok'))
same(str, 'ok')
})
test('basic 200 ok baseurl', async () => {
const request = bent('string', baseurl)
const str = await request('/echo.js?body=ok')
same(str, 'ok')
})
test('basic 200', async () => {
const request = bent()
const res = await request(u('/echo.js?body=ok'))
same(res.statusCode, 200)
})
test('basic buffer', async () => {
const request = bent('buffer')
const buff = await request(u('/echo.js?body=ok'))
if (buff instanceof ArrayBuffer) {
same(buff, enc('ok'))
} else {
same(buff, Buffer.from('ok'))
}
})
test('double buffer decode', async () => {
const request = bent()
const resp = await request(u('/echo.js?body=ok'))
const validate = buff => {
if (buff instanceof ArrayBuffer) {
same(buff, enc('ok'))
} else {
same(buff, Buffer.from('ok'))
}
}
validate(await resp.arrayBuffer())
let threw = true
try {
await resp.arrayBuffer()
threw = false
} catch (e) {
if (!e.message.includes('body stream is locked')) throw e
}
assert.ok(threw)
})
test('basic json', async () => {
const request = bent('json')
const json = await request(u('/info.js'))
same(json.method, 'GET')
})
test('json based media type', async () => {
const request = bent('json', { accept: 'application/vnd.something.com' })
const json = await request(u('/info.js'))
same(json.headers.accept, 'application/vnd.something.com')
})
test('basic PUT', async () => {
const request = bent('PUT', 'json')
let body
if (process.browser) {
body = enc(Math.random().toString())
} else {
body = Buffer.from(Math.random().toString())
}
const json = await request(u('/info.js'), body)
if (process.browser) {
same(dec(json.base64), body)
} else {
same(Buffer.from(json.base64, 'base64'), body)
}
})
test('base PUT string', async () => {
const request = bent('PUT', 'json')
const json = await request(u('/info.js'), 'teststring')
if (process.browser) {
same(atob(json.base64), 'teststring')
} else {
same(Buffer.from(json.base64, 'base64').toString(), 'teststring')
}
})
test('status 201', async () => {
const request = bent('string', 201)
const str = await request(u('/echo.js?statusCode=201&body=ok'))
same(str, 'ok')
try {
await request(u('/echo.js?body=ok'))
throw new Error('Call should have thrown.')
} catch (e) {
same(e.message, process.browser ? null : 'OK')
// basic header test
same(e.headers['content-length'], '2')
}
})
test('multiple status', async () => {
const request = bent('string', [200, 201])
const str200 = await request(u('/echo.js?body=ok'))
same(str200, 'ok')
const str201 = await request(u('/echo.js?statusCode=201&body=ok'))
same(str201, 'ok')
try {
await request(u('/echo.js?statusCode=202&body=ok'))
throw new Error('Call should have thrown.')
} catch (e) {
same(e.message, process.browser ? null : 'Accepted')
// basic header test
same(e.headers['content-length'], '2')
}
})
test('PUT stream', async () => {
const body = Buffer.from(Math.random().toString())
const request = bent('PUT', 'json')
const b = new PassThrough()
const res = request(u('/info.js'), b)
b.end(body)
const info = await res
same(info.method, 'PUT')
// Unfortunately, we can't test this against lamda cause it doesn't support
// transfer-encoding: chunked.
// t.same(Buffer.from(info.base64, 'base64'), body)
})
test('PUT JSON', async () => {
const request = bent('PUT', 'json')
const info = await request(u('/info.js'), { ok: 200 })
let res
if (process.browser) {
res = JSON.parse(atob(info.base64))
} else {
res = JSON.parse(Buffer.from(info.base64, 'base64').toString())
}
same(res, { ok: 200 })
same(info.headers['content-type'], 'application/json')
})
if (process.browser) {
test('500 Response body and message', async () => {
const request = bent()
let body
let _e
try {
await request(u('/echo.js?statusCode=500&body=ok'))
} catch (e) {
_e = e
body = e.responseBody
}
const validate = buffer => {
if (process.browser) {
same(decode(buffer), 'ok')
} else {
same(buffer.toString(), 'ok')
}
}
validate(await body)
// should be able to access again
validate(await _e.responseBody)
same(_e.message, null)
})
} else {
test('500 Response body and message', async () => {
const request = bent()
let body
let _e
try {
await request(u('/echo.js?statusCode=500&body=ok'))
} catch (e) {
_e = e
body = e.responseBody
}
const validate = buffer => {
if (process.browser) {
same(decode(buffer), 'ok')
} else {
same(buffer.toString(), 'ok')
}
}
validate(await body)
// should be able to access again
validate(await _e.responseBody)
same(_e.message, 'Internal Server Error')
})
}
test('auth', async () => {
const request = bent('https://test:pass@httpbin.org/basic-auth/test/pass', 'json')
const obj = await request()
same(obj, { authenticated: true, user: 'test' })
})
if (process.browser) {
test('override headers', async () => {
const request = bent('string', { Accept: 'application/json' })
let info = await request(u('/info.js'), null, { Accept: 'application/xml' })
info = JSON.parse(info)
same(info.headers.accept, 'application/xml')
})
} else {
test('override headers', async () => {
const request = bent('json', { 'X-Default': 'ok', 'X-Override-Me': 'not overriden' })
const info = await request(u('/info.js'), null, { 'X-Override-Me': 'overriden', 'X-New': 'ok' })
same(info.headers['x-default'], 'ok')
same(info.headers['x-override-me'], 'overriden')
same(info.headers['x-new'], 'ok')
})
test('manually-set content-type header when body is present', async () => {
const server = http.createServer((request, response) => {
response.statusCode = request.headers['content-type'] === 'application/jose+json' ? 200 : 400
response.end()
})
await new Promise((resolve, reject) => {
server.listen(9999, () => {
resolve()
})
})
const request = bent('POST')
const response = request('http://localhost:9999', { ok: true }, { 'content-type': 'application/jose+json' })
const info = await response
same(info.statusCode, 200)
server.close()
})
}