mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
test(producer): unit tests never reach the network (#5135)
* test(producer): unit tests never reach the network * test(producer): the unit lane refuses sockets to other hosts, not only fetch * test(producer): refuse outside hosts at the lookup, not by parsing socket calls * test(producer): keep dns.lookup promisify-compatible under the no-network guard
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import dns from "node:dns";
|
||||
|
||||
// Unit tests run offline: fetch throws, and a lookup of any host but this machine fails, which also covers a test
|
||||
// environment's own fetch (happy-dom's) and node:http. A test that needs a response stubs fetch itself.
|
||||
const LOCAL = new Set(["localhost"]);
|
||||
const refusal = (target) => new TypeError(`No network in unit tests: ${target}`);
|
||||
|
||||
globalThis.fetch = async (input) => {
|
||||
throw refusal(input?.url ?? input);
|
||||
};
|
||||
|
||||
const { lookup } = dns;
|
||||
const guarded = (host, ...rest) =>
|
||||
LOCAL.has(host) ? lookup(host, ...rest) : process.nextTick(rest.at(-1), refusal(host));
|
||||
// Keeps the original's own properties, among them what util.promisify reads to resolve { address, family }.
|
||||
dns.lookup = Object.defineProperties(guarded, Object.getOwnPropertyDescriptors(lookup));
|
||||
@@ -1,4 +1,5 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { discoverProducerTests, PRODUCER_ROOT } from "./test-classification.mjs";
|
||||
|
||||
const lane = process.argv[2];
|
||||
@@ -14,10 +15,13 @@ const tests = discoverProducerTests().filter(
|
||||
(test) => test.lane === lane && (!requestedRunner || test.runner === requestedRunner),
|
||||
);
|
||||
|
||||
function run(args) {
|
||||
const noNetwork = new URL("./no-network.mjs", import.meta.url);
|
||||
const unit = lane === "unit";
|
||||
|
||||
function run(args, env = {}) {
|
||||
const result = spawnSync("bun", args, {
|
||||
cwd: PRODUCER_ROOT,
|
||||
env: { ...process.env, HYPERFRAMES_TEST_LANE: lane },
|
||||
env: { ...process.env, HYPERFRAMES_TEST_LANE: lane, ...env },
|
||||
stdio: "inherit",
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
@@ -25,10 +29,13 @@ function run(args) {
|
||||
}
|
||||
|
||||
const vitestFiles = tests.filter((test) => test.runner === "vitest").map((test) => test.file);
|
||||
if (vitestFiles.length > 0) run(["x", "vitest", "run", ...vitestFiles]);
|
||||
const vitestEnv = unit
|
||||
? { NODE_OPTIONS: `${process.env.NODE_OPTIONS ?? ""} --import ${noNetwork.href}`.trim() }
|
||||
: {};
|
||||
if (vitestFiles.length > 0) run(["x", "vitest", "run", ...vitestFiles], vitestEnv);
|
||||
|
||||
// Bun's mock.module registry is process-global. Run each file in a fresh
|
||||
// process so mocks from one source test cannot mutate another test's imports.
|
||||
for (const test of tests.filter((entry) => entry.runner === "bun")) {
|
||||
run(["test", test.file]);
|
||||
run(["test", ...(unit ? ["--preload", fileURLToPath(noNetwork)] : []), test.file]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { expect, it } from "bun:test";
|
||||
|
||||
// scripts/run-test-lane.mjs preloads scripts/no-network.mjs for the unit lane.
|
||||
it("reaches no network in the unit lane", async () => {
|
||||
await expect(fetch("https://example.com")).rejects.toThrow("No network in unit tests");
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { get } from "node:http";
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
// scripts/run-test-lane.mjs imports scripts/no-network.mjs into the unit lane's vitest workers.
|
||||
it("refuses happy-dom's own fetch in the unit lane", async () => {
|
||||
await expect(fetch("https://example.com")).rejects.toThrow("No network in unit tests");
|
||||
});
|
||||
|
||||
it("refuses a node:http request to another host in the unit lane", async () => {
|
||||
const request = new Promise((resolve, reject) => {
|
||||
get("http://example.com", resolve).on("error", reject);
|
||||
});
|
||||
await expect(request).rejects.toThrow("No network in unit tests");
|
||||
});
|
||||
@@ -1686,7 +1686,7 @@ describe("crossorigin attribute stripping", () => {
|
||||
//
|
||||
// Tests run on localizeRemoteMediaSources directly (exported for testing) to
|
||||
// avoid invoking ffprobe / the full compileForRender pipeline. fetch is patched
|
||||
// in-process for success cases; real 404s from example.com cover fallback.
|
||||
// in-process for success cases; the unit lane's refused network covers fallback.
|
||||
|
||||
describe("localizeRemoteMediaSources", () => {
|
||||
it("rewrites remote <video> src to _remote_media path when download succeeds", async () => {
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
"packages/producer/tests/**/*.test.ts"
|
||||
],
|
||||
"sources": {
|
||||
"packages/producer/scripts/run-test-lane.mjs": "bff02680f19eebcce0df72cdeedbbc05edfdcede3f3f60658fc0cb18ed8c59f6",
|
||||
"packages/producer/scripts/run-test-lane.mjs": "638885e14480d03290803389325a655f3749442167d784e07bb3af3404598af7",
|
||||
"packages/producer/scripts/test-classification.mjs": "ae0cd9e09bf93df932d41649855f86ebb2230b25aabf3e56355fed8f101a0322",
|
||||
".github/workflows/ci.yml#job#producer-source-tests": "45da72aa6cf08cdfd5bcf5311e89f12af4842f9eebc6735df19da8c02f4d4864",
|
||||
"packages/producer/package.json#script#test:unit": "ae6beda8319d166774be958ea5593cd27dbf7f6c9bce1d787a3fe28dfc3477b1",
|
||||
|
||||
Reference in New Issue
Block a user