spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import { describe, expect, it } from "vitest";2import { intervalMs, parseConnectorConfig, validateAgainstRegistry } from "./config.js";3import { registerParser } from "./registry.js";45const BASE = `id: t\nname: T\ndomain: x.com\nkind: operator\n`;67describe("connector config cross-field validation", () => {8 it("rejects level > maxLevel", () => {9 expect(() => parseConnectorConfig(`${BASE}fetch: { level: 3, maxLevel: 2 }`)).toThrow(/fetch.level 3 exceeds fetch.maxLevel 2/);10 });11 it("rejects a per-run credit budget above the daily one on premium connectors", () => {12 expect(() => parseConnectorConfig(`${BASE}fetch: { maxLevel: 4, maxCreditsPerRun: 200, maxCreditsPerDay: 60 }`)).toThrow(/maxCreditsPerRun 200 exceeds fetch.maxCreditsPerDay 60/);13 expect(() => parseConnectorConfig(`${BASE}fetch: { maxLevel: 2, maxCreditsPerRun: 200, maxCreditsPerDay: 0 }`)).not.toThrow();14 });15 it("compiles every discovery / extractor regex at parse time", () => {16 expect(() => parseConnectorConfig(`${BASE}discovery: { include: ["/ok/", "(unclosed"] }`)).toThrow(/discovery.include.1: invalid regex/);17 expect(() => parseConnectorConfig(`${BASE}discovery: { classify: [{ pattern: "[a-", group: g }] }`)).toThrow(/classify.0.pattern/);18 expect(() => parseConnectorConfig(`${BASE}extractors: { f: { parser: p, match: ["*bad"] } }`)).toThrow(/extractors.f.match.0/);19 expect(() => parseConnectorConfig(`${BASE}extractors: { f: { fields: { name: { selector: h1, regex: "(" } } } }`)).toThrow(/fields.name.regex/);20 });21 it("rejects seeds / classify rules whose minLevel exceeds maxLevel and extractors without parser or fields", () => {22 expect(() => parseConnectorConfig(`${BASE}fetch: { maxLevel: 2 }\ndiscovery: { seeds: [{ url: /a, minLevel: 4 }] }`)).toThrow(/minLevel 4 exceeds/);23 expect(() => parseConnectorConfig(`${BASE}extractors: { f: { kind: facility } }`)).toThrow(/needs either/);24 });25 it("rejects bad schedule intervals and accepts the documented forms", () => {26 expect(() => parseConnectorConfig(`${BASE}schedule: { newsroom: soonish }`)).toThrow(/bad interval "soonish"/);27 const cfg = parseConnectorConfig(`${BASE}schedule: { a: daily, b: 6h, c: 30m, d: never, e: quarterly }`);28 expect(cfg.schedule.d).toBe("never");29 expect(intervalMs("6h")).toBe(6 * 3_600_000);30 expect(intervalMs("never")).toBe(Number.POSITIVE_INFINITY);31 expect(() => intervalMs("2y")).toThrow(/bad interval/);32 });33 it("applies defaults", () => {34 const cfg = parseConnectorConfig(BASE);35 expect(cfg.fetch).toMatchObject({ level: 1, maxLevel: 2, rpm: 30, respectRobots: true, maxCreditsPerRun: 200 });36 expect(cfg.schedule).toEqual({ seed: "weekly" });37 });38});3940describe("validateAgainstRegistry", () => {41 it("is a no-op while nothing is registered, then reports unknown parsers / implementations", () => {42 const cfg = parseConnectorConfig(`${BASE}extractors: { f: { parser: nope_v1 } }`);43 expect(validateAgainstRegistry(cfg)).toEqual([]);44 registerParser({ name: "known_v1", version: "1", parse: () => [] });45 expect(validateAgainstRegistry(cfg)).toEqual(['extractors.f.parser "nope_v1" is not registered']);46 expect(validateAgainstRegistry(parseConnectorConfig(`${BASE}extractors: { f: { parser: known_v1 } }`))).toEqual([]);47 expect(validateAgainstRegistry(parseConnectorConfig(`${BASE}implementation: ghost`))).toEqual(['implementation "ghost" is not registered']);48 });49});50