Files
flights_web/tests/eslint/restricted-imports.test.ts
gnezim b4266e4b0f
Deploy / build-and-deploy (push) Failing after 6s
Fix flaky ESLint probe tests: use Node API instead of subprocess
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.
2026-04-15 12:32:59 +03:00

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");
});
});