corepack/tests/recordRequests.js

87 lines
2.4 KiB
JavaScript

"use strict";
const path = require(`node:path`);
const crypto = require(`node:crypto`);
const SQLite3 = require(`better-sqlite3`);
const db = new SQLite3(path.join(__dirname, `nocks.db`));
process.once(`exit`, () => {
db.close();
});
db.exec(`CREATE TABLE IF NOT EXISTS nocks (
hash BLOB PRIMARY KEY NOT NULL,
body BLOB NOT NULL,
headers BLOB NOT NULL,
status INTEGER NOT NULL
)`);
/**
* @param {string | URL} input
* @param {RequestInit | undefined} init
*/
function getRequestHash(input, init) {
const hash = crypto.createHash(`sha256`);
hash.update(`${input}\0`);
if (init) {
for (const key in init) {
if (init[key] === undefined) continue;
switch (key) {
case `headers`:
hash.update(`${JSON.stringify(Object.fromEntries(new Headers(init.headers || {})))}\0`);
break;
default:
throw new Error(`Hashing for "${key}" not implemented`);
}
}
}
return hash.digest();
}
if (process.env.NOCK_ENV === `record`) {
const insertNockStatement = db.prepare(`INSERT OR REPLACE INTO nocks (hash, body, headers, status) VALUES (?, ?, jsonb(?), ?)`);
const realFetch = globalThis.fetch;
globalThis.fetch = async (input, init) => {
const response = await realFetch(input, init);
const data = await response.arrayBuffer();
const minimalHeaders = new Headers();
for (const headerName of [`content-type`, `content-length`]) {
const headerValue = response.headers.get(headerName);
if (headerValue != null) {
minimalHeaders.set(headerName, headerValue);
}
}
const requestHash = getRequestHash(input, init);
insertNockStatement.run(
requestHash,
Buffer.from(data),
JSON.stringify(Object.fromEntries(minimalHeaders)),
response.status,
);
return new Response(data, {
status: response.status,
headers: minimalHeaders,
});
};
} else if (process.env.NOCK_ENV === `replay`) {
const getNockStatement = db.prepare(`SELECT body, json(headers) as headers, status FROM nocks WHERE hash = ?`);
globalThis.fetch = async (input, init) => {
const requestHash = getRequestHash(input, init);
const mock = getNockStatement.get(requestHash);
if (!mock) throw new Error(`No mock found for ${input}; run the tests with NOCK_ENV=record to generate one`);
return new Response(mock.body, {
status: mock.status,
headers: JSON.parse(mock.headers),
});
};
}