Created
March 7, 2017 16:56
-
-
Save cpsubrian/51cbd9c497f9573f29d368eaa85cfa31 to your computer and use it in GitHub Desktop.
Chainable request helper for testing express apps with jest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import request from './request' | |
// Your express app (or router). | |
import app from './app' | |
it('can serve requests', () => { | |
return request | |
.app(app) | |
.post('/foo/bar') | |
.header({authorization: 'Bearer mytoken'}) | |
.payload({user: 'Brian'}) | |
.debug() // log the req and res | |
.tap((req, res) => { | |
// Stash something from the req or res | |
}) | |
.expect('statusCode', 'toBe', 200) | |
.expect('payload.deep.property', 'toEqual', {some: 'object'}) | |
// Start another request after the prev one. | |
.next() | |
.get('/foo/bar') | |
.expect('payload.message', 'toBe', 'This thing exists') | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-env jest */ | |
import _ from 'lodash' | |
import util from 'util' | |
import {inject} from 'pickleback' | |
class Request { | |
constructor (options, prev) { | |
this.prev = prev || Promise.resolve() | |
this.expectations = [] | |
this.taps = [] | |
this.options = _.defaultsDeep(options || {}, { | |
headers: { | |
'content-type': 'application/json' | |
} | |
}) | |
} | |
app (app) { | |
this._app = app | |
return this | |
} | |
header (key, value) { | |
this.options.headers[key] = value | |
return this | |
} | |
payload (payload) { | |
this.options.payload = payload | |
return this | |
} | |
get (url) { | |
this.options.url = url | |
this.options.method = 'get' | |
return this | |
} | |
post (url) { | |
this.options.url = url | |
this.options.method = 'post' | |
return this | |
} | |
put (url) { | |
this.options.url = url | |
this.options.method = 'put' | |
return this | |
} | |
patch (url) { | |
this.options.url = url | |
this.options.method = 'patch' | |
return this | |
} | |
delete (url) { | |
this.options.url = url | |
this.options.method = 'delete' | |
return this | |
} | |
expect (...args) { | |
this.expectations.push({ | |
prop: args[0], | |
method: args[1], | |
args: args.slice(2) | |
}) | |
return this | |
} | |
inject () { | |
return (new Promise((resolve, reject) => { | |
inject(this._app || app, this.options, (res) => { | |
if ( | |
res.payload && | |
res.payload.length && | |
res.headers['content-type'] && | |
res.headers['content-type'].match(/application\/json/) | |
) { | |
res.rawPayload = res.payload | |
try { | |
res.payload = JSON.parse(res.rawPayload) | |
} catch (e) { | |
return reject(e) | |
} | |
} | |
return resolve(res) | |
}) | |
})) | |
} | |
next (beforeNext) { | |
let opts = _.pick(this.options, 'headers') | |
let next = new Request(opts, this) | |
next._app = this._app | |
next._beforeNext = beforeNext | |
return next | |
} | |
tap (fn) { | |
this.taps.push(fn) | |
return this | |
} | |
debug () { | |
return this.tap((req, res) => { | |
console.log('request options:\n', | |
util.inspect(req.options, {colors: true}) | |
) | |
console.log('response:\n', | |
util.inspect( | |
_.pick(res, 'statusCode', 'headers', 'payload'), | |
{colors: true} | |
) | |
) | |
}) | |
} | |
run () { | |
return this | |
.prev | |
.then((res) => this._beforeNext ? this._beforeNext(this, res) : res) | |
.then(() => this.inject()) | |
.then((res) => { | |
this.taps.forEach((fn) => { | |
fn(this, res) | |
}) | |
this.expectations.forEach(({prop, method, args}) => { | |
let context = expect(_.get(res, prop)) | |
let check = _.get(context, method) | |
check.apply(context, args) | |
}) | |
return res | |
}) | |
} | |
then (cb) { | |
return this.run().then(cb) | |
} | |
} | |
export default new Proxy({}, { | |
get (target, key) { | |
let req = new Request() | |
return req[key].bind(req) | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment