add tests, fix flawed logic
This commit is contained in:
parent
bc92aa6865
commit
c452c8d860
54
index.js
54
index.js
@ -7,10 +7,48 @@ function md5(str) {
|
|||||||
return crypto.createHash('md5').update(str).digest('hex');
|
return crypto.createHash('md5').update(str).digest('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Headers {
|
||||||
|
constructor(rawHeaders) {
|
||||||
|
this.rawHeaders = rawHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
* entries() {
|
||||||
|
for (let entry of Object.entries(this.rawHeaders)) {
|
||||||
|
yield entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* keys() {
|
||||||
|
for (let key of Object.keys(this.rawHeaders)) {
|
||||||
|
yield key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* values() {
|
||||||
|
for (let value of Object.values(this.rawHeaders)) {
|
||||||
|
yield value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(name) {
|
||||||
|
return this.rawHeaders[name.toLowerCase()] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
has(name) {
|
||||||
|
return !!this.get(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Response {
|
class Response {
|
||||||
constructor(raw, cacheFilePath) {
|
constructor(raw, cacheFilePath, fromCache) {
|
||||||
Object.assign(this, raw);
|
Object.assign(this, raw);
|
||||||
this.cacheFilePath = cacheFilePath;
|
this.cacheFilePath = cacheFilePath;
|
||||||
|
this.headers = new Headers(raw.headers);
|
||||||
|
this.fromCache = fromCache;
|
||||||
|
|
||||||
|
if (this.bodyBuffer.type === 'Buffer') {
|
||||||
|
this.bodyBuffer = Buffer.from(this.bodyBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text() {
|
text() {
|
||||||
@ -33,14 +71,16 @@ class Response {
|
|||||||
async function createRawResponse(fetchRes) {
|
async function createRawResponse(fetchRes) {
|
||||||
const buffer = await fetchRes.buffer();
|
const buffer = await fetchRes.buffer();
|
||||||
|
|
||||||
|
const rawHeaders = Array.from(fetchRes.headers.entries())
|
||||||
|
.reduce((aggregate, entry) => ({ ...aggregate, [entry[0]]: entry[1] }), {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: fetchRes.status,
|
status: fetchRes.status,
|
||||||
statusText: fetchRes.statusText,
|
statusText: fetchRes.statusText,
|
||||||
type: fetchRes.type,
|
type: fetchRes.type,
|
||||||
url: fetchRes.url,
|
url: fetchRes.url,
|
||||||
useFinalURL: fetchRes.useFinalURL,
|
|
||||||
ok: fetchRes.ok,
|
ok: fetchRes.ok,
|
||||||
headers: fetchRes.headers,
|
headers: rawHeaders,
|
||||||
redirected: fetchRes.redirected,
|
redirected: fetchRes.redirected,
|
||||||
bodyBuffer: buffer,
|
bodyBuffer: buffer,
|
||||||
};
|
};
|
||||||
@ -52,17 +92,17 @@ async function getResponse(cacheDirPath, requestArguments) {
|
|||||||
? ({ ...requestInit, body: typeof requestInit.body === 'object' ? requestInit.body.toString() : requestInit.body })
|
? ({ ...requestInit, body: typeof requestInit.body === 'object' ? requestInit.body.toString() : requestInit.body })
|
||||||
: requestInit;
|
: requestInit;
|
||||||
|
|
||||||
const cacheHash = md5(JSON.stringify([url, requestParams, ...rest]) + bodyFunctionName);
|
const cacheHash = md5(JSON.stringify([url, requestParams, ...rest]));
|
||||||
const cachedFilePath = path.join(cacheDirPath, `${cacheHash}.json`);
|
const cachedFilePath = path.join(cacheDirPath, `${cacheHash}.json`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const rawResponse = JSON.parse(await fs.promises.readFile(cachedFilePath));
|
const rawResponse = JSON.parse(await fs.promises.readFile(cachedFilePath));
|
||||||
return new Response(rawResponse);
|
return new Response(rawResponse, cachedFilePath, true);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const fetchResponse = await fetch(...requestArguments);
|
const fetchResponse = await fetch(...requestArguments);
|
||||||
const rawResponse = createRawResponse(fetchResponse);
|
const rawResponse = await createRawResponse(fetchResponse);
|
||||||
await fs.promises.writeFile(cachedFilePath, JSON.stringify(rawResponse));
|
await fs.promises.writeFile(cachedFilePath, JSON.stringify(rawResponse));
|
||||||
return new Response(rawResponse);
|
return new Response(rawResponse, cachedFilePath, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
package-lock.json
generated
17
package-lock.json
generated
@ -750,6 +750,17 @@
|
|||||||
"flatted": "^2.0.0",
|
"flatted": "^2.0.0",
|
||||||
"rimraf": "2.6.3",
|
"rimraf": "2.6.3",
|
||||||
"write": "1.0.3"
|
"write": "1.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"rimraf": {
|
||||||
|
"version": "2.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||||
|
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flatted": {
|
"flatted": {
|
||||||
@ -1730,9 +1741,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "2.6.3",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-airbnb-base": "^14.1.0",
|
"eslint-config-airbnb-base": "^14.1.0",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-plugin-import": "^2.20.2",
|
||||||
"mocha": "^8.2.1"
|
"mocha": "^8.2.1",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-fetch": "*"
|
"node-fetch": "*"
|
||||||
|
@ -1,50 +1,95 @@
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const rimraf = require('rimraf');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fetch = require('../index.js')(path.join(__dirname, '..', '.cache'));
|
const FetchCache = require('../index.js');
|
||||||
|
|
||||||
|
const CACHE_PATH = path.join(__dirname, '..', '.cache');
|
||||||
|
|
||||||
const TWO_HUNDRED_URL = 'https://httpbin.org/status/200';
|
const TWO_HUNDRED_URL = 'https://httpbin.org/status/200';
|
||||||
const FOUR_HUNDRED_URL = 'https://httpbin.org/status/400';
|
const FOUR_HUNDRED_URL = 'https://httpbin.org/status/400';
|
||||||
const THREE_HUNDRED_TWO_URL = 'https://httpbin.org/status/302';
|
const THREE_HUNDRED_TWO_URL = 'https://httpbin.org/status/302';
|
||||||
|
const TEXT_BODY_URL = 'https://httpbin.org/robots.txt';
|
||||||
|
const TEXT_BODY_EXPECTED = 'User-agent: *\nDisallow: /deny\n';
|
||||||
|
|
||||||
|
let fetch;
|
||||||
|
let res;
|
||||||
|
let body;
|
||||||
|
|
||||||
|
beforeEach(async function() {
|
||||||
|
rimraf.sync(CACHE_PATH);
|
||||||
|
fetch = FetchCache(CACHE_PATH);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Basic property tests', function() {
|
describe('Basic property tests', function() {
|
||||||
it('Has a status property', async function() {
|
it('Has a status property', async function() {
|
||||||
const res = await fetch(TWO_HUNDRED_URL);
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
|
||||||
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Has a statusText property', async function() {
|
it('Has a statusText property', async function() {
|
||||||
const res = await fetch(TWO_HUNDRED_URL);
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
|
assert.strictEqual(res.statusText, 'OK');
|
||||||
|
|
||||||
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
assert.strictEqual(res.statusText, 'OK');
|
assert.strictEqual(res.statusText, 'OK');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Has a type property', async function() {
|
|
||||||
const res = await fetch(TWO_HUNDRED_URL);
|
|
||||||
assert.strictEqual(res.type, 'basic');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Has a url property', async function() {
|
it('Has a url property', async function() {
|
||||||
const res = await fetch(TWO_HUNDRED_URL);
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
|
assert.strictEqual(res.url, TWO_HUNDRED_URL);
|
||||||
|
|
||||||
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
assert.strictEqual(res.url, TWO_HUNDRED_URL);
|
assert.strictEqual(res.url, TWO_HUNDRED_URL);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Has a useFinalURL property', async function() {
|
|
||||||
const res = await fetch(TWO_HUNDRED_URL);
|
|
||||||
assert.strictEqual(res.useFinalURL, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Has an ok property', async function() {
|
it('Has an ok property', async function() {
|
||||||
const res = await fetch(FOUR_HUNDRED_URL);
|
res = await fetch(FOUR_HUNDRED_URL);
|
||||||
|
assert.strictEqual(res.ok, false);
|
||||||
|
assert.strictEqual(res.status, 400);
|
||||||
|
|
||||||
|
res = await fetch(FOUR_HUNDRED_URL);
|
||||||
assert.strictEqual(res.ok, false);
|
assert.strictEqual(res.ok, false);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Has a headers property', async function() {
|
it('Has a headers property', async function() {
|
||||||
const res = await fetch(TWO_HUNDRED_URL);
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
|
assert.notStrictEqual(res.headers, undefined);
|
||||||
|
|
||||||
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
assert.notStrictEqual(res.headers, undefined);
|
assert.notStrictEqual(res.headers, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Has a redirected property', async function() {
|
it('Has a redirected property', async function() {
|
||||||
const res = await fetch(THREE_HUNDRED_TWO_URL);
|
res = await fetch(THREE_HUNDRED_TWO_URL);
|
||||||
|
assert.strictEqual(res.redirected, true);
|
||||||
|
|
||||||
|
res = await fetch(THREE_HUNDRED_TWO_URL);
|
||||||
assert.strictEqual(res.redirected, true);
|
assert.strictEqual(res.redirected, true);
|
||||||
});
|
});
|
||||||
|
}).timeout(10000);
|
||||||
|
|
||||||
|
describe('Cache tests', function() {
|
||||||
|
it('Uses cache', async function() {
|
||||||
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
|
assert.strictEqual(res.fromCache, false);
|
||||||
|
|
||||||
|
res = await fetch(TWO_HUNDRED_URL);
|
||||||
|
assert.strictEqual(res.fromCache, true);
|
||||||
});
|
});
|
||||||
|
}).timeout(10000);
|
||||||
|
|
||||||
|
describe('Data tests', function() {
|
||||||
|
it('Can get text body', async function() {
|
||||||
|
res = await fetch(TEXT_BODY_URL);
|
||||||
|
body = await res.text();
|
||||||
|
assert.strictEqual(body, TEXT_BODY_EXPECTED);
|
||||||
|
|
||||||
|
res = await fetch(TEXT_BODY_URL);
|
||||||
|
body = await res.text();
|
||||||
|
assert.strictEqual(body, TEXT_BODY_EXPECTED);
|
||||||
|
});
|
||||||
|
}).timeout(10000);
|
||||||
|
Reference in New Issue
Block a user