Spaces:
Runtime error
Runtime error
| const { test } = require('node:test') | |
| const { Readable, finished, pipeline } = require('node:stream') | |
| const qs = require('node:querystring') | |
| const fs = require('node:fs') | |
| const zlib = require('node:zlib') | |
| const http = require('node:http') | |
| const eos = require('end-of-stream') | |
| const express = require('express') | |
| const multer = require('multer') | |
| const inject = require('../index') | |
| const parseURL = require('../lib/parse-url') | |
| const NpmFormData = require('form-data') | |
| const formAutoContent = require('form-auto-content') | |
| const httpMethods = [ | |
| 'delete', | |
| 'get', | |
| 'head', | |
| 'options', | |
| 'patch', | |
| 'post', | |
| 'put', | |
| 'trace' | |
| ] | |
| test('returns non-chunked payload', (t, done) => { | |
| t.plan(7) | |
| const output = 'example.com:8080|/hello' | |
| const dispatch = function (req, res) { | |
| res.statusMessage = 'Super' | |
| res.setHeader('x-extra', 'hello') | |
| res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': output.length }) | |
| res.end(req.headers.host + '|' + req.url) | |
| } | |
| inject(dispatch, 'http://example.com:8080/hello', (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.statusCode, 200) | |
| t.assert.strictEqual(res.statusMessage, 'Super') | |
| t.assert.ok(res.headers.date) | |
| t.assert.deepStrictEqual(res.headers, { | |
| date: res.headers.date, | |
| connection: 'keep-alive', | |
| 'x-extra': 'hello', | |
| 'content-type': 'text/plain', | |
| 'content-length': output.length.toString() | |
| }) | |
| t.assert.strictEqual(res.payload, output) | |
| t.assert.strictEqual(res.rawPayload.toString(), 'example.com:8080|/hello') | |
| done() | |
| }) | |
| }) | |
| test('returns single buffer payload', (t, done) => { | |
| t.plan(6) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host + '|' + req.url) | |
| } | |
| inject(dispatch, { url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.ok(res.headers.date) | |
| t.assert.ok(res.headers.connection) | |
| t.assert.strictEqual(res.headers['transfer-encoding'], 'chunked') | |
| t.assert.strictEqual(res.payload, 'example.com:8080|/hello') | |
| t.assert.strictEqual(res.rawPayload.toString(), 'example.com:8080|/hello') | |
| done() | |
| }) | |
| }) | |
| test('passes headers', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.super) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', headers: { Super: 'duper' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'duper') | |
| done() | |
| }) | |
| }) | |
| test('request has rawHeaders', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| t.assert.ok(Array.isArray(req.rawHeaders)) | |
| t.assert.deepStrictEqual(req.rawHeaders, ['super', 'duper', 'user-agent', 'lightMyRequest', 'host', 'example.com:8080']) | |
| res.writeHead(200) | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', headers: { Super: 'duper' } }, (err) => { | |
| t.assert.ifError(err) | |
| done() | |
| }) | |
| }) | |
| test('request inherits from custom class', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| t.assert.ok(req instanceof http.IncomingMessage) | |
| res.writeHead(200) | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', Request: http.IncomingMessage }, (err) => { | |
| t.assert.ifError(err) | |
| done() | |
| }) | |
| }) | |
| test('request with custom class preserves stream data', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| t.assert.ok(req._readableState) | |
| res.writeHead(200) | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', Request: http.IncomingMessage }, (err) => { | |
| t.assert.ifError(err) | |
| done() | |
| }) | |
| }) | |
| test('assert Request option has a valid prototype', (t) => { | |
| t.plan(2) | |
| const dispatch = function (_req, res) { | |
| t.assert.ifError('should not get here') | |
| res.writeHead(500) | |
| res.end() | |
| } | |
| const MyInvalidRequest = {} | |
| t.assert.throws(() => { | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', Request: MyInvalidRequest }, () => {}) | |
| }, Error) | |
| t.assert.throws(() => { | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', Request: 'InvalidRequest' }, () => {}) | |
| }, Error) | |
| }) | |
| test('passes remote address', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.socket.remoteAddress) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', remoteAddress: '1.2.3.4' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '1.2.3.4') | |
| done() | |
| }) | |
| }) | |
| test('passes a socket which emits events like a normal one does', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| req.socket.on('timeout', () => {}) | |
| res.end('added') | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'added') | |
| done() | |
| }) | |
| }) | |
| test('includes deprecated connection on request', (t, done) => { | |
| t.plan(3) | |
| const warnings = process.listeners('warning') | |
| process.removeAllListeners('warning') | |
| function onWarning (err) { | |
| t.assert.strictEqual(err.code, 'FST_LIGHTMYREQUEST_DEP01') | |
| return false | |
| } | |
| process.on('warning', onWarning) | |
| t.after(() => { | |
| process.removeListener('warning', onWarning) | |
| for (const fn of warnings) { | |
| process.on('warning', fn) | |
| } | |
| }) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.connection.remoteAddress) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', remoteAddress: '1.2.3.4' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '1.2.3.4') | |
| done() | |
| }) | |
| }) | |
| const parseQuery = url => { | |
| const parsedURL = parseURL(url) | |
| return qs.parse(parsedURL.search.slice(1)) | |
| } | |
| test('passes query', (t, done) => { | |
| t.plan(2) | |
| const query = { | |
| message: 'OK', | |
| xs: ['foo', 'bar'] | |
| } | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.url) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', query }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.deepEqual(parseQuery(res.payload), query) | |
| done() | |
| }) | |
| }) | |
| test('query will be merged into that in url', (t, done) => { | |
| t.plan(2) | |
| const query = { | |
| xs: ['foo', 'bar'] | |
| } | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.url) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello?message=OK', query }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.deepEqual(parseQuery(res.payload), Object.assign({ message: 'OK' }, query)) | |
| done() | |
| }) | |
| }) | |
| test('passes query as a string', (t, done) => { | |
| t.plan(2) | |
| const query = 'message=OK&xs=foo&xs=bar' | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.url) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', query }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.deepEqual(parseQuery(res.payload), { | |
| message: 'OK', | |
| xs: ['foo', 'bar'] | |
| }) | |
| done() | |
| }) | |
| }) | |
| test('query as a string will be merged into that in url', (t, done) => { | |
| t.plan(2) | |
| const query = 'xs=foo&xs=bar' | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.url) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello?message=OK', query }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.deepEqual(parseQuery(res.payload), Object.assign({ message: 'OK' }, { | |
| xs: ['foo', 'bar'] | |
| })) | |
| done() | |
| }) | |
| }) | |
| test('passes localhost as default remote address', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.socket.remoteAddress) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '127.0.0.1') | |
| done() | |
| }) | |
| }) | |
| test('passes host option as host header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/hello', headers: { host: 'test.example.com' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'test.example.com') | |
| done() | |
| }) | |
| }) | |
| test('passes localhost as default host header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'localhost:80') | |
| done() | |
| }) | |
| }) | |
| test('passes authority as host header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/hello', authority: 'something' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'something') | |
| done() | |
| }) | |
| }) | |
| test('passes uri host as host header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:8080') | |
| done() | |
| }) | |
| }) | |
| test('includes default http port in host header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host) | |
| } | |
| inject(dispatch, 'http://example.com', (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:80') | |
| done() | |
| }) | |
| }) | |
| test('includes default https port in host header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host) | |
| } | |
| inject(dispatch, 'https://example.com', (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:443') | |
| done() | |
| }) | |
| }) | |
| test('optionally accepts an object as url', (t, done) => { | |
| t.plan(5) | |
| const output = 'example.com:8080|/hello?test=1234' | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': output.length }) | |
| res.end(req.headers.host + '|' + req.url) | |
| } | |
| const url = { | |
| protocol: 'http', | |
| hostname: 'example.com', | |
| port: '8080', | |
| pathname: 'hello', | |
| query: { | |
| test: '1234' | |
| } | |
| } | |
| inject(dispatch, { url }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.ok(res.headers.date) | |
| t.assert.ok(res.headers.connection) | |
| t.assert.ifError(res.headers['transfer-encoding']) | |
| t.assert.strictEqual(res.payload, output) | |
| done() | |
| }) | |
| }) | |
| test('leaves user-agent unmodified', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers['user-agent']) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', headers: { 'user-agent': 'duper' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'duper') | |
| done() | |
| }) | |
| }) | |
| test('returns chunked payload', (t, done) => { | |
| t.plan(5) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, 'OK') | |
| res.write('a') | |
| res.write('b') | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.ok(res.headers.date) | |
| t.assert.ok(res.headers.connection) | |
| t.assert.strictEqual(res.headers['transfer-encoding'], 'chunked') | |
| t.assert.strictEqual(res.payload, 'ab') | |
| done() | |
| }) | |
| }) | |
| test('sets trailers in response object', (t, done) => { | |
| t.plan(4) | |
| const dispatch = function (_req, res) { | |
| res.setHeader('Trailer', 'Test') | |
| res.addTrailers({ Test: 123 }) | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers.trailer, 'Test') | |
| t.assert.strictEqual(res.headers.test, undefined) | |
| t.assert.strictEqual(res.trailers.test, '123') | |
| done() | |
| }) | |
| }) | |
| test('parses zipped payload', (t, done) => { | |
| t.plan(4) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, 'OK') | |
| const stream = fs.createReadStream('./package.json') | |
| stream.pipe(zlib.createGzip()).pipe(res) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| fs.readFile('./package.json', { encoding: 'utf-8' }, (err, file) => { | |
| t.assert.ifError(err) | |
| zlib.unzip(res.rawPayload, (err, unzipped) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(unzipped.toString('utf-8'), file) | |
| done() | |
| }) | |
| }) | |
| }) | |
| }) | |
| test('returns multi buffer payload', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200) | |
| res.write('a') | |
| res.write(Buffer.from('b')) | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'ab') | |
| done() | |
| }) | |
| }) | |
| test('returns null payload', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '') | |
| done() | |
| }) | |
| }) | |
| test('allows ending twice', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end() | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '') | |
| done() | |
| }) | |
| }) | |
| test('identifies injection object', (t, done) => { | |
| t.plan(6) | |
| const dispatchRequest = function (req, res) { | |
| t.assert.strictEqual(inject.isInjection(req), true) | |
| t.assert.strictEqual(inject.isInjection(res), true) | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end() | |
| } | |
| const dispatchCustomRequest = function (req, res) { | |
| t.assert.strictEqual(inject.isInjection(req), true) | |
| t.assert.strictEqual(inject.isInjection(res), true) | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end() | |
| } | |
| const options = { method: 'GET', url: '/' } | |
| const cb = (err) => { t.assert.ifError(err) } | |
| const cbDone = (err) => { | |
| t.assert.ifError(err) | |
| done() | |
| } | |
| inject(dispatchRequest, options, cb) | |
| inject(dispatchCustomRequest, { ...options, Request: http.IncomingMessage }, cbDone) | |
| }) | |
| test('pipes response', (t, done) => { | |
| t.plan(3) | |
| let finished = false | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200) | |
| const stream = getTestStream() | |
| res.on('finish', () => { | |
| finished = true | |
| }) | |
| stream.pipe(res) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(finished, true) | |
| t.assert.strictEqual(res.payload, 'hi') | |
| done() | |
| }) | |
| }) | |
| test('pipes response with old stream', (t, done) => { | |
| t.plan(3) | |
| let finished = false | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200) | |
| const stream = getTestStream() | |
| stream.pause() | |
| const stream2 = new Readable().wrap(stream) | |
| stream.resume() | |
| res.on('finish', () => { | |
| finished = true | |
| }) | |
| stream2.pipe(res) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(finished, true) | |
| t.assert.strictEqual(res.payload, 'hi') | |
| done() | |
| }) | |
| }) | |
| test('echos object payload', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'content-type': req.headers['content-type'] }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', payload: { a: 1 } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-type'], 'application/json') | |
| t.assert.strictEqual(res.payload, '{"a":1}') | |
| done() | |
| }) | |
| }) | |
| test('supports body option in Request and property in Response', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'content-type': req.headers['content-type'] }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', body: { a: 1 } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-type'], 'application/json') | |
| t.assert.strictEqual(res.body, '{"a":1}') | |
| done() | |
| }) | |
| }) | |
| test('echos buffer payload', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', payload: Buffer.from('test!') }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'test!') | |
| done() | |
| }) | |
| }) | |
| test('echos object payload with non-english utf-8 string', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'content-type': req.headers['content-type'] }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', payload: { a: '½½א' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-type'], 'application/json') | |
| t.assert.strictEqual(res.payload, '{"a":"½½א"}') | |
| done() | |
| }) | |
| }) | |
| test('echos object payload without payload', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '') | |
| done() | |
| }) | |
| }) | |
| test('retains content-type header', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'content-type': req.headers['content-type'] }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', payload: { a: 1 }, headers: { 'content-type': 'something' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-type'], 'something') | |
| t.assert.strictEqual(res.payload, '{"a":1}') | |
| done() | |
| }) | |
| }) | |
| test('adds a content-length header if none set when payload specified', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers['content-length']) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', payload: { a: 1 } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '{"a":1}'.length.toString()) | |
| done() | |
| }) | |
| }) | |
| test('retains a content-length header when payload specified', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers['content-length']) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/test', payload: '', headers: { 'content-length': '10' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '10') | |
| done() | |
| }) | |
| }) | |
| test('can handle a stream payload', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| readStream(req, (buff) => { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(buff) | |
| }) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/', payload: getTestStream() }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'hi') | |
| done() | |
| }) | |
| }) | |
| test('can handle a stream payload that errors', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req) { | |
| req.resume() | |
| } | |
| const payload = new Readable({ | |
| read () { | |
| this.destroy(new Error('kaboom')) | |
| } | |
| }) | |
| inject(dispatch, { method: 'POST', url: '/', payload }, (err) => { | |
| t.assert.ok(err) | |
| t.assert.equal(err.message, 'kaboom') | |
| done() | |
| }) | |
| }) | |
| test('can handle a stream payload of utf-8 strings', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| readStream(req, (buff) => { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(buff) | |
| }) | |
| } | |
| inject(dispatch, { method: 'POST', url: '/', payload: getTestStream('utf8') }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'hi') | |
| done() | |
| }) | |
| }) | |
| test('can override stream payload content-length header', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers['content-length']) | |
| } | |
| const headers = { 'content-length': '100' } | |
| inject(dispatch, { method: 'POST', url: '/', payload: getTestStream(), headers }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '100') | |
| done() | |
| }) | |
| }) | |
| test('writeHead returns single buffer payload', (t, done) => { | |
| t.plan(4) | |
| const reply = 'Hello World' | |
| const statusCode = 200 | |
| const statusMessage = 'OK' | |
| const dispatch = function (_req, res) { | |
| res.writeHead(statusCode, statusMessage, { 'Content-Type': 'text/plain', 'Content-Length': reply.length }) | |
| res.end(reply) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.statusCode, statusCode) | |
| t.assert.strictEqual(res.statusMessage, statusMessage) | |
| t.assert.strictEqual(res.payload, reply) | |
| done() | |
| }) | |
| }) | |
| test('_read() plays payload', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| let buffer = '' | |
| req.on('readable', () => { | |
| buffer = buffer + (req.read() || '') | |
| }) | |
| req.on('close', () => { | |
| }) | |
| req.on('end', () => { | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end(buffer) | |
| req.destroy() | |
| }) | |
| } | |
| const body = 'something special just for you' | |
| inject(dispatch, { method: 'GET', url: '/', payload: body }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, body) | |
| done() | |
| }) | |
| }) | |
| test('simulates split', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| let buffer = '' | |
| req.on('readable', () => { | |
| buffer = buffer + (req.read() || '') | |
| }) | |
| req.on('close', () => { | |
| }) | |
| req.on('end', () => { | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end(buffer) | |
| req.destroy() | |
| }) | |
| } | |
| const body = 'something special just for you' | |
| inject(dispatch, { method: 'GET', url: '/', payload: body, simulate: { split: true } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, body) | |
| done() | |
| }) | |
| }) | |
| test('simulates error', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| req.on('readable', () => { | |
| }) | |
| req.on('error', () => { | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end('error') | |
| }) | |
| } | |
| const body = 'something special just for you' | |
| inject(dispatch, { method: 'GET', url: '/', payload: body, simulate: { error: true } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'error') | |
| done() | |
| }) | |
| }) | |
| test('simulates no end without payload', (t, done) => { | |
| t.plan(2) | |
| let end = false | |
| const dispatch = function (req) { | |
| req.resume() | |
| req.on('end', () => { | |
| end = true | |
| }) | |
| } | |
| let replied = false | |
| inject(dispatch, { method: 'GET', url: '/', simulate: { end: false } }, () => { | |
| replied = true | |
| }) | |
| setTimeout(() => { | |
| t.assert.strictEqual(end, false) | |
| t.assert.strictEqual(replied, false) | |
| done() | |
| }, 10) | |
| }) | |
| test('simulates no end with payload', (t, done) => { | |
| t.plan(2) | |
| let end = false | |
| const dispatch = function (req) { | |
| req.resume() | |
| req.on('end', () => { | |
| end = true | |
| }) | |
| } | |
| let replied = false | |
| inject(dispatch, { method: 'GET', url: '/', payload: '1234567', simulate: { end: false } }, () => { | |
| replied = true | |
| }) | |
| setTimeout(() => { | |
| t.assert.strictEqual(end, false) | |
| t.assert.strictEqual(replied, false) | |
| done() | |
| }, 10) | |
| }) | |
| test('simulates close', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| let buffer = '' | |
| req.on('readable', () => { | |
| buffer = buffer + (req.read() || '') | |
| }) | |
| req.on('close', () => { | |
| res.writeHead(200, { 'Content-Length': 0 }) | |
| res.end('close') | |
| }) | |
| req.on('end', () => { | |
| }) | |
| } | |
| const body = 'something special just for you' | |
| inject(dispatch, { method: 'GET', url: '/', payload: body, simulate: { close: true } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'close') | |
| done() | |
| }) | |
| }) | |
| test('errors for invalid input options', (t) => { | |
| t.plan(1) | |
| t.assert.throws( | |
| () => inject({}, {}, () => {}), | |
| { name: 'AssertionError', message: 'dispatchFunc should be a function' } | |
| ) | |
| }) | |
| test('errors for missing url', (t) => { | |
| t.plan(1) | |
| t.assert.throws( | |
| () => inject(() => {}, {}, () => {}), | |
| { message: /must have required property 'url'/ } | |
| ) | |
| }) | |
| test('errors for an incorrect simulation object', (t) => { | |
| t.plan(1) | |
| t.assert.throws( | |
| () => inject(() => {}, { url: '/', simulate: 'sample string' }, () => {}), | |
| { message: /^must be object$/ } | |
| ) | |
| }) | |
| test('ignores incorrect simulation object', (t) => { | |
| t.plan(1) | |
| t.assert.doesNotThrow(() => inject(() => { }, { url: '/', simulate: 'sample string', validate: false }, () => { })) | |
| }) | |
| test('errors for an incorrect simulation object values', (t) => { | |
| t.plan(1) | |
| t.assert.throws( | |
| () => inject(() => {}, { url: '/', simulate: { end: 'wrong input' } }, () => {}), | |
| { message: /^must be boolean$/ } | |
| ) | |
| }) | |
| test('promises support', (t, done) => { | |
| t.plan(1) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('hello') | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello' }) | |
| .then(res => { | |
| t.assert.strictEqual(res.payload, 'hello') | |
| done() | |
| }) | |
| .catch(t.assert.fail) | |
| }) | |
| test('this should be the server instance', (t, done) => { | |
| t.plan(2) | |
| const server = http.createServer() | |
| const dispatch = function (_req, res) { | |
| t.assert.strictEqual(this, server) | |
| res.end('hello') | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', server }) | |
| .then(res => t.assert.strictEqual(res.statusCode, 200)) | |
| .catch(t.assert.fail) | |
| .finally(done) | |
| }) | |
| test('should handle response errors', (t, done) => { | |
| t.plan(1) | |
| const dispatch = function (_req, res) { | |
| res.connection.destroy(new Error('kaboom')) | |
| } | |
| inject(dispatch, 'http://example.com:8080/hello', (err) => { | |
| t.assert.ok(err) | |
| done() | |
| }) | |
| }) | |
| test('should handle response errors (promises)', async (t) => { | |
| t.plan(1) | |
| const dispatch = function (_req, res) { | |
| res.connection.destroy(new Error('kaboom')) | |
| } | |
| await t.assert.rejects( | |
| () => inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello' }), | |
| { name: 'Error', message: 'kaboom' } | |
| ) | |
| }) | |
| test('should handle response timeout handler', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (_req, res) { | |
| const handle = setTimeout(() => { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('incorrect') | |
| }, 200) | |
| res.setTimeout(100, () => { | |
| clearTimeout(handle) | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('correct') | |
| }) | |
| res.on('timeout', () => { | |
| t.assert.ok(true, 'Response timeout event not emitted') | |
| }) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/test' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'correct') | |
| done() | |
| }) | |
| }) | |
| test('should throw on unknown HTTP method', (t) => { | |
| t.plan(1) | |
| const dispatch = function () { } | |
| t.assert.throws(() => inject(dispatch, { method: 'UNKNOWN_METHOD', url: 'http://example.com:8080/hello' }, (err, _res) => { | |
| t.assert.ok(err) | |
| }), Error) | |
| }) | |
| test('should throw on unknown HTTP method (promises)', (t) => { | |
| t.plan(1) | |
| const dispatch = function () { } | |
| t.assert.throws(() => inject(dispatch, { method: 'UNKNOWN_METHOD', url: 'http://example.com:8080/hello' }) | |
| .then(() => {}), Error) | |
| }) | |
| test('HTTP method is case insensitive', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (_req, res) { | |
| res.end('Hi!') | |
| } | |
| inject(dispatch, { method: 'get', url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.statusCode, 200) | |
| t.assert.strictEqual(res.payload, 'Hi!') | |
| done() | |
| }) | |
| }) | |
| test('form-data should be handled correctly', (t, done) => { | |
| t.plan(4) | |
| const dispatch = function (req, res) { | |
| t.assert.strictEqual(req.headers['transfer-encoding'], undefined) | |
| let body = '' | |
| req.on('data', d => { | |
| body += d | |
| }) | |
| req.on('end', () => { | |
| res.end(body) | |
| }) | |
| } | |
| const form = new NpmFormData() | |
| form.append('my_field', 'my value') | |
| inject(dispatch, { | |
| method: 'POST', | |
| url: 'http://example.com:8080/hello', | |
| headers: { | |
| // Transfer-encoding is automatically deleted if Stream1 is used | |
| 'transfer-encoding': 'chunked' | |
| }, | |
| payload: form | |
| }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.statusCode, 200) | |
| t.assert.ok(/--.+\r\nContent-Disposition: form-data; name="my_field"\r\n\r\nmy value\r\n--.+--\r\n/.test(res.payload)) | |
| done() | |
| }) | |
| }) | |
| test('path as alias to url', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.url) | |
| } | |
| inject(dispatch, { method: 'GET', path: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, '/hello') | |
| done() | |
| }) | |
| }) | |
| test('Should throw if both path and url are missing', (t) => { | |
| t.plan(1) | |
| t.assert.throws( | |
| () => inject(() => {}, { method: 'GET' }, () => {}), | |
| { message: /must have required property 'url',must have required property 'path'/ } | |
| ) | |
| }) | |
| test('chainable api: backwards compatibility for promise (then)', (t, done) => { | |
| t.plan(1) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('hello') | |
| } | |
| inject(dispatch) | |
| .get('/') | |
| .then(res => t.assert.strictEqual(res.payload, 'hello')) | |
| .catch(t.assert.fail) | |
| .finally(done) | |
| }) | |
| test('chainable api: backwards compatibility for promise (catch)', (t, done) => { | |
| t.plan(1) | |
| function dispatch () { | |
| throw Error | |
| } | |
| inject(dispatch) | |
| .get('/') | |
| .catch(err => t.assert.ok(err)) | |
| .finally(done) | |
| }) | |
| test('chainable api: multiple call of then should return the same promise', (t, done) => { | |
| t.plan(2) | |
| let id = 0 | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain', 'Request-Id': id }) | |
| ++id | |
| t.assert.ok('request id incremented') | |
| res.end('hello') | |
| } | |
| const chain = inject(dispatch).get('/') | |
| chain.then(res => { | |
| chain.then(rep => { | |
| t.assert.strictEqual(res.headers['request-id'], rep.headers['request-id']) | |
| done() | |
| }) | |
| }) | |
| }) | |
| test('chainable api: http methods should work correctly', (t, done) => { | |
| t.plan(16) | |
| function dispatch (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.method) | |
| } | |
| httpMethods.forEach((method, index) => { | |
| inject(dispatch)[method]('http://example.com:8080/hello') | |
| .end((err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.body, method.toUpperCase()) | |
| if (index === httpMethods.length - 1) { | |
| done() | |
| } | |
| }) | |
| }) | |
| }) | |
| test('chainable api: http methods should throw if already invoked', (t, done) => { | |
| t.plan(8) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| httpMethods.forEach((method, index) => { | |
| const chain = inject(dispatch)[method]('http://example.com:8080/hello') | |
| chain.end() | |
| t.assert.throws(() => chain[method]('/'), Error) | |
| if (index === httpMethods.length - 1) { | |
| done() | |
| } | |
| }) | |
| }) | |
| test('chainable api: body method should work correctly', (t, done) => { | |
| t.plan(2) | |
| function dispatch (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch) | |
| .get('http://example.com:8080/hello') | |
| .body('test') | |
| .end((err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.body, 'test') | |
| done() | |
| }) | |
| }) | |
| test('chainable api: cookie', (t, done) => { | |
| t.plan(2) | |
| function dispatch (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.cookie) | |
| } | |
| inject(dispatch) | |
| .get('http://example.com:8080/hello') | |
| .body('test') | |
| .cookies({ hello: 'world', fastify: 'rulez' }) | |
| .end((err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.body, 'hello=world; fastify=rulez') | |
| done() | |
| }) | |
| }) | |
| test('chainable api: body method should throw if already invoked', (t) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch) | |
| chain | |
| .get('http://example.com:8080/hello') | |
| .end() | |
| t.assert.throws(() => chain.body('test'), Error) | |
| }) | |
| test('chainable api: headers method should work correctly', (t, done) => { | |
| t.plan(2) | |
| function dispatch (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.foo) | |
| } | |
| inject(dispatch) | |
| .get('http://example.com:8080/hello') | |
| .headers({ foo: 'bar' }) | |
| .end((err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'bar') | |
| done() | |
| }) | |
| }) | |
| test('chainable api: headers method should throw if already invoked', (t) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch) | |
| chain | |
| .get('http://example.com:8080/hello') | |
| .end() | |
| t.assert.throws(() => chain.headers({ foo: 'bar' }), Error) | |
| }) | |
| test('chainable api: payload method should work correctly', (t, done) => { | |
| t.plan(2) | |
| function dispatch (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch) | |
| .get('http://example.com:8080/hello') | |
| .payload('payload') | |
| .end((err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'payload') | |
| done() | |
| }) | |
| }) | |
| test('chainable api: payload method should throw if already invoked', (t) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch) | |
| chain | |
| .get('http://example.com:8080/hello') | |
| .end() | |
| t.assert.throws(() => chain.payload('payload'), Error) | |
| }) | |
| test('chainable api: query method should work correctly', (t, done) => { | |
| t.plan(2) | |
| const query = { | |
| message: 'OK', | |
| xs: ['foo', 'bar'] | |
| } | |
| function dispatch (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.url) | |
| } | |
| inject(dispatch) | |
| .get('http://example.com:8080/hello') | |
| .query(query) | |
| .end((err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.deepEqual(parseQuery(res.payload), query) | |
| done() | |
| }) | |
| }) | |
| test('chainable api: query method should throw if already invoked', (t) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch) | |
| chain | |
| .get('http://example.com:8080/hello') | |
| .end() | |
| t.assert.throws(() => chain.query({ foo: 'bar' }), Error) | |
| }) | |
| test('chainable api: invoking end method after promise method should throw', (t) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch).get('http://example.com:8080/hello') | |
| chain.then() | |
| t.assert.throws(() => chain.end(), Error) | |
| }) | |
| test('chainable api: invoking promise method after end method with a callback function should throw', (t, done) => { | |
| t.plan(2) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch).get('http://example.com:8080/hello') | |
| chain.end((err) => { | |
| t.assert.ifError(err) | |
| done() | |
| }) | |
| t.assert.throws(() => chain.then(), Error) | |
| }) | |
| test('chainable api: invoking promise method after end method without a callback function should work properly', (t, done) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('hello') | |
| } | |
| inject(dispatch) | |
| .get('http://example.com:8080/hello') | |
| .end() | |
| .then(res => t.assert.strictEqual(res.payload, 'hello')) | |
| .finally(done) | |
| }) | |
| test('chainable api: invoking end method multiple times should throw', (t) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| const chain = inject(dispatch).get('http://example.com:8080/hello') | |
| chain.end() | |
| t.assert.throws(() => chain.end(), Error) | |
| }) | |
| test('chainable api: string url', (t, done) => { | |
| t.plan(2) | |
| function dispatch (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| t.assert.ok('pass') | |
| } | |
| const chain = inject(dispatch, 'http://example.com:8080/hello') | |
| chain.then(() => t.assert.ok('pass')).finally(done) | |
| }) | |
| test('Response.json() should parse the JSON payload', (t, done) => { | |
| t.plan(2) | |
| const jsonData = { | |
| a: 1, | |
| b: '2' | |
| } | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'application/json' }) | |
| res.end(JSON.stringify(jsonData)) | |
| } | |
| inject(dispatch, { method: 'GET', path: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| const { json } = res | |
| t.assert.deepStrictEqual(json(), jsonData) | |
| done() | |
| }) | |
| }) | |
| test('Response.json() should not throw an error if content-type is not application/json', (t, done) => { | |
| t.plan(2) | |
| const jsonData = { | |
| a: 1, | |
| b: '2' | |
| } | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(JSON.stringify(jsonData)) | |
| } | |
| inject(dispatch, { method: 'GET', path: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| const { json } = res | |
| t.assert.deepStrictEqual(json(), jsonData) | |
| done() | |
| }) | |
| }) | |
| test('Response.json() should throw an error if the payload is not of valid JSON format', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'application/json' }) | |
| res.end('notAJSON') | |
| } | |
| inject(dispatch, { method: 'GET', path: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.throws(res.json, Error) | |
| done() | |
| }) | |
| }) | |
| test('Response.stream() should provide a Readable stream', (t, done) => { | |
| const lines = [ | |
| JSON.stringify({ foo: 'bar' }), | |
| JSON.stringify({ hello: 'world' }) | |
| ] | |
| t.plan(2 + lines.length) | |
| const dispatch = function (_req, res) { | |
| res.writeHead(200, { 'Content-Type': 'multiple/json' }) | |
| for (const line of lines) { | |
| res.write(line) | |
| } | |
| res.end() | |
| } | |
| inject(dispatch, { method: 'GET', path: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| const readable = res.stream() | |
| const payload = [] | |
| t.assert.strictEqual(readable instanceof Readable, true) | |
| readable.on('data', function (chunk) { | |
| payload.push(chunk) | |
| }) | |
| readable.on('end', function () { | |
| for (let i = 0; i < lines.length; i++) { | |
| t.assert.strictEqual(lines[i], payload[i].toString()) | |
| } | |
| done() | |
| }) | |
| }) | |
| }) | |
| test('promise api should auto start (fire and forget)', (t, done) => { | |
| t.plan(1) | |
| function dispatch (_req, res) { | |
| t.assert.ok('dispatch called') | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| } | |
| inject(dispatch, 'http://example.com:8080/hello') | |
| process.nextTick(done) | |
| }) | |
| test('disabling autostart', (t, done) => { | |
| t.plan(3) | |
| let called = false | |
| function dispatch (_req, res) { | |
| t.assert.ok('dispatch called') | |
| called = true | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end() | |
| done() | |
| } | |
| const p = inject(dispatch, { | |
| url: 'http://example.com:8080/hello', | |
| autoStart: false | |
| }) | |
| setImmediate(() => { | |
| t.assert.strictEqual(called, false) | |
| p.then(() => { | |
| t.assert.strictEqual(called, true) | |
| }) | |
| }) | |
| }) | |
| function getTestStream (encoding) { | |
| const word = 'hi' | |
| let i = 0 | |
| const stream = new Readable({ | |
| read () { | |
| this.push(word[i] ? word[i++] : null) | |
| } | |
| }) | |
| if (encoding) { | |
| stream.setEncoding(encoding) | |
| } | |
| return stream | |
| } | |
| function readStream (stream, callback) { | |
| const chunks = [] | |
| stream.on('data', (chunk) => chunks.push(chunk)) | |
| stream.on('end', () => { | |
| return callback(Buffer.concat(chunks)) | |
| }) | |
| } | |
| test('send cookie', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host + '|' + req.headers.cookie) | |
| } | |
| inject(dispatch, { url: 'http://example.com:8080/hello', cookies: { foo: 'bar', grass: 'àìùòlé' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:8080|foo=bar; grass=%C3%A0%C3%AC%C3%B9%C3%B2l%C3%A9') | |
| t.assert.strictEqual(res.rawPayload.toString(), 'example.com:8080|foo=bar; grass=%C3%A0%C3%AC%C3%B9%C3%B2l%C3%A9') | |
| done() | |
| }) | |
| }) | |
| test('send cookie with header already set', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host + '|' + req.headers.cookie) | |
| } | |
| inject(dispatch, { | |
| url: 'http://example.com:8080/hello', | |
| headers: { cookie: 'custom=one' }, | |
| cookies: { foo: 'bar', grass: 'àìùòlé' } | |
| }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:8080|custom=one; foo=bar; grass=%C3%A0%C3%AC%C3%B9%C3%B2l%C3%A9') | |
| t.assert.strictEqual(res.rawPayload.toString(), 'example.com:8080|custom=one; foo=bar; grass=%C3%A0%C3%AC%C3%B9%C3%B2l%C3%A9') | |
| done() | |
| }) | |
| }) | |
| test('read cookie', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.setHeader('Set-Cookie', [ | |
| 'type=ninja', | |
| 'dev=me; Expires=Fri, 17 Jan 2020 20:26:08 -0000; Max-Age=1234; Domain=.home.com; Path=/wow; Secure; HttpOnly; SameSite=Strict' | |
| ]) | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host + '|' + req.headers.cookie) | |
| } | |
| inject(dispatch, { url: 'http://example.com:8080/hello', cookies: { foo: 'bar' } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:8080|foo=bar') | |
| t.assert.deepStrictEqual(res.cookies, [ | |
| { name: 'type', value: 'ninja' }, | |
| { | |
| name: 'dev', | |
| value: 'me', | |
| expires: new Date('Fri, 17 Jan 2020 20:26:08 -0000'), | |
| maxAge: 1234, | |
| domain: '.home.com', | |
| path: '/wow', | |
| secure: true, | |
| httpOnly: true, | |
| sameSite: 'Strict' | |
| } | |
| ]) | |
| done() | |
| }) | |
| }) | |
| test('correctly handles no string headers', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| const payload = JSON.stringify(req.headers) | |
| res.writeHead(200, { | |
| 'Content-Type': 'application/json', | |
| integer: 12, | |
| float: 3.14, | |
| null: null, | |
| string: 'string', | |
| object: { foo: 'bar' }, | |
| array: [1, 'two', 3], | |
| date, | |
| true: true, | |
| false: false | |
| }) | |
| res.end(payload) | |
| } | |
| const date = new Date(0) | |
| const headers = { | |
| integer: 12, | |
| float: 3.14, | |
| null: null, | |
| string: 'string', | |
| object: { foo: 'bar' }, | |
| array: [1, 'two', 3], | |
| date, | |
| true: true, | |
| false: false | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080/hello', headers }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.deepStrictEqual(res.headers, { | |
| integer: '12', | |
| float: '3.14', | |
| null: 'null', | |
| string: 'string', | |
| object: '[object Object]', | |
| array: ['1', 'two', '3'], | |
| date: date.toString(), | |
| true: 'true', | |
| false: 'false', | |
| connection: 'keep-alive', | |
| 'transfer-encoding': 'chunked', | |
| 'content-type': 'application/json' | |
| }) | |
| t.assert.deepStrictEqual(JSON.parse(res.payload), { | |
| integer: '12', | |
| float: '3.14', | |
| null: 'null', | |
| string: 'string', | |
| object: '[object Object]', | |
| array: '1,two,3', | |
| date: date.toString(), | |
| true: 'true', | |
| false: 'false', | |
| host: 'example.com:8080', | |
| 'user-agent': 'lightMyRequest' | |
| }) | |
| done() | |
| }) | |
| }) | |
| test('errors for invalid undefined header value', (t, done) => { | |
| t.plan(1) | |
| try { | |
| inject(() => {}, { url: '/', headers: { 'header-key': undefined } }, () => {}) | |
| } catch (err) { | |
| t.assert.ok(err) | |
| done() | |
| } | |
| }) | |
| test('example with form-auto-content', (t, done) => { | |
| t.plan(4) | |
| const dispatch = function (req, res) { | |
| let body = '' | |
| req.on('data', d => { | |
| body += d | |
| }) | |
| req.on('end', () => { | |
| res.end(body) | |
| }) | |
| } | |
| const form = formAutoContent({ | |
| myField: 'my value', | |
| myFile: fs.createReadStream('./LICENSE') | |
| }) | |
| inject(dispatch, { | |
| method: 'POST', | |
| url: 'http://example.com:8080/hello', | |
| payload: form.payload, | |
| headers: form.headers | |
| }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.statusCode, 200) | |
| t.assert.ok(/--.+\r\nContent-Disposition: form-data; name="myField"\r\n\r\nmy value\r\n--.*/.test(res.payload)) | |
| t.assert.ok(/--.+\r\nContent-Disposition: form-data; name="myFile"; filename="LICENSE"\r\n.*/.test(res.payload)) | |
| done() | |
| }) | |
| }) | |
| test('simulate invalid alter _lightMyRequest.isDone with end', (t, done) => { | |
| const dispatch = function (req) { | |
| req.resume() | |
| req._lightMyRequest.isDone = true | |
| req.on('end', () => { | |
| t.assert.ok('should have end event') | |
| done() | |
| }) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/', simulate: { end: true } }, () => { | |
| t.assert.fail('should not have reply') | |
| }) | |
| }) | |
| test('simulate invalid alter _lightMyRequest.isDone without end', (t, done) => { | |
| const dispatch = function (req) { | |
| req.resume() | |
| req._lightMyRequest.isDone = true | |
| req.on('end', () => { | |
| t.assert.fail('should not have end event') | |
| }) | |
| done() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/', simulate: { end: false } }, () => { | |
| t.assert.fail('should not have reply') | |
| }) | |
| }) | |
| test('no error for response destroy', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (_req, res) { | |
| res.destroy() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.equal(res, null) | |
| t.assert.equal(err.code, 'LIGHT_ECONNRESET') | |
| done() | |
| }) | |
| }) | |
| test('request destory without.assert.ifError', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req) { | |
| req.destroy() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.equal(err.code, 'LIGHT_ECONNRESET') | |
| t.assert.equal(res, null) | |
| done() | |
| }) | |
| }) | |
| test('request destory with error', (t, done) => { | |
| t.plan(2) | |
| const fakeError = new Error('some-err') | |
| const dispatch = function (req) { | |
| req.destroy(fakeError) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.strictEqual(err, fakeError) | |
| t.assert.strictEqual(res, null) | |
| done() | |
| }) | |
| }) | |
| test('compatible with stream.finished', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| finished(res, (err) => { | |
| t.assert.ok(err instanceof Error) | |
| }) | |
| req.destroy() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.equal(err.code, 'LIGHT_ECONNRESET') | |
| t.assert.equal(res, null) | |
| done() | |
| }) | |
| }) | |
| test('compatible with eos', (t, done) => { | |
| t.plan(4) | |
| const dispatch = function (req, res) { | |
| eos(res, (err) => { | |
| t.assert.ok(err instanceof Error) | |
| }) | |
| req.destroy() | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ok(err) | |
| t.assert.equal(err.code, 'LIGHT_ECONNRESET') | |
| t.assert.equal(res, null) | |
| done() | |
| }) | |
| }) | |
| test('compatible with stream.finished pipe a Stream', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (_req, res) { | |
| finished(res, (err) => { | |
| t.assert.ifError(err) | |
| }) | |
| new Readable({ | |
| read () { | |
| this.push('hello world') | |
| this.push(null) | |
| } | |
| }).pipe(res) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.body, 'hello world') | |
| done() | |
| }) | |
| }) | |
| test('compatible with eos, passes error correctly', (t, done) => { | |
| t.plan(3) | |
| const fakeError = new Error('some-error') | |
| const dispatch = function (req, res) { | |
| eos(res, (err) => { | |
| t.assert.strictEqual(err, fakeError) | |
| }) | |
| req.destroy(fakeError) | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.strictEqual(err, fakeError) | |
| t.assert.strictEqual(res, null) | |
| done() | |
| }) | |
| }) | |
| test('multiple calls to req.destroy should not be called', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req) { | |
| req.destroy() | |
| req.destroy() // twice | |
| } | |
| inject(dispatch, { method: 'GET', url: '/' }, (err, res) => { | |
| t.assert.equal(res, null) | |
| t.assert.equal(err.code, 'LIGHT_ECONNRESET') | |
| done() | |
| }) | |
| }) | |
| test('passes headers when using an express app', (t, done) => { | |
| t.plan(2) | |
| const app = express() | |
| app.get('/hello', (_req, res) => { | |
| res.setHeader('Some-Fancy-Header', 'a very cool value') | |
| res.end() | |
| }) | |
| inject(app, { method: 'GET', url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['some-fancy-header'], 'a very cool value') | |
| done() | |
| }) | |
| }) | |
| test('value of request url when using inject should not differ', (t, done) => { | |
| t.plan(1) | |
| const server = http.createServer() | |
| const dispatch = function (req, res) { | |
| res.end(req.url) | |
| } | |
| inject(dispatch, { method: 'GET', url: 'http://example.com:8080//hello', server }) | |
| .then(res => { t.assert.strictEqual(res.body, '//hello') }) | |
| .catch(err => t.assert.ifError(err)) | |
| .finally(done) | |
| }) | |
| test('Can parse paths with single leading slash', (t) => { | |
| t.plan(1) | |
| const parsedURL = parseURL('/test', undefined) | |
| t.assert.strictEqual(parsedURL.href, 'http://localhost/test') | |
| }) | |
| test('Can parse paths with two leading slashes', (t) => { | |
| t.plan(1) | |
| const parsedURL = parseURL('//test', undefined) | |
| t.assert.strictEqual(parsedURL.href, 'http://localhost//test') | |
| }) | |
| test('Can parse URLs with two leading slashes', (t) => { | |
| t.plan(1) | |
| const parsedURL = parseURL('https://example.com//test', undefined) | |
| t.assert.strictEqual(parsedURL.href, 'https://example.com//test') | |
| }) | |
| test('Can parse URLs with single leading slash', (t) => { | |
| t.plan(1) | |
| const parsedURL = parseURL('https://example.com/test', undefined) | |
| t.assert.strictEqual(parsedURL.href, 'https://example.com/test') | |
| }) | |
| test('Can abort a request using AbortController/AbortSignal', (t) => { | |
| t.plan(1) | |
| const dispatch = function () {} | |
| const controller = new AbortController() | |
| const promise = inject(dispatch, { | |
| method: 'GET', | |
| url: 'http://example.com:8080/hello', | |
| signal: controller.signal | |
| }) | |
| controller.abort() | |
| const wanted = new Error('The operation was aborted') | |
| wanted.name = 'AbortError' | |
| t.assert.rejects(promise, wanted) | |
| }, { skip: globalThis.AbortController == null }) | |
| test('should pass req to ServerResponse', (t, done) => { | |
| if (parseInt(process.versions.node.split('.', 1)[0], 10) < 16) { | |
| t.assert.ok('Skip because Node version < 16') | |
| t.end() | |
| return | |
| } | |
| t.plan(5) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end(req.headers.host + '|' + req.url) | |
| } | |
| inject(dispatch, 'http://example.com:8080/hello', (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.ok(res.raw.req === res.raw.res.req) | |
| t.assert.ok(res.raw.res.req.removeListener) | |
| t.assert.strictEqual(res.payload, 'example.com:8080|/hello') | |
| t.assert.strictEqual(res.rawPayload.toString(), 'example.com:8080|/hello') | |
| done() | |
| }) | |
| }) | |
| test('should work with pipeline', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| pipeline(req.headers.host + '|' + req.url, res, () => res.end()) | |
| } | |
| inject(dispatch, 'http://example.com:8080/hello', (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.payload, 'example.com:8080|/hello') | |
| t.assert.strictEqual(res.rawPayload.toString(), 'example.com:8080|/hello') | |
| done() | |
| }) | |
| }) | |
| test('should leave the headers user-agent and content-type undefined when the headers are explicitly set to undefined in the inject', (t, done) => { | |
| t.plan(5) | |
| const dispatch = function (req, res) { | |
| t.assert.ok(Array.isArray(req.rawHeaders)) | |
| t.assert.strictEqual(req.headers['user-agent'], undefined) | |
| t.assert.strictEqual(req.headers['content-type'], undefined) | |
| t.assert.strictEqual(req.headers['x-foo'], 'bar') | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('Ok') | |
| } | |
| inject(dispatch, { | |
| url: 'http://example.com:8080/hello', | |
| method: 'POST', | |
| headers: { | |
| 'x-foo': 'bar', | |
| 'user-agent': undefined, | |
| 'content-type': undefined | |
| }, | |
| body: {} | |
| }, (err) => { | |
| t.assert.ifError(err) | |
| done() | |
| }) | |
| }) | |
| test("passes payload when using express' send", (t, done) => { | |
| t.plan(3) | |
| const app = express() | |
| app.get('/hello', (_req, res) => { | |
| res.send('some text') | |
| }) | |
| inject(app, { method: 'GET', url: 'http://example.com:8080/hello' }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-length'], '9') | |
| t.assert.strictEqual(res.payload, 'some text') | |
| done() | |
| }) | |
| }) | |
| test('request that is destroyed errors', (t, done) => { | |
| t.plan(2) | |
| const dispatch = function (req, res) { | |
| readStream(req, () => { | |
| req.destroy() // this should be a no-op | |
| setImmediate(() => { | |
| res.writeHead(200, { 'Content-Type': 'text/plain' }) | |
| res.end('hi') | |
| }) | |
| }) | |
| } | |
| const payload = getTestStream() | |
| inject(dispatch, { method: 'POST', url: '/', payload }, (err, res) => { | |
| t.assert.equal(res, null) | |
| t.assert.equal(err.code, 'LIGHT_ECONNRESET') | |
| done() | |
| }) | |
| }) | |
| function runFormDataUnitTest (name, { FormData, Blob }) { | |
| test(`${name} - form-data should be handled correctly`, (t, done) => { | |
| t.plan(23) | |
| const dispatch = function (req, res) { | |
| let body = '' | |
| t.assert.ok(/multipart\/form-data; boundary=----formdata-[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}(--)?$/.test(req.headers['content-type']), 'proper Content-Type provided') | |
| req.on('data', d => { | |
| body += d | |
| }) | |
| req.on('end', () => { | |
| res.end(body) | |
| }) | |
| } | |
| const form = new FormData() | |
| form.append('field', 'value') | |
| form.append('blob', new Blob(['value']), '') | |
| form.append('blob-with-type', new Blob(['value'], { type: 'text/plain' }), '') | |
| form.append('blob-with-name', new Blob(['value']), 'file.txt') | |
| form.append('number', 1) | |
| inject(dispatch, { | |
| method: 'POST', | |
| url: 'http://example.com:8080/hello', | |
| payload: form | |
| }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.statusCode, 200) | |
| const regexp = [ | |
| // header | |
| /^------formdata-[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}(--)?$/, | |
| // content-disposition | |
| /^Content-Disposition: form-data; name="(.*)"(; filename="(.*)")?$/, | |
| // content-type | |
| /^Content-Type: (.*)$/ | |
| ] | |
| const readable = Readable.from(res.body.split('\r\n')) | |
| let i = 1 | |
| readable.on('data', function (chunk) { | |
| switch (i) { | |
| case 1: | |
| case 5: | |
| case 10: | |
| case 15: | |
| case 20: { | |
| // header | |
| t.assert.ok(regexp[0].test(chunk), 'correct header') | |
| break | |
| } | |
| case 2: | |
| case 6: | |
| case 11: | |
| case 16: { | |
| // content-disposition | |
| t.assert.ok(regexp[1].test(chunk), 'correct content-disposition') | |
| break | |
| } | |
| case 7: | |
| case 12: | |
| case 17: { | |
| // content-type | |
| t.assert.ok(regexp[2].test(chunk), 'correct content-type') | |
| break | |
| } | |
| case 3: | |
| case 8: | |
| case 13: | |
| case 18: { | |
| // empty | |
| t.assert.strictEqual(chunk, '', 'correct space') | |
| break | |
| } | |
| case 4: | |
| case 9: | |
| case 14: | |
| case 19: { | |
| // value | |
| t.assert.strictEqual(chunk, 'value', 'correct value') | |
| break | |
| } | |
| } | |
| i++ | |
| }) | |
| done() | |
| }) | |
| }, { skip: FormData == null || Blob == null }) | |
| } | |
| // supports >= node@18 | |
| runFormDataUnitTest('native', { FormData: globalThis.FormData, Blob: globalThis.Blob }) | |
| // supports >= node@16 | |
| runFormDataUnitTest('undici', { FormData: require('undici').FormData, Blob: require('node:buffer').Blob }) | |
| // supports >= node@14 | |
| runFormDataUnitTest('formdata-node', { FormData: require('formdata-node').FormData, Blob: require('formdata-node').Blob }) | |
| test('QUERY method works', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'content-type': req.headers['content-type'] }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'QUERY', url: '/test', payload: { a: 1 } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-type'], 'application/json') | |
| t.assert.strictEqual(res.payload, '{"a":1}') | |
| done() | |
| }) | |
| }) | |
| test('query method works', (t, done) => { | |
| t.plan(3) | |
| const dispatch = function (req, res) { | |
| res.writeHead(200, { 'content-type': req.headers['content-type'] }) | |
| req.pipe(res) | |
| } | |
| inject(dispatch, { method: 'query', url: '/test', payload: { a: 1 } }, (err, res) => { | |
| t.assert.ifError(err) | |
| t.assert.strictEqual(res.headers['content-type'], 'application/json') | |
| t.assert.strictEqual(res.payload, '{"a":1}') | |
| done() | |
| }) | |
| }) | |
| test('should return the file content', async (t) => { | |
| const multerMiddleware = multer({ | |
| storage: multer.memoryStorage(), | |
| limits: { | |
| fileSize: 1024 | |
| } | |
| }) | |
| const app = express() | |
| app.use((req, res, next) => { | |
| if (req.headers['content-type'].indexOf('multipart/form-data') === 0) { | |
| req.multipart = true | |
| } | |
| next() | |
| }) | |
| app.post('/hello', multerMiddleware.single('textFile'), (req, res) => { | |
| res.send(req.file.buffer.toString('utf8')) | |
| }) | |
| app.use((err, req, res, next) => { | |
| console.warn(err) | |
| res.status(500).send('Something was wrong') | |
| }) | |
| const formData = new FormData() | |
| formData.append('textFile', new Blob(['some data']), 'sample.txt') | |
| const response = await inject(app, { | |
| method: 'POST', | |
| url: 'http://example.com:8080/hello', | |
| payload: formData | |
| }) | |
| t.assert.equal(response.statusCode, 200) | |
| t.assert.equal(response.payload, 'some data') | |
| }) | |