1 |
|
2 | const server = require('server');
|
3 | const run = require('server/test/run');
|
4 | const { get, post, put, del, sub, error } = server.router;
|
5 | const { status } = server.reply;
|
6 |
|
7 |
|
8 |
|
9 | const question = { answer: 42 };
|
10 | const mirror = ctx => ctx.data;
|
11 | const hello = () => 'Hello 世界';
|
12 | const throwError = () => {
|
13 | const err = new Error('MockError');
|
14 | err.code = 'test';
|
15 | throw err;
|
16 | };
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | run.options = { security: false };
|
22 |
|
23 | describe('Basic router types', () => {
|
24 | it('can do a GET request', async () => {
|
25 | const mid = get('/', hello);
|
26 |
|
27 | const res = await run(mid).get('/');
|
28 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
29 | });
|
30 |
|
31 | it('can skip a request', async () => {
|
32 | let called = false;
|
33 | const notCalled = ctx => {
|
34 | called = true;
|
35 | };
|
36 | const mid = get('/', () => status(200).send('Done'), notCalled);
|
37 |
|
38 | await run(mid).get('/');
|
39 | expect(called).toBe(false);
|
40 | });
|
41 |
|
42 | it('can do a POST request', async () => {
|
43 | const mid = post('/', ctx => ctx.data);
|
44 |
|
45 | const res = await run(mid).post('/', { body: question });
|
46 | expect(res.body).toEqual({ answer: 42 });
|
47 | expect(res.status).toBe(200);
|
48 | });
|
49 |
|
50 | it('can do a PUT request', async () => {
|
51 | const mid = post('/', ctx => ctx.data);
|
52 |
|
53 | const res = await run(mid).post('/', { body: question });
|
54 | expect(res.body).toEqual({ answer: 42 });
|
55 | expect(res.status).toBe(200);
|
56 | });
|
57 |
|
58 | it('can do a DELETE request', async () => {
|
59 | const mid = del('/', ctx => 'Hello 世界');
|
60 |
|
61 | const res = await run(mid).del('/', { body: question });
|
62 | expect(res.body).toEqual('Hello 世界');
|
63 | expect(res.status).toBe(200);
|
64 | });
|
65 | });
|
66 |
|
67 |
|
68 | describe('Generic paths', () => {
|
69 | it('can do a GET request', async () => {
|
70 | const mid = get(hello);
|
71 |
|
72 | const res = await run(mid).get('/');
|
73 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
74 | });
|
75 |
|
76 | it('can do a GET request', async () => {
|
77 | const mid = get('*', hello);
|
78 |
|
79 | const res = await run(mid).get('/');
|
80 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
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 | describe('Subdomain router', () => {
|
110 | it('can do a request to a subdomain', async () => {
|
111 | const mid = sub('api', get('/', hello));
|
112 |
|
113 | const res = await run((ctx) => {
|
114 | ctx.headers.host = 'api.example.com';
|
115 | }, mid).get('/');
|
116 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
117 | });
|
118 |
|
119 | it('can handle regex', async () => {
|
120 | const mid = sub(/^api$/, get('/', hello));
|
121 |
|
122 | const res = await run((ctx) => {
|
123 | ctx.headers.host = 'api.example.com';
|
124 | }, mid).get('/');
|
125 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
126 | });
|
127 |
|
128 | it('does not do partial match', async () => {
|
129 | const mid = sub(/^api$/, get('/', hello));
|
130 |
|
131 | const res = await run((ctx) => {
|
132 | ctx.headers.host = 'bla.api.example.com';
|
133 | }, mid, () => 'Did not match').get('/');
|
134 | expect(res).toMatchObject({ status: 200, body: 'Did not match' });
|
135 | });
|
136 |
|
137 | it('can do a request to a multi-level subdomain', async () => {
|
138 | const mid = sub('api.local', get('/', hello));
|
139 |
|
140 | const res = await run((ctx) => {
|
141 | ctx.headers.host = 'api.local.example.com';
|
142 | }, mid).get('/');
|
143 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
144 | });
|
145 | });
|
146 |
|
147 |
|
148 | describe('Ends where it should end', () => {
|
149 |
|
150 | it('uses the matching method', async () => {
|
151 | const mid = [
|
152 | post('/', throwError),
|
153 | put('/', throwError),
|
154 | del('/', throwError),
|
155 | get('/', hello)
|
156 | ];
|
157 |
|
158 | const res = await run(mid).get('/');
|
159 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
160 | });
|
161 |
|
162 |
|
163 | it('uses the matching path', async () => {
|
164 | const mid = [
|
165 | get('/bla', throwError),
|
166 | get('/:id', throwError),
|
167 | get('/', hello)
|
168 | ];
|
169 |
|
170 | const res = await run(mid).get('/');
|
171 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
172 | });
|
173 |
|
174 |
|
175 | it('uses a route only once', async () => {
|
176 | const mid = [
|
177 | get('/', hello),
|
178 | get('/', throwError)
|
179 | ];
|
180 |
|
181 | const res = await run(mid).get('/');
|
182 | expect(res).toMatchObject({ status: 200, body: 'Hello 世界' });
|
183 | });
|
184 |
|
185 |
|
186 | it('parses params correctly', async () => {
|
187 | const mid = get('/:id', ctx => ctx.params.id);
|
188 |
|
189 | const res = await run(mid).get('/42?ignored=true');
|
190 | expect(res.body).toBe('42');
|
191 | });
|
192 |
|
193 | // A bug shifted the router's middleware on each request so now we test for
|
194 | // multiple request to make sure the middleware remains the same
|
195 | it('does not modify the router', async () => {
|
196 | await run(get('/', hello)).alive(async api => {
|
197 | for (let url of [0, 1, 2]) {
|
198 | const res = await api.get('/');
|
199 | expect(res.body).toBe('Hello 世界');
|
200 | }
|
201 | });
|
202 | });
|
203 |
|
204 |
|
205 | it('does generic error matching', async () => {
|
206 | let err;
|
207 | const res = await run(throwError, error(ctx => {
|
208 | err = ctx.error;
|
209 | return 'Hello world';
|
210 | })).get('/');
|
211 | expect(res.body).toBe('Hello world');
|
212 | expect(err.message).toMatch(/MockError/);
|
213 | });
|
214 |
|
215 | it('does path error matching', async () => {
|
216 | let err;
|
217 | const res = await run(throwError, error('test', ctx => {
|
218 | err = ctx.error;
|
219 | return 'Hello world';
|
220 | })).get('/');
|
221 | expect(res.body).toBe('Hello world');
|
222 | expect(err.message).toMatch(/MockError/);
|
223 | });
|
224 |
|
225 | it('does empty error matching', async () => {
|
226 | let err;
|
227 | const res = await run(throwError).get('/');
|
228 | expect(res.status).toBe(500);
|
229 | });
|
230 | });
|