Skip to content

Commit dbf1d3a

Browse files
test(search): add DB-gated smoke test for /search regression guard
Complements the hermetic vitest unit tests (lib/data/search.test.ts) with a live-DB regression guard gated on $DATABASE_URL. Asserts the specific bugs flagged in Morgan's Relay report: - /search?q=tri-state must return Tri-State G&T (ALL-731 bug #3) - /search?q=duke%20energy must return Duke Energy utilities - /search?q=demand%20response must return Demand Response programs - /search?q=pjm&types=isos must return PJM Interconnection - broad queries fan out across buckets (utility + transmission-line) - per-type limit is respected - empty/whitespace query returns [] Skips cleanly on local machines without DATABASE_URL so `npm test` stays hermetic and fast. When DATABASE_URL is provisioned in CI, this test file becomes the last line of defense before a silent `/search` regression ships.
1 parent d3ac2d6 commit dbf1d3a

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

lib/data/search.smoke.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* DB-backed smoke test for the global /search dispatcher.
3+
*
4+
* Regression guard for ALL-731 (Relay bug #3). If `/search?q=tri-state`
5+
* stops returning Tri-State G&T, this test fires in CI (when a DB URL is
6+
* provisioned) and blocks the merge.
7+
*
8+
* Gated on `process.env.DATABASE_URL`. Local runs without a DB skip cleanly.
9+
* To run locally:
10+
*
11+
* export DATABASE_URL=... # Neon connection string from 1Password
12+
* npm test -- search.smoke
13+
*/
14+
15+
import { describe, expect, it } from "vitest";
16+
17+
import { searchAll } from "./search";
18+
19+
const runIfDb = process.env.DATABASE_URL ? describe : describe.skip;
20+
21+
runIfDb("search — live DB smoke", () => {
22+
it("finds Tri-State G&T by query 'tri-state'", async () => {
23+
const { results } = await searchAll("tri-state", { types: ["utilities"], limit: 5 });
24+
const utilities = results.get("utility") ?? [];
25+
expect(utilities.length).toBeGreaterThan(0);
26+
27+
const slugs = utilities.map((u) => u.slug);
28+
expect(slugs).toContain("tri-state-gandt-assn-inc");
29+
}, 15_000);
30+
31+
it("finds at least one utility for 'duke energy'", async () => {
32+
const { results } = await searchAll("duke energy", { types: ["utilities"], limit: 5 });
33+
const utilities = results.get("utility") ?? [];
34+
expect(utilities.length).toBeGreaterThan(0);
35+
expect(utilities.some((u) => /duke/i.test(u.name))).toBe(true);
36+
}, 15_000);
37+
38+
it("finds programs for 'demand response'", async () => {
39+
const { results } = await searchAll("demand response", { types: ["programs"], limit: 5 });
40+
const programs = results.get("program") ?? [];
41+
expect(programs.length).toBeGreaterThan(0);
42+
expect(programs.some((p) => /demand/i.test(p.name))).toBe(true);
43+
}, 15_000);
44+
45+
it("finds PJM in the isos bucket", async () => {
46+
const { results } = await searchAll("pjm", { types: ["isos"], limit: 5 });
47+
const isos = results.get("iso") ?? [];
48+
expect(isos.length).toBeGreaterThan(0);
49+
expect(isos.some((i) => /pjm/i.test(i.name))).toBe(true);
50+
}, 15_000);
51+
52+
it("returns results across multiple buckets for a broad query", async () => {
53+
const { results, source } = await searchAll("tri-state", { limit: 3 });
54+
expect(source).toBe("db");
55+
56+
// At minimum utilities + transmission-lines should hit for 'tri-state'.
57+
const utilities = results.get("utility") ?? [];
58+
const transmissionLines = results.get("transmission-line") ?? [];
59+
expect(utilities.length).toBeGreaterThan(0);
60+
expect(transmissionLines.length).toBeGreaterThan(0);
61+
}, 30_000);
62+
63+
it("respects the per-type limit", async () => {
64+
const { results } = await searchAll("energy", { types: ["utilities"], limit: 3 });
65+
const utilities = results.get("utility") ?? [];
66+
expect(utilities.length).toBeLessThanOrEqual(3);
67+
}, 15_000);
68+
69+
it("returns empty for an empty/whitespace query", async () => {
70+
const { results } = await searchAll(" ", { types: ["utilities"], limit: 3 });
71+
expect(results.get("utility")).toEqual([]);
72+
}, 15_000);
73+
});

0 commit comments

Comments
 (0)