import { describe, expect, it } from "vitest"; import type { NormalizedFacility, NormalizedProject } from "@dci/core"; import { fallbackProjectGate, NON_PROJECT_HEADLINE_RE, TITLE_LIKE_NAME_RE, trimSummary, validateEntities, THIRD_PARTY_SUMMARY_MAX } from "./generic.js"; const prov = { sourceId: "s", connectorId: "c", url: "https://x.com/f", firstObserved: "2026-09-01", lastObserved: "2026-09-01", retrievedAt: "2026-09-01", confidence: "high" as const, extractorVersion: "v1" }; function facility(p: Partial): NormalizedFacility { return { entityType: "facility", key: "c:f", name: "DC One", aliases: [], operatorName: "Op", campusName: null, address: null, city: "Ashburn", regionName: null, countryIso2: "US", postalCode: null, geo: null, status: "operational", facilityType: "colocation", tier: null, buildingSqm: null, siteAreaHa: null, itCapacityMw: null, totalPowerMw: null, plannedPowerMw: null, rackCount: null, pue: null, coolingType: null, renewableClaim: null, openedOn: null, constructionStartedOn: null, announcedOn: null, website: null, isAi: null, isHyperscale: null, certifications: [], carriers: [], cloudProviders: [], ixps: [], externalIds: {}, description: null, provenance: prov, ...p }; } const errors = (r: ReturnType) => r.issues.filter((i) => i.level === "error").map((i) => i.field); describe("validateEntities — facilities", () => { it("accepts a plain facility and a sub-MW decimal capacity", () => { const r = validateEntities([facility({ itCapacityMw: 0.779 })]); expect(r).toMatchObject({ total: 1, valid: 1, rejected: 0 }); }); it("rejects title-like and non-facility names", () => { expect(errors(validateEntities([facility({ name: "Data Centers in Virginia | Acme" })]))).toContain("name"); expect(errors(validateEntities([facility({ name: "Our Locations" })]))).toContain("name"); expect(errors(validateEntities([facility({ name: "How we build data centers" })]))).toContain("name"); expect(errors(validateEntities([facility({ name: "Joe's Computer Repair Shop" })]))).toContain("name"); expect(TITLE_LIKE_NAME_RE.test("Ashburn VA1")).toBe(false); expect(TITLE_LIKE_NAME_RE.test("Frankfurt FRA5 Data Center")).toBe(false); }); it("rejects > 1 000 MW on a single building unless it is a campus", () => { expect(errors(validateEntities([facility({ itCapacityMw: 1200 })]))).toContain("itCapacityMw"); expect(validateEntities([facility({ name: "Prince William Digital Gateway Campus", totalPowerMw: 1200 })]).rejected).toBe(0); expect(validateEntities([facility({ campusName: "Mesa Campus", itCapacityMw: 1500 })]).rejected).toBe(0); expect(errors(validateEntities([facility({ itCapacityMw: 20_000 })]))).toContain("itCapacityMw"); // > 10 000 always implausible }); it("rejects impossible figures and coordinates", () => { expect(errors(validateEntities([facility({ pue: 0.8 })]))).toContain("pue"); expect(errors(validateEntities([facility({ geo: { lat: 39, lng: -77, precision: "exact", source: "x" } })]))).toContain("geo"); expect(errors(validateEntities([facility({ geo: { lat: 99, lng: 0, precision: "city", source: "x" } })]))).toContain("geo"); expect(errors(validateEntities([facility({ buildingSqm: 600_000 })]))).toContain("buildingSqm"); expect(errors(validateEntities([facility({ openedOn: "1930" })]))).toContain("openedOn"); expect(errors(validateEntities([facility({ countryIso2: "USA" })]))).toContain("countryIso2"); }); it("warns without rejecting", () => { const r = validateEntities([facility({ countryIso2: null, itCapacityMw: 10, totalPowerMw: 8 })]); expect(r.rejected).toBe(0); expect(r.issues.map((i) => i.field)).toEqual(expect.arrayContaining(["countryIso2", "itCapacityMw"])); }); }); describe("validateEntities — projects, regions, news", () => { const project: NormalizedProject = { entityType: "project", key: "c:p", name: "Acme Ohio campus", operatorName: "Acme", countryIso2: "US", status: "announced", announcedOn: "2026-09", plannedMw: 300, investmentUsd: 2e9, description: null, sourceUrl: "https://x.com/n", timeline: [], provenance: prov }; it("bounds MW and investment", () => { expect(validateEntities([project]).rejected).toBe(0); expect(errors(validateEntities([{ ...project, plannedMw: 25_000 }]))).toContain("plannedMw"); expect(errors(validateEntities([{ ...project, investmentUsd: 250e9 }]))).toContain("investmentUsd"); expect(errors(validateEntities([{ ...project, expectedOpening: "2060" }]))).toContain("expectedOpening"); }); it("news events need a real url and title; cloud regions need code+name", () => { expect(validateEntities([{ entityType: "news_event", key: "n", title: "", url: "ftp://x", publishedAt: null, summary: null, pageType: "press_release", mentions: { mw: [], operators: [], countriesIso2: [], cities: [] }, provenance: prov }]).rejected).toBe(1); expect(validateEntities([{ entityType: "cloud_region", key: "r", providerName: "P", code: "", name: "N", city: null, regionName: null, countryIso2: null, geo: null, availabilityZones: null, launchedOn: null, status: "operational", isSovereign: false, sourceUrl: "https://x", provenance: prov }]).rejected).toBe(1); }); }); describe("fallbackProjectGate", () => { it("accepts a build headline with MW + pipeline status", () => { expect(fallbackProjectGate("Acme to build 120 MW data center campus in Ohio", null)).toEqual({ mw: 120, status: "announced" }); expect(fallbackProjectGate("Acme breaks ground on new hyperscale campus", "The 90MW first phase is due in 2027.")).toEqual({ mw: 90, status: "under_construction" }); }); it("rejects people / deal / opening / money headlines even with MW in them", () => { expect(fallbackProjectGate("Acme appoints Jane Doe as CEO of its 1,400 MW platform", null)).toBeNull(); expect(fallbackProjectGate("Acme opens 20 MW data center in Paris", null)).toBeNull(); expect(fallbackProjectGate("Acme signs 50 MW PPA with wind farm", null)).toBeNull(); expect(fallbackProjectGate("Acme raises $500m to build 100 MW campus", null)).toBeNull(); expect(NON_PROJECT_HEADLINE_RE.test("Why data centers matter")).toBe(true); }); it("needs a MW figure somewhere up front and a plausible value", () => { expect(fallbackProjectGate("Acme plans new campus in Texas", "Details to follow.")).toBeNull(); expect(fallbackProjectGate("Acme plans 50,000 MW campus", null)).toBeNull(); }); }); describe("trimSummary", () => { it("cuts at a word boundary with an ellipsis, never above the cap", () => { const long = Array.from({ length: 120 }, (_, i) => `word${i}`).join(" "); const t = trimSummary(long)!; expect(t.length).toBeLessThanOrEqual(THIRD_PARTY_SUMMARY_MAX); expect(t.endsWith("…")).toBe(true); // the kept text is a prefix of the original and the cut falls on a word boundary (next original char is a space) const kept = t.slice(0, -1); expect(long.startsWith(kept)).toBe(true); expect(long[kept.length]).toBe(" "); expect(trimSummary("short")).toBe("short"); expect(trimSummary(null)).toBeNull(); expect(trimSummary("abcdef", 4)!.length).toBeLessThanOrEqual(4); expect(trimSummary("abcdef", 4)!.endsWith("…")).toBe(true); }); });