This repository has been archived on 2023-10-27. You can view files and clone it, but cannot push or open issues or pull requests.
node-fetch-cache/test/tests.js

437 lines
15 KiB
JavaScript
Raw Normal View History

2020-11-28 16:25:23 +00:00
const fs = require('fs');
2020-11-28 16:43:50 +00:00
const FormData = require('form-data');
const assert = require('assert');
2020-11-28 03:26:31 +00:00
const rimraf = require('rimraf');
const path = require('path');
const { URLSearchParams } = require('url');
2021-06-11 19:25:53 +00:00
const standardFetch = require('node-fetch');
const FetchCache = require('../index.js');
2020-11-28 03:26:31 +00:00
const CACHE_PATH = path.join(__dirname, '..', '.cache');
const expectedPngBuffer = fs.readFileSync(path.join(__dirname, 'expected_png.png'));
const TWO_HUNDRED_URL = 'https://httpbin.org/status/200';
const FOUR_HUNDRED_URL = 'https://httpbin.org/status/400';
const THREE_HUNDRED_TWO_URL = 'https://httpbin.org/status/302';
2020-11-28 03:26:31 +00:00
const TEXT_BODY_URL = 'https://httpbin.org/robots.txt';
const JSON_BODY_URL = 'https://httpbin.org/json';
const PNG_BODY_URL = 'https://httpbin.org/image/png';
2020-11-28 03:26:31 +00:00
const TEXT_BODY_EXPECTED = 'User-agent: *\nDisallow: /deny\n';
2021-06-11 19:25:53 +00:00
let cachedFetch;
2020-11-28 03:26:31 +00:00
let body;
function post(body) {
return { method: 'POST', body };
}
2021-06-11 19:25:53 +00:00
function removeDates(arrOrObj) {
if (arrOrObj.date) {
const copy = { ...arrOrObj };
delete copy.date;
return copy;
}
if (Array.isArray(arrOrObj)) {
2021-06-11 20:37:51 +00:00
if (Array.isArray(arrOrObj[0])) {
return arrOrObj.filter(e => e[0] !== 'date');
}
return arrOrObj.filter(e => !Date.parse(e));
2021-06-11 19:25:53 +00:00
}
return arrOrObj;
}
2021-06-11 19:52:15 +00:00
function wait(ms) {
return new Promise((fulfill) => setTimeout(fulfill, ms));
}
2021-06-11 19:25:53 +00:00
async function dualFetch(...args) {
const [cachedFetchResponse, standardFetchResponse] = await Promise.all([
cachedFetch(...args),
standardFetch(...args),
]);
return { cachedFetchResponse, standardFetchResponse };
}
2020-11-28 03:26:31 +00:00
beforeEach(async function() {
rimraf.sync(CACHE_PATH);
2021-06-12 19:47:06 +00:00
cachedFetch = FetchCache.withCache(new FetchCache.MemoryCache());
2020-11-28 03:26:31 +00:00
});
describe('Basic property tests', function() {
it('Has a status property', async function() {
2021-06-11 19:25:53 +00:00
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.status, standardFetchResponse.status);
2020-11-28 03:26:31 +00:00
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.status, standardFetchResponse.status);
});
it('Has a statusText property', async function() {
2021-06-11 19:25:53 +00:00
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.statusText, standardFetchResponse.statusText);
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.statusText, standardFetchResponse.statusText);
});
it('Has a url property', async function() {
2021-06-11 19:25:53 +00:00
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.url, standardFetchResponse.url);
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.url, standardFetchResponse.url);
});
it('Has an ok property', async function() {
2021-06-11 19:25:53 +00:00
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(FOUR_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.ok, standardFetchResponse.ok);
assert.strictEqual(cachedFetchResponse.status, standardFetchResponse.status);
2020-11-28 03:26:31 +00:00
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(FOUR_HUNDRED_URL);
assert.strictEqual(cachedFetchResponse.ok, standardFetchResponse.ok);
assert.strictEqual(cachedFetchResponse.status, standardFetchResponse.status);
});
2021-06-11 19:25:53 +00:00
it('Has a redirected property', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(THREE_HUNDRED_TWO_URL);
assert.strictEqual(cachedFetchResponse.redirected, standardFetchResponse.redirected);
2020-11-28 03:26:31 +00:00
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(THREE_HUNDRED_TWO_URL);
assert.strictEqual(cachedFetchResponse.redirected, standardFetchResponse.redirected);
});
2021-06-11 19:25:53 +00:00
}).timeout(10000);
2021-06-11 19:25:53 +00:00
describe('Header tests', function() {
it('Gets correct raw headers', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(
removeDates(cachedFetchResponse.headers.raw()),
removeDates(standardFetchResponse.headers.raw()),
);
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(
removeDates(cachedFetchResponse.headers.raw()),
removeDates(standardFetchResponse.headers.raw()),
);
});
it('Gets correct header keys', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(cachedFetchResponse.headers.keys(), [...standardFetchResponse.headers.keys()]);
2020-11-28 03:26:31 +00:00
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(cachedFetchResponse.headers.keys(), [...standardFetchResponse.headers.keys()]);
2020-11-28 03:26:31 +00:00
});
2021-06-11 19:25:53 +00:00
it('Gets correct header values', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
2021-06-11 19:52:15 +00:00
assert.deepStrictEqual(
removeDates(cachedFetchResponse.headers.values()),
removeDates([...standardFetchResponse.headers.values()]),
);
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
2021-06-11 19:52:15 +00:00
assert.deepStrictEqual(
removeDates(cachedFetchResponse.headers.values()),
removeDates([...standardFetchResponse.headers.values()]),
);
2021-06-11 19:25:53 +00:00
});
it('Gets correct header entries', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
2021-06-11 20:37:51 +00:00
assert.deepStrictEqual(
removeDates(cachedFetchResponse.headers.entries()),
removeDates([...standardFetchResponse.headers.entries()]),
);
2021-06-11 19:25:53 +00:00
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
2021-06-11 20:37:51 +00:00
assert.deepStrictEqual(
removeDates(cachedFetchResponse.headers.entries()),
removeDates([...standardFetchResponse.headers.entries()]),
);
2021-06-11 19:25:53 +00:00
});
it('Can get a header by value', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert(standardFetchResponse.headers.get('content-length'));
assert.deepStrictEqual(cachedFetchResponse.headers.get('content-length'), standardFetchResponse.headers.get('content-length'));
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(cachedFetchResponse.headers.get('content-length'), standardFetchResponse.headers.get('content-length'));
});
2021-06-11 19:52:15 +00:00
it('Returns undefined for non-existent header', async function() {
const headerName = 'zzzz';
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert(!standardFetchResponse.headers.get(headerName));
assert.deepStrictEqual(cachedFetchResponse.headers.get(headerName), standardFetchResponse.headers.get(headerName));
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(cachedFetchResponse.headers.get(headerName), standardFetchResponse.headers.get(headerName));
});
2021-06-11 19:25:53 +00:00
it('Can get whether a header is present', async function() {
let { cachedFetchResponse, standardFetchResponse } = await dualFetch(TWO_HUNDRED_URL);
assert(standardFetchResponse.headers.has('content-length'));
assert.deepStrictEqual(cachedFetchResponse.headers.has('content-length'), standardFetchResponse.headers.has('content-length'));
cachedFetchResponse = await cachedFetch(TWO_HUNDRED_URL);
assert.deepStrictEqual(cachedFetchResponse.headers.has('content-length'), standardFetchResponse.headers.has('content-length'));
});
2021-06-11 19:52:15 +00:00
}).timeout(10000);
2020-11-28 03:26:31 +00:00
describe('Cache tests', function() {
it('Uses cache', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL);
2020-11-28 03:26:31 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL);
2020-11-28 03:26:31 +00:00
assert.strictEqual(res.fromCache, true);
});
2020-11-28 03:27:59 +00:00
it('Can eject from cache', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL);
2020-11-28 03:27:59 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL);
2020-11-28 03:27:59 +00:00
assert.strictEqual(res.fromCache, true);
await res.ejectFromCache();
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL);
2020-11-28 03:27:59 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL);
2020-11-28 03:27:59 +00:00
assert.strictEqual(res.fromCache, true);
});
2021-06-11 19:25:53 +00:00
it('Does not error if ejecting from cache twice', async function() {
res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, false);
await res.ejectFromCache();
await res.ejectFromCache();
});
it('Gives different string bodies different cache keys', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post('a'));
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post('b'));
assert.strictEqual(res.fromCache, false);
});
it('Gives same string bodies same cache keys', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post('a'));
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post('a'));
assert.strictEqual(res.fromCache, true);
});
it('Gives different URLSearchParams different cache keys', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(new URLSearchParams('a=a')));
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(new URLSearchParams('a=b')));
assert.strictEqual(res.fromCache, false);
});
it('Gives same URLSearchParams same cache keys', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(new URLSearchParams('a=a')));
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(new URLSearchParams('a=a')));
assert.strictEqual(res.fromCache, true);
});
2020-11-28 16:25:23 +00:00
it('Gives different read streams different cache keys', async function() {
const s1 = fs.createReadStream(__filename);
const s2 = fs.createReadStream(path.join(__dirname, '..', 'index.js'));
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(s1));
2020-11-28 16:25:23 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(s2));
2020-11-28 16:25:23 +00:00
assert.strictEqual(res.fromCache, false);
});
it('Gives the same read streams the same cache key', async function() {
const s1 = fs.createReadStream(__filename);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(s1));
2020-11-28 16:25:23 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(s1));
2020-11-28 16:25:23 +00:00
assert.strictEqual(res.fromCache, true);
});
2020-11-28 16:43:50 +00:00
it('Gives different form data different cache keys', async function() {
const data1 = new FormData();
data1.append('a', 'a');
const data2 = new FormData();
data2.append('b', 'b');
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(data1));
2020-11-28 16:43:50 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(data2));
2020-11-28 16:43:50 +00:00
assert.strictEqual(res.fromCache, false);
});
it('Gives same form data same cache keys', async function() {
const data1 = new FormData();
data1.append('a', 'a');
const data2 = new FormData();
data2.append('a', 'a');
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(data1));
2020-11-28 16:43:50 +00:00
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TWO_HUNDRED_URL, post(data2));
2020-11-28 16:43:50 +00:00
assert.strictEqual(res.fromCache, true);
});
2020-11-28 03:26:31 +00:00
}).timeout(10000);
describe('Data tests', function() {
2021-06-11 19:52:15 +00:00
it('Does not support Request objects', async function() {
try {
const request = new standardFetch.Request('https://google.com');
await cachedFetch(request);
throw new Error('The above line should have thrown.');
} catch (err) {
assert(err.message.includes('The first argument must be a string (fetch.Request is not supported).'));
}
});
it('Refuses to consume body twice', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TEXT_BODY_URL);
await res.text();
try {
await res.text();
throw new Error('The above line should have thrown.');
} catch (err) {
2021-06-11 19:52:15 +00:00
assert(err.message.includes('Error: body used already'));
}
});
2020-11-28 03:26:31 +00:00
it('Can get text body', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TEXT_BODY_URL);
2020-11-28 03:26:31 +00:00
body = await res.text();
assert.strictEqual(body, TEXT_BODY_EXPECTED);
assert.strictEqual(res.fromCache, false);
2020-11-28 03:26:31 +00:00
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TEXT_BODY_URL);
2020-11-28 03:26:31 +00:00
body = await res.text();
assert.strictEqual(body, TEXT_BODY_EXPECTED);
assert.strictEqual(res.fromCache, true);
});
it('Can get JSON body', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(JSON_BODY_URL);
body = await res.json();
assert(body.slideshow);
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(JSON_BODY_URL);
body = await res.json();
assert(body.slideshow);
assert.strictEqual(res.fromCache, true);
});
it('Can get PNG buffer body', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(PNG_BODY_URL);
body = await res.buffer();
assert.strictEqual(expectedPngBuffer.equals(body), true);
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(PNG_BODY_URL);
body = await res.buffer();
assert.strictEqual(expectedPngBuffer.equals(body), true);
assert.strictEqual(res.fromCache, true);
});
2021-06-10 15:28:05 +00:00
it('Can stream a body', async function() {
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TEXT_BODY_URL);
2021-06-10 15:28:05 +00:00
body = '';
for await (const chunk of res.body) {
body += chunk.toString();
}
assert.strictEqual(TEXT_BODY_EXPECTED, body);
assert.strictEqual(res.fromCache, false);
2021-06-11 19:25:53 +00:00
res = await cachedFetch(TEXT_BODY_URL);
2021-06-10 15:28:05 +00:00
body = '';
for await (const chunk of res.body) {
body += chunk.toString();
}
assert.strictEqual(TEXT_BODY_EXPECTED, body);
assert.strictEqual(res.fromCache, true);
});
2021-06-11 19:52:15 +00:00
it('Errors if the body type is not supported', async function() {
try {
await cachedFetch(TEXT_BODY_URL, { body: {} });
throw new Error('It was supposed to throw');
} catch (err) {
assert(err.message.includes('Unsupported body type'));
}
});
}).timeout(10000);
describe('Memory cache tests', function() {
it('Supports TTL', async function() {
2021-06-12 19:47:06 +00:00
cachedFetch = FetchCache.withCache(new FetchCache.MemoryCache({ ttl: 100 }));
2021-06-11 19:52:15 +00:00
let res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, false);
res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, true);
await wait(200);
res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, false);
});
2020-11-28 03:26:31 +00:00
}).timeout(10000);
2021-06-12 19:43:35 +00:00
describe('File system cache tests', function() {
it('Supports TTL', async function() {
2021-06-12 19:47:06 +00:00
cachedFetch = FetchCache.withCache(new FetchCache.FileSystemCache({ ttl: 100 }));
2021-06-12 19:43:35 +00:00
let res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, false);
res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, true);
await wait(200);
res = await cachedFetch(TWO_HUNDRED_URL);
assert.strictEqual(res.fromCache, false);
});
it('Can get PNG buffer body', async function() {
2021-06-12 19:47:06 +00:00
cachedFetch = FetchCache.withCache(new FetchCache.FileSystemCache());
2021-06-12 19:43:35 +00:00
res = await cachedFetch(PNG_BODY_URL);
body = await res.buffer();
assert.strictEqual(expectedPngBuffer.equals(body), true);
assert.strictEqual(res.fromCache, false);
res = await cachedFetch(PNG_BODY_URL);
body = await res.buffer();
assert.strictEqual(expectedPngBuffer.equals(body), true);
assert.strictEqual(res.fromCache, true);
});
});