import { describe, expect, it } from "vitest"; import { eslint } from "./lintProbe.testkit"; // "Every request is logged" lives in eslint.config.js, not prose: `fetch`, `XMLHttpRequest` // and `WebSocket` each belong to ONE module that logs them, and `console` to none. A restriction // that matches nothing looks exactly like a clean codebase, so this asserts the rules FIRE — and // that each owner is exempt from its own global only. const RULES = new Set(["no-restricted-globals", "no-restricted-properties", "no-console"]); async function flagged(source: string, filePath: string): Promise { const [result] = await eslint.lintText(source, { filePath }); return (result?.messages ?? []) .filter((m) => m.ruleId && RULES.has(m.ruleId)) .map((m) => `${m.ruleId}: ${m.message}`); } const ALL = [ `export const a = () => fetch("/x");`, `export const b = () => new XMLHttpRequest();`, `export const c = () => new WebSocket("wss://x");`, `export const d = () => window.fetch("/x");`, `export const e = () => navigator.sendBeacon("/x");`, `export const f = () => console.log("x");`, ].join("\n"); describe("network and console boundary", () => { it("refuses every way out of the browser, and console, in an ordinary module", async () => { const found = await flagged(ALL, "src/components/__network_probe.tsx"); expect(found).toHaveLength(6); expect(found.filter((f) => f.startsWith("no-console"))).toHaveLength(1); }); it.each([ ["src/lib/http.ts", "fetch"], ["src/lib/api/core.ts", "XMLHttpRequest"], ])("%s may use %s — and nothing else", async (owner, own) => { const found = await flagged(ALL, owner); // Its own global goes quiet; the other two globals, the two properties and console still fire. expect(found).toHaveLength(5); expect(found.some((f) => f.includes(`\`${own}\``))).toBe(false); }); });