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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 | 24x
24x
24x
24x
105x
105x
105x
105x
105x
7x
105x
24x
98x
98x
98x
98x
98x
98x
24x
198x
99x
99x
98x
98x
13x
11x
98x
97x
96x
97x
92x
92x
92x
92x
92x
7x
7x
92x
92x
92x
99x
5x
5x
5x
5x
20x
13x
12x
12x
12x
3x
3x
12x
12x
5x
5x
4x
99x
99x
99x
99x
99x
24x
| const server = require('../');
const request = require('request-promises');
const port = require('./port');
// Make an object with the options as expected by request()
const normalize = (method, url, port, options) => {
// Make sure it's a simple object
Iif (typeof options === 'string') options = { url: options };
// Assign independent parts
options = Object.assign({}, options, { url, method });
// Make sure it has a right URL or localhost otherwise
Eif (!/^https?:\/\//.test(options.url)) {
options.url = `http://localhost:${port}${options.url}`;
}
// Set it to send a JSON when appropriate
if (options.body && typeof options.body === 'object') {
options.json = true;
}
// Finally return the fully formed object
return options;
};
// Parse the server options
const serverOptions = async middle => {
// First parameter can be:
// - options: Number || Object (cannot be ID'd)
// - middleware: undefined || null || Boolean || Function || Array
let opts = (
typeof middle[0] === 'undefined' ||
typeof middle[0] === 'boolean' ||
typeof middle[0] === 'string' ||
middle[0] === null ||
middle[0] instanceof Function ||
middle[0] instanceof Array
) ? {} : middle.shift();
// In case the port is the defaults one
let synthetic = !opts || !opts.port;
await opts;
// Create the port when none was specified
if (synthetic) opts.port = port();
// Be able to set global variables from outside
opts = Object.assign({}, opts, module.exports.options || {}, {
env: undefined,
secret: undefined
});
return opts;
};
module.exports = function (...middle) {
// Make sure we are working with an instance
if (!(this instanceof (module.exports))) {
return new (module.exports)(...middle);
}
const launch = async (method, url, reqOpts) => {
// Parse the server options
const opts = await serverOptions(middle);
const error = server.router.error(ctx => {
if (!ctx.res.headersSent) {
return server.reply.status(500).send(ctx.error.message);
}
});
const ctx = await server(opts, middle, opts.raw ? false : error);
ctx.close = () => new Promise((resolve, reject) => {
ctx.server.close(err => err ? reject(err) : resolve());
});
if (!method) return ctx;
const res = await request(normalize(method, url, ctx.options.port, reqOpts));
// Fix small bug. TODO: report it
res.method = res.request.method;
res.status = res.statusCode;
res.options = ctx.options;
if (/application\/json/.test(res.headers['content-type']) && typeof res.body === 'string') {
res.rawBody = res.body;
res.body = JSON.parse(res.body);
}
res.ctx = ctx;
// Close the server once it has all finished
await ctx.close();
// Return the response that happened from the server
return res;
}
this.alive = async cb => {
let instance;
try {
instance = await launch();
const port = instance.options.port;
const requestApi = request.defaults({ jar: request.jar() });
const generic = method => async (url, options) => {
const res = await requestApi(normalize(method, url, port, options));
res.method = res.request.method;
res.status = res.statusCode;
if (/application\/json/.test(res.headers['content-type']) && typeof res.body === 'string') {
res.rawBody = res.body;
res.body = JSON.parse(res.body);
}
// console.log(instance);
res.ctx = instance;
return res;
};
const api = {
get: generic('GET'),
post: generic('POST'),
put: generic('PUT'),
del: generic('DELETE'),
ctx: instance
};
await cb(api);
} catch (err) {
if (!instance) {
console.log(err);
}
throw err;
} finally {
instance.close();
}
};
this.get = (url, options) => launch('GET', url, options);
this.post = (url, options) => launch('POST', url, options);
this.put = (url, options) => launch('PUT', url, options);
this.del = (url, options) => launch('DELETE', url, options);
return this;
};
module.exports.options = {};
|