-
Notifications
You must be signed in to change notification settings - Fork 1
/
mock.js
98 lines (79 loc) · 2.49 KB
/
mock.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const hapi = require('hapi')
const boom = require('boom')
const R = require('ramda')
const fs = require('fs')
const path = require('path')
const { load } = require('./contract-loader')
const { log } = require('./request')
const { joiOptions } = require('./options')
const allMethods = ['GET', 'POST', 'PUT', 'DELETE']
const hasPath = R.pathEq([ 'request', 'path' ])
const hasMethod = R.pathEq([ 'request', 'method' ])
const hasHeaders = headers => R.pipe(
R.path(['request', 'headers']),
R.merge(headers),
R.equals(headers)
)
const hasCorrectSchema = ({ method, payload }) => contract => {
const { bodySchema } = contract.request
const result = bodySchema.validate(payload, joiOptions)
return result.error === null
}
const requestMatchesContract = req => R.allPass([
hasPath(req.path),
hasMethod(R.toUpper(req.method)),
hasHeaders(req.headers),
hasCorrectSchema(req)
])
const contractFor = req => R.filter(requestMatchesContract(req))
const notFound = req =>
boom.notFound(`mock data not found for ${req.method}: ${req.path}`)
const parseHeader = (name, value) =>
({ name, value })
const setHeaderFor = response => header => {
const { name, value } = parseHeader(...header)
response.header(name, value)
}
const replyMatch = (h, match) => {
const { status, headers, body } = R.head(match).response
const response = h.response(body).code(status)
R.forEach(setHeaderFor(response), R.toPairs(headers))
return response
}
const handlerFor = contracts => (req, h) => {
log(req)
const match = contractFor(req)(contracts)
if (R.isEmpty(match)) {
return notFound(req)
}
return replyMatch(h, match)
}
const tlsOpts = () => ({
key: fs.readFileSync(path.join(__dirname, 'certs/key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'certs/cert.pem'))
})
const createServerFor = (contracts, { port = 3000, tls = false, cors = true } = {}) => {
const server = new hapi.Server(
Object.assign({ port, routes: { cors } }, tls ? { tls: tlsOpts() } : {})
)
server.route({
method: allMethods,
path: '/{path*}',
handler: handlerFor(contracts)
})
return server
}
const serve = (path, options) =>
createServerFor(load(path), options)
module.exports = async (path, port) => {
console.log('mocking responses for:', path)
const server = serve(path, port)
try {
await server.start()
console.log(`server started at ${server.info.uri}`)
} catch (err) {
console.error('error occured starting server:', err)
}
return server
}
module.exports.serve = serve