b4266e4b0f
Deploy / build-and-deploy (push) Failing after 6s
The 10 ESLint boundary and restricted-imports probe tests spawned a fresh eslint subprocess per test (~2.7s each), causing timeout flakes under load. Replaced with ESLint's Node API (single instance reused across all tests in a file) — first test pays ~5s init, subsequent tests ~1.3s each. Added 30s timeout to accommodate the init cost.
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import { afterAll, describe, expect, it, vi } from "vitest";
|
|
|
|
vi.setConfig({ testTimeout: 30_000 });
|
|
import { ESLint } from "eslint";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import crypto from "node:crypto";
|
|
|
|
const ROOT = path.resolve(import.meta.dirname, "../..");
|
|
const eslint = new ESLint({ cwd: ROOT });
|
|
|
|
const probeFiles: string[] = [];
|
|
|
|
function uid(): string {
|
|
return crypto.randomBytes(4).toString("hex");
|
|
}
|
|
|
|
afterAll(() => {
|
|
for (const f of probeFiles) {
|
|
try { fs.unlinkSync(f); } catch { /* ok */ }
|
|
let dir = path.dirname(f);
|
|
const srcDir = path.join(ROOT, "src");
|
|
while (dir.length > srcDir.length) {
|
|
try { fs.rmdirSync(dir); } catch { break; }
|
|
dir = path.dirname(dir);
|
|
}
|
|
}
|
|
});
|
|
|
|
async function lintString(filePath: string, content: string): Promise<string> {
|
|
const absPath = path.join(ROOT, filePath);
|
|
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
fs.writeFileSync(absPath, content, "utf8");
|
|
probeFiles.push(absPath);
|
|
|
|
const results = await eslint.lintFiles([absPath]);
|
|
const messages = results.flatMap((r) => r.messages);
|
|
|
|
if (messages.length === 0) return "PASS";
|
|
return JSON.stringify(messages.map((m) => ({ ruleId: m.ruleId, message: m.message })));
|
|
}
|
|
|
|
describe("no-restricted-imports rules", () => {
|
|
it("blocks @opentelemetry/sdk-metrics outside otel.ts", async () => {
|
|
const id = uid();
|
|
const result = await lintString(
|
|
`src/features/online-board/__ri_probe_${id}__.ts`,
|
|
'import { MeterProvider } from "@opentelemetry/sdk-metrics";\nexport const x = MeterProvider;\n',
|
|
);
|
|
expect(result).toContain("no-restricted-imports");
|
|
});
|
|
|
|
it("blocks react-i18next outside provider.tsx", async () => {
|
|
const id = uid();
|
|
const result = await lintString(
|
|
`src/features/online-board/__ri_probe_${id}__.ts`,
|
|
'import { useTranslation } from "react-i18next";\nexport const x = useTranslation;\n',
|
|
);
|
|
expect(result).toContain("no-restricted-imports");
|
|
});
|
|
|
|
it("blocks @microsoft/signalr in routes/ (SSR bundle)", async () => {
|
|
const id = uid();
|
|
const result = await lintString(
|
|
`src/routes/__probe_${id}__/__ri_probe__.ts`,
|
|
'import { HubConnectionBuilder } from "@microsoft/signalr";\nexport const x = HubConnectionBuilder;\n',
|
|
);
|
|
expect(result).toContain("no-restricted-imports");
|
|
});
|
|
|
|
it("blocks localStorage outside storage.ts", async () => {
|
|
const id = uid();
|
|
const result = await lintString(
|
|
`src/features/online-board/__ri_probe_${id}__.ts`,
|
|
'const x = localStorage.getItem("key");\nexport default x;\n',
|
|
);
|
|
expect(result).toContain("no-restricted-globals");
|
|
});
|
|
});
|