1 |
|
2 | const { expect } = require('chai');
|
3 |
|
4 | const Grown = require('../../..')();
|
5 |
|
6 | Grown.use(require('../../test'));
|
7 | Grown.use(require('..'));
|
8 |
|
9 |
|
10 |
|
11 | describe('Grown.Conn', () => {
|
12 | let server;
|
13 |
|
14 | beforeEach(() => {
|
15 | server = new Grown();
|
16 | server.plug(Grown.Conn);
|
17 | server.plug(Grown.Test);
|
18 | });
|
19 |
|
20 | describe('Request', () => {
|
21 | const options = {
|
22 | headers: {
|
23 | 'content-type': 'application/json',
|
24 | },
|
25 | body: '{"foo":"bar"}',
|
26 | };
|
27 |
|
28 | it('should add handful props and methods', () => {
|
29 | return server.request('/', 'POST', options, (err, conn) => {
|
30 | expect(conn.req_headers).to.eql({
|
31 | 'content-type': 'application/json',
|
32 | 'content-length': '13',
|
33 | });
|
34 |
|
35 | expect(conn.is_xhr).to.be.false;
|
36 | expect(conn.is_json).to.be.true;
|
37 | expect(conn.host).to.eql('0.0.0.0');
|
38 | expect(conn.port).to.eql('80');
|
39 | expect(conn.remote_ip).to.eql('0.0.0.0');
|
40 | expect(conn.method).to.eql('POST');
|
41 | expect(conn.params).to.eql({});
|
42 | expect(conn.path_info).to.eql([]);
|
43 | expect(conn.path_params).to.eql({});
|
44 | expect(conn.body_params).to.eql({});
|
45 | expect(conn.request_path).to.eql('/');
|
46 | expect(conn.query_string).to.eql('');
|
47 | expect(conn.query_params).to.eql({});
|
48 | expect(conn.accept_charset).to.eql(['*']);
|
49 | expect(conn.accept_charsets).to.eql(['*']);
|
50 | expect(conn.accept_encoding).to.eql(['identity']);
|
51 | expect(conn.accept_encodings).to.eql(['identity']);
|
52 | expect(conn.accept_language).to.eql(['*']);
|
53 | expect(conn.accept_languages).to.eql(['*']);
|
54 | expect(conn.accept_type).to.eql(['*/*']);
|
55 | expect(conn.accept_types).to.eql(['*/*']);
|
56 |
|
57 | expect(conn.has_type('text')).to.be.false;
|
58 | expect(conn.has_type('json')).to.eql('json');
|
59 | expect(err).to.be.null;
|
60 | });
|
61 | });
|
62 |
|
63 | it('should handle req.headers', () => {
|
64 | return server.request('/', options, (err, conn) => {
|
65 | expect(conn.get_req_header('content-length')).to.eql('13');
|
66 |
|
67 | expect(() => conn.get_req_header(-1)).to.throw(/Invalid req_header/);
|
68 | expect(() => conn.put_req_header(-1)).to.throw(/Invalid req_header/);
|
69 | expect(() => conn.delete_req_header(-1)).to.throw(/Invalid req_header/);
|
70 |
|
71 | conn.put_req_header('foo-bar', 'baz buzz');
|
72 | expect(conn.get_req_header('foo-bar')).to.eql('baz buzz');
|
73 | conn.delete_req_header('foo-bar');
|
74 | expect(conn.get_req_header('foo-bar')).to.be.undefined;
|
75 | expect(err).to.be.null;
|
76 | });
|
77 | });
|
78 |
|
79 | it('should extract host/port from headers', () => {
|
80 | return server.request('/', {
|
81 | headers: {
|
82 | host: 'localhost:8080',
|
83 | },
|
84 | }, (err, conn) => {
|
85 | expect(conn.host).to.eql('localhost');
|
86 | expect(conn.port).to.eql('8080');
|
87 | expect(err).to.be.null;
|
88 | });
|
89 | });
|
90 | });
|
91 |
|
92 | describe('Response', () => {
|
93 | it('should add handful props and methods', () => {
|
94 | return server.request('/', (err, conn) => {
|
95 | expect(conn.has_body).to.be.false;
|
96 | expect(conn.has_status).to.be.true;
|
97 |
|
98 | expect(conn.content_type).to.eql('text/html');
|
99 | expect(() => { conn.content_type = 42; }).to.throw(/Invalid type/);
|
100 |
|
101 | expect(conn.status_code).to.eql(200);
|
102 | expect(() => { conn.status_code = []; }).to.throw(/Invalid status_code/);
|
103 |
|
104 | expect(conn.resp_body).to.be.null;
|
105 | expect(() => { conn.resp_body = []; }).to.throw(/Invalid resp_body/);
|
106 | expect(() => { conn.resp_body = new Array(101).join('A'); }).not.to.throw();
|
107 |
|
108 | expect(conn.resp_charset).to.eql('utf8');
|
109 | expect(() => { conn.resp_charset = ''; }).not.to.throw();
|
110 | expect(() => { conn.resp_charset = -1; }).to.throw(/Invalid charset/);
|
111 | expect(err).to.be.null;
|
112 | });
|
113 | });
|
114 |
|
115 | it('should handle resp.headers', () => {
|
116 | return server.request('/', (err, conn) => {
|
117 | expect(conn.resp_headers).to.eql({
|
118 | 'content-type': 'text/html; charset=utf8',
|
119 | 'content-length': 0,
|
120 | });
|
121 | expect(() => { conn.resp_headers = {}; }).not.to.throw();
|
122 | expect(() => { conn.resp_headers = -1; }).to.throw(/Invalid headers/);
|
123 |
|
124 | conn.put_resp_header('x-truth', '42');
|
125 | conn.merge_resp_headers({ foo: 'bar', baz: 'buzz' });
|
126 | conn.delete_resp_header('foo');
|
127 |
|
128 | expect(conn.get_resp_header('x-truth')).to.eql('42');
|
129 | expect(conn.get_resp_header('foo')).to.be.undefined;
|
130 | expect(conn.get_resp_header('baz')).to.eql('buzz');
|
131 |
|
132 | expect(() => conn.put_resp_header(-1)).to.throw(/Invalid resp_header/);
|
133 | expect(() => conn.get_resp_header(-1)).to.throw(/Invalid resp_header/);
|
134 | expect(() => conn.merge_resp_headers(-1)).to.throw(/Invalid resp_header/);
|
135 | expect(() => conn.delete_resp_header(-1)).to.throw(/Invalid resp_header/);
|
136 | expect(err).to.be.null;
|
137 | });
|
138 | });
|
139 |
|
140 | it('should handle redirect()', () => {
|
141 | server.mount(conn => {
|
142 | expect(() => conn.redirect(-1)).to.throw(/Invalid location/);
|
143 |
|
144 | return conn.redirect('/fix?a=b');
|
145 | });
|
146 |
|
147 | return server.request('/', (err, conn) => {
|
148 | expect(conn.resp_headers).to.eql({ location: '/fix?a=b' });
|
149 | expect(err).to.be.null;
|
150 | });
|
151 | });
|
152 |
|
153 | it('should handle redirect() with full-urls', () => {
|
154 | server.mount(conn => conn.redirect('https://api.soypache.co:8080'));
|
155 |
|
156 | return server.request('/', (err, conn) => {
|
157 | expect(conn.resp_headers).to.eql({ location: 'https://api.soypache.co:8080' });
|
158 | expect(err).to.be.null;
|
159 | });
|
160 | });
|
161 |
|
162 | it('should handle redirect() with timeout', () => {
|
163 | server.mount(conn => conn.redirect('/wait', 1000));
|
164 |
|
165 | return server.request('/', (err, conn) => {
|
166 | expect(conn.res.body).to.contain('<meta http-equiv="refresh" content="1000;url=/wait">');
|
167 | expect(err).to.be.null;
|
168 | });
|
169 | });
|
170 |
|
171 | it('should handle json()', () => {
|
172 | server.mount(conn => {
|
173 | expect(() => conn.json(-1)).to.throw(/Invalid JSON/);
|
174 |
|
175 | return conn.json({ foo: 'bar' });
|
176 | });
|
177 |
|
178 | return server.request('/', (err, conn) => {
|
179 | expect(conn.res.body).to.eql('{"foo":"bar"}');
|
180 | expect(err).to.be.null;
|
181 | });
|
182 | });
|
183 |
|
184 | it('should handle send_file()', () => {
|
185 | server.mount(conn => conn.send_file({ file: __filename }));
|
186 |
|
187 | return server.request('/', (err, conn) => {
|
188 | expect(conn.res.body).to.contain('should handle send_file()');
|
189 | expect(err).to.be.null;
|
190 | });
|
191 | });
|
192 |
|
193 | it('should handle send()', () => {
|
194 | server.mount(conn => conn.send('OSOM'));
|
195 |
|
196 | return server.request('/', (err, conn) => {
|
197 | expect(conn.res.body).to.eql('OSOM');
|
198 | expect(err).to.be.null;
|
199 | });
|
200 | });
|
201 |
|
202 | it('should handle send() as buffer', () => {
|
203 | server.mount(conn => conn.send(Buffer.from('OSOM')));
|
204 |
|
205 | return server.request('/', (err, conn) => {
|
206 | expect(conn.res.body).to.eql('OSOM');
|
207 | expect(err).to.be.null;
|
208 | });
|
209 | });
|
210 |
|
211 | it('should handle send() as stream', () => {
|
212 | server.mount(conn => conn.send(require('fs').createReadStream(__filename)));
|
213 |
|
214 | return server.request('/', (err, conn) => {
|
215 | expect(conn.res.body).to.contain('should handle send() as stream');
|
216 | expect(err).to.be.null;
|
217 | });
|
218 | });
|
219 |
|
220 | it('should handle send() failures', () => {
|
221 | server.mount(conn => {
|
222 | conn.res.finished = true;
|
223 |
|
224 | return conn.send().catch(e => {
|
225 | expect(e.message).to.match(/Already finished/);
|
226 | });
|
227 | });
|
228 |
|
229 | return server.request('/', (err, conn) => conn.res.ok(err));
|
230 | });
|
231 |
|
232 | it('should handle end()', () => {
|
233 | server.mount(conn => conn.end(201));
|
234 |
|
235 | return server.request('/', (err, conn) => conn.res.ok(err, '', 201));
|
236 | });
|
237 |
|
238 | it('should handle end() with text', () => {
|
239 | server.mount(conn => conn.end('OSOM'));
|
240 |
|
241 | return server.request('/', (err, conn) => conn.res.ok(err, 'OSOM', 200));
|
242 | });
|
243 |
|
244 | it('should handle end() with error', () => {
|
245 | server.mount(conn => {
|
246 | const e = new Error('Unexpected');
|
247 |
|
248 | e.toString = () => 'FAILURE';
|
249 | delete e.message;
|
250 | return conn.end(e);
|
251 | });
|
252 |
|
253 | return server.request('/', (err, conn) => conn.res.ok(err, 'FAILURE', 500));
|
254 | });
|
255 |
|
256 | it('should handle end() with message', () => {
|
257 | server.mount(conn => conn.end(400, 'Invalid input'));
|
258 |
|
259 | return server.request('/', (err, conn) => conn.res.ok(err, 'Invalid input', 400));
|
260 | });
|
261 |
|
262 | it('should handle end() failures', () => {
|
263 | server.mount(conn => {
|
264 | conn.res.finished = true;
|
265 | expect(() => conn.end()).to.throw(/Already finished/);
|
266 | });
|
267 |
|
268 | return server.request('/', (err, conn) => conn.res.ok(err, 200));
|
269 | });
|
270 |
|
271 | it('should handle shared state', () => {
|
272 | const template = {
|
273 | locals: {
|
274 | foo: 'bar',
|
275 | },
|
276 | };
|
277 |
|
278 | let emit;
|
279 |
|
280 | server.plug({
|
281 | $install(ctx) {
|
282 | emit = (evt, _ctx, opts) => ctx.emit(evt, _ctx, opts);
|
283 | },
|
284 | });
|
285 |
|
286 | server.mount(conn => {
|
287 | conn.state.title = 'Untitled';
|
288 |
|
289 | return emit('before_render', conn, template);
|
290 | });
|
291 |
|
292 | return server.request('/', (err, conn) => conn.res.ok(err, 200));
|
293 | });
|
294 | });
|
295 | });
|