UNPKG

8.56 kBJavaScriptView Raw
1const Koa = require('koa');
2const LRU = require('lru-cache');
3const intoStream = require('into-stream');
4const request = require('supertest');
5const test = require('ava');
6
7const cash = require('..');
8
9const createApp = function(c, opts) {
10 const app = new Koa();
11 app.use(
12 cash(
13 opts || {
14 get(key) {
15 return c.get(key);
16 },
17 set(key, value) {
18 return c.set(key, value);
19 }
20 }
21 )
22 );
23 return app;
24};
25
26test.cb('should pass the maxAge through ctx.cash=', t => {
27 let set = false;
28
29 const c = new LRU();
30 const app = createApp(c, {
31 get(key) {
32 return c.get(key);
33 },
34 set(key, value, maxAge) {
35 set = true;
36 t.is(maxAge, 300);
37 return c.set(key, value);
38 }
39 });
40
41 app.use(async function(ctx) {
42 if (await ctx.cashed()) return;
43 ctx.cash = {
44 maxAge: 300
45 };
46 ctx.body = 'lol';
47 });
48
49 request(app.listen())
50 .get('/')
51 .expect(200)
52 .expect('lol', err => {
53 if (err) return t.end(err);
54
55 t.truthy(set);
56 t.is(c.get('/').body, 'lol');
57 t.end();
58 });
59});
60
61test.cb('when body is a string it should cache the response', t => {
62 const c = new LRU();
63 const app = createApp(c);
64 app.use(async function(ctx) {
65 if (await ctx.cashed()) return;
66 ctx.body = 'lol';
67 });
68
69 request(app.listen())
70 .get('/')
71 .expect(200)
72 .expect('lol', err => {
73 if (err) return t.end(err);
74
75 t.is(c.get('/').body, 'lol');
76 t.end();
77 });
78});
79
80test.cb('when the body is a buffer it should cache the response', t => {
81 const c = new LRU();
82 const app = createApp(c);
83 app.use(async function(ctx) {
84 if (await ctx.cashed()) return;
85 ctx.body = Buffer.from('lol');
86 });
87
88 request(app.listen())
89 .get('/')
90 .expect(200)
91 .expect('lol', err => {
92 if (err) return t.end(err);
93
94 t.is(c.get('/').body.toString('utf8'), 'lol');
95 t.end();
96 });
97});
98
99test.cb('when the body is JSON it should cache the response', t => {
100 const c = new LRU();
101 const app = createApp(c);
102 app.use(async function(ctx) {
103 if (await ctx.cashed()) return;
104 ctx.body = {
105 message: 'hi'
106 };
107 });
108
109 request(app.listen())
110 .get('/')
111 .expect(200)
112 .expect('{"message":"hi"}', err => {
113 if (err) return t.end(err);
114
115 t.is(c.get('/').body, '{"message":"hi"}');
116 t.end();
117 });
118});
119
120test.cb('when the body is a stream it should cache the response', t => {
121 const c = new LRU();
122 const app = createApp(c);
123 app.use(async function(ctx) {
124 if (await ctx.cashed()) return;
125 ctx.body = intoStream('lol');
126 });
127
128 request(app.listen())
129 .get('/')
130 .expect(200)
131 .expect('lol', err => {
132 if (err) return t.end(err);
133
134 t.is(c.get('/').body.toString('utf8'), 'lol');
135 t.end();
136 });
137});
138
139test.cb('when the type is compressible it should compress the body', t => {
140 const c = new LRU();
141 const app = createApp(c);
142 app.use(async function(ctx) {
143 if (await ctx.cashed()) return;
144 ctx.response.type = 'text/plain';
145 ctx.body = Buffer.alloc(2048);
146 });
147
148 request(app.listen())
149 .get('/')
150 .expect('Content-Encoding', 'gzip')
151 .expect(200, err => {
152 if (err) return t.end(err);
153
154 t.truthy(c.get('/').body);
155 t.truthy(c.get('/').gzip);
156 t.is(c.get('/').type, 'text/plain; charset=utf-8');
157 t.end();
158 });
159});
160
161test.cb(
162 'when the type is compressible it should handle possible data serialisation and deserialisation',
163 t => {
164 const c = new LRU();
165 const app = createApp(c, {
166 get(key) {
167 const value = c.get(key);
168 return value && JSON.parse(value);
169 },
170 set(key, value) {
171 return c.set(key, JSON.stringify(value));
172 }
173 });
174 app.use(async function(ctx) {
175 if (await ctx.cashed()) return;
176 ctx.body = new Array(1024).join('42');
177 });
178
179 const server = app.listen();
180 request(server)
181 .get('/')
182 .expect('Content-Encoding', 'gzip')
183 .expect(200, (err, res1) => {
184 if (err) return t.end(err);
185
186 request(server)
187 .get('/')
188 .expect('Content-Encoding', 'gzip')
189 .expect(200, (err, res2) => {
190 if (err) return t.end(err);
191
192 t.is(res1.text, res2.text);
193 t.end();
194 });
195 });
196 }
197);
198
199test.cb(
200 'when the type is not compressible it should not compress the body',
201 t => {
202 const c = new LRU();
203 const app = createApp(c);
204 app.use(async function(ctx) {
205 if (await ctx.cashed()) return;
206 ctx.response.type = 'image/png';
207 ctx.body = Buffer.alloc(2048);
208 });
209
210 request(app.listen())
211 .get('/')
212 .expect('Content-Encoding', 'identity')
213 .expect(200, err => {
214 if (err) return t.end(err);
215
216 t.truthy(c.get('/').body);
217 t.true(!c.get('/').gzip);
218 t.is(c.get('/').type, 'image/png');
219 t.end();
220 });
221 }
222);
223
224test.cb(
225 'when the body is below the threshold it should not compress the body',
226 t => {
227 const c = new LRU();
228 const app = createApp(c);
229 app.use(async function(ctx) {
230 if (await ctx.cashed()) return;
231 ctx.body = 'lol';
232 });
233
234 request(app.listen())
235 .get('/')
236 .expect('Content-Encoding', 'identity')
237 .expect('lol')
238 .expect(200, err => {
239 if (err) return t.end(err);
240
241 t.truthy(c.get('/').body);
242 t.true(!c.get('/').gzip);
243 t.is(c.get('/').type, 'text/plain; charset=utf-8');
244 t.end();
245 });
246 }
247);
248
249test.cb('when the method is HEAD it should cache the response', t => {
250 const c = new LRU();
251 const app = createApp(c);
252 app.use(async function(ctx) {
253 if (await ctx.cashed()) return;
254 ctx.body = 'lol';
255 });
256
257 request(app.listen())
258 .head('/')
259 .expect('')
260 .expect(200, err => {
261 if (err) return t.end(err);
262
263 t.is(c.get('/').body, 'lol');
264 t.is(c.get('/').type, 'text/plain; charset=utf-8');
265 t.end();
266 });
267});
268
269test.cb('when the method is POST it should not cache the response', t => {
270 const c = new LRU();
271 const app = createApp(c);
272 app.use(async function(ctx) {
273 if (await ctx.cashed()) return;
274 ctx.body = 'lol';
275 });
276
277 request(app.listen())
278 .post('/')
279 .expect('lol')
280 .expect(200, err => {
281 if (err) return t.end(err);
282
283 t.true(!c.get('/'));
284 t.end();
285 });
286});
287
288test.cb(
289 'when the response code is not 200 it should not cache the response',
290 t => {
291 const c = new LRU();
292 const app = createApp(c);
293 app.use(async function(ctx) {
294 if (await ctx.cashed()) return;
295 ctx.body = 'lol';
296 ctx.status = 201;
297 });
298
299 request(app.listen())
300 .post('/')
301 .expect('lol')
302 .expect(201, err => {
303 if (err) return t.end(err);
304
305 t.true(!c.get('/'));
306 t.end();
307 });
308 }
309);
310
311test.cb(
312 'when etag and last-modified headers are set it should cache those values',
313 t => {
314 const c = new LRU();
315 const app = createApp(c);
316 const date = Math.round(Date.now() / 1000);
317 app.use(async function(ctx) {
318 if (await ctx.cashed()) return;
319 ctx.body = 'lol';
320 ctx.etag = 'lol';
321 ctx.type = 'text/lol; charset=utf-8';
322 ctx.lastModified = new Date(date * 1000);
323 });
324
325 request(app.listen())
326 .get('/')
327 .expect('lol')
328 .expect(200, err => {
329 if (err) return t.end(err);
330
331 const obj = c.get('/');
332 t.truthy(obj);
333 t.is(obj.body, 'lol');
334 t.is(obj.etag, '"lol"');
335 t.is(obj.type, 'text/lol; charset=utf-8');
336 t.is(obj.lastModified.getTime(), new Date(date * 1000).getTime());
337 t.end();
338 });
339 }
340);
341
342test.cb(
343 'when the response is fresh it should return a 304 and cache the response',
344 t => {
345 const c = new LRU();
346 const app = createApp(c);
347 const date = Math.round(Date.now() / 1000);
348 app.use(async function(ctx) {
349 if (await ctx.cashed()) return;
350 ctx.body = 'lol';
351 ctx.etag = 'lol';
352 ctx.type = 'text/lol; charset=utf-8';
353 ctx.lastModified = new Date(date * 1000);
354 });
355
356 const server = app.listen();
357 request(server)
358 .get('/')
359 .set('If-None-Match', '"lol"')
360 .expect('')
361 .expect(304, err => {
362 if (err) return t.end(err);
363
364 const obj = c.get('/');
365 t.truthy(obj);
366 t.is(obj.body, 'lol');
367 t.is(obj.etag, '"lol"');
368 t.is(obj.type, 'text/lol; charset=utf-8');
369 t.is(obj.lastModified.getTime(), new Date(date * 1000).getTime());
370 t.end();
371 });
372 }
373);