mock-request-queue

1.1.0 • Public • Published

mock-request-queue

A super-simple mock for the request library. There's nothing fancy about this mock: no route, nor verb matching. It's just an ordered queue that is consumed as your code executes request. mock-request-queue doesn't break the Open/Closed Principle by overwriting / monkey patching anything. It's intended to be used with Dependency Injection (injecting an instance that meets the request interface into your modules).

NOTE mock-request-queue doesn't implement the entire request interface, however common functions are supplied: request, request.get, request.post, request.put, request.patch, request.delete, request(...).pipe.

Installation

npm install --save-dev mock-request-queue

Usage

Given the following example module, which accepts an instance of request in it's constructor (e.g. constructor injection):

// UserService.js
module.exports = function UserService (request) {
  const getUser = (id) => {
    return new Promise((resolve, reject) => {
      request('https://github.com/losandes/supposed', (err, res, body) => {
        if (err) return reject(err)
        return resolve({ res, body })
      })
    })
  }
 
  return { getUser }
}

If we give the module an instance of MockRequest instead of the request library, we can remove network traffic, and live dependencies from our tests:

const test = require('supposed')
const { MockRequest } = require('mock-request-queue')
const UserService = require('./UserService.js')
 
 
test('when making a request with 2 args: (url, callback)', {
  given: () => {
    const request = new MockRequest()
    request.enqueue(null, { statusCode: 200 }, { id: 42, name: 'Zaphod' })
    return new UserService(request)
  },
  when: (userService) => userService.getUser(42),
  'it should resolve the enqueued request': (then) => (err, actual) => {
    then.ifError(err)
    then.strictEqual(actual.res.statusCode, 200)
    then.strictEqual(actual.res.statusMessage, 'OK')
    then.strictEqual(actual.res.request.href, 'https://github.com/losandes/supposed')
    then.strictEqual(actual.body.id, 42)
    then.strictEqual(actual.body.name, 'Zaphod')
  }
})

enqueue

Use request.enqueue to add a mock response to an instance of MockRequest. The order in which you enqueue responses is the order that they will be executed when requests are made. request.enqueue accepts 3 arguments:

  • err {Error} - a mock request level error
  • response {Object} - the mock response
  • body {Object} - the mock body

NOTE if you don't enqueue enough requests, additional requests will receive an error in their callback stating that a request wasn't enqueued.

request

An instance of MockRequest returns a function, which can be used without verbs:

const { MockRequest } = require('mock-request-queue')
 
request('https://github.com/losandes/supposed', (err, res, body) => { /*...*/ })
request({
  method: 'GET',
  url: 'https://github.com/losandes/supposed'
}, (err, res, body) => { /*...*/ })

Verbs

An instance of MockRequest returns a function that has get, post, put, patch, and delete verbs, which can be used instead of the main request function.

const { MockRequest } = require('mock-request-queue')
 
request.get('https://github.com/losandes/supposed', (err, res, body) => { /*...*/ })
request.post({
  url: 'https://github.com/losandes/supposed'
}, (err, res, body) => { /*...*/ })
request.put({
  url: 'https://github.com/losandes/supposed'
}, (err, res, body) => { /*...*/ })
request.patch({
  url: 'https://github.com/losandes/supposed'
}, (err, res, body) => { /*...*/ })
request.delete('https://github.com/losandes/supposed', (err, res, body) => { /*...*/ })

NOTE that enqueue does not perform route, nor verb matching.

Streams

To pipe a mock stream, skip passing the callback to request. First, let's look at an example writable stream / consumer:

const { Writable } = require('stream')
 
class TestWritable extends Writable {
  /**
   * Creates a Writable stream with support for running in a Promise
   * @param resolve {function} - the `resolve` function of a new Promise
   * @param reject {function} - the `reject` function of a new Promise
   */
  constructor (options) {
    super({ ...{ objectMode: true }, ...options })
 
    if (!options || !options.resolve || !options.reject) {
      throw new Error('Expected expectedBody, and resolve, and reject functions to be provided')
    }
 
    const { resolve, reject } = options
 
    this.buffers = []
    this.response = null
 
    this.on('response', (res) => { this.response = res })
    this.on('error', reject)
    this.on('end', () => resolve({
      res: this.getResponse(),
      body: this.getBody()
    }))
  }
 
  _write (chunk, encoding, next) {
    this.buffers.push(chunk)
    next()
  }
 
  getResponse () {
    return this.response
  }
 
  getBody () {
    return this.buffers.join('')
  }
}

Given a writable stream like this, we can:

const fs = require('fs')
const path = require('path')
const test = require('supposed')
const { MockRequest } = require('mock-request-queue')
 
// <TestWritable> (from example above)
 
test('when making a request with 2 args: (url, callback)', {
  given: () => {
    const request = new MockRequest()
    // you can enqueue, a string, an object, or a Readable stream
    request.enqueue(null, { statusCode: 200 }, '{ "message": "ok" }')
    request.enqueue(null, { statusCode: 200 }, { message: 'ok' })
    request.enqueue(
      null,
      { statusCode: 200 },
      fs.createReadStream(path.join(__dirname, 'README.md'))
    )
 
    return { request }
  },
  when: ({ request }) => {
    const results = [
      new Promise((resolve, reject) => {
        request('https://github.com/losandes/supposed')
          .pipe(new TestWritable({ resolve, reject }))
      }),
      new Promise((resolve, reject) => {
        request('https://github.com/losandes/supposed')
          .pipe(new TestWritable({ resolve, reject }))
      }),
      new Promise((resolve, reject) => {
        request('https://github.com/losandes/supposed')
          .pipe(new TestWritable({ resolve, reject }))
      })
    ]
 
    return Promise.all(results)
  },
  'it should pipe the request output to the given writable stream': (then) => (err, results) => {
    then.ifError(err)
 
    results.forEach((actual) => {
      then.strictEqual(actual.res.statusCode, 200)
      then.strictEqual(actual.res.statusMessage, 'OK')
      then.strictEqual(actual.res.request.href, 'https://github.com/losandes/supposed')
    })
  }
})

Dependents (0)

Package Sidebar

Install

npm i mock-request-queue

Weekly Downloads

5

Version

1.1.0

License

MIT

Unpacked Size

34 kB

Total Files

13

Last publish

Collaborators

  • losandes