aboutsummaryrefslogtreecommitdiff
path: root/test/deep-research/serp-parser-test.ts
diff options
context:
space:
mode:
authoramankumarsingh77 <amankumarsingh7702@gmail.com>2026-07-27 00:27:08 +0530
committerAman Kumar <145339995+amankumarsingh77@users.noreply.github.com>2026-08-02 19:12:46 +0530
commit15a537a99efba614e6e108722462bcb78ec6c3c4 (patch)
tree2ff20907fee8ace7a071470d491fe7808dce6a63 /test/deep-research/serp-parser-test.ts
parentce5d808cb4cc3581d85b829656d1d478dc43e3a6 (diff)
test: port remaining suites to node:test
Mechanical port of the hand-rolled check() harness. Import-after-env ordering preserved so suites still read their sandbox dirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'test/deep-research/serp-parser-test.ts')
-rw-r--r--test/deep-research/serp-parser-test.ts97
1 files changed, 53 insertions, 44 deletions
diff --git a/test/deep-research/serp-parser-test.ts b/test/deep-research/serp-parser-test.ts
index dabd72b..af5ac54 100644
--- a/test/deep-research/serp-parser-test.ts
+++ b/test/deep-research/serp-parser-test.ts
@@ -1,24 +1,14 @@
/**
* Unit tests for the pure Google SERP parser — no browser required.
*
- * Run: npx tsx test/deep-research/serp-parser-test.ts
+ * Run: npm test
*/
+import { test, describe } from "node:test";
+import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { classifySerp, parseGoogleSerp, type SerpExtraction } from "../../src/domains/search/google-serp";
-let passed = 0;
-let failed = 0;
-const check = (cond: boolean, label: string): void => {
- if (cond) {
- passed++;
- console.log(` ✓ ${label}`);
- } else {
- failed++;
- console.error(` ✗ ${label}`);
- }
-};
-
const fixture = (name: string): SerpExtraction =>
JSON.parse(readFileSync(join(import.meta.dirname, "fixtures", name), "utf8")) as SerpExtraction;
@@ -26,34 +16,53 @@ const ok = fixture("google-serp-ok.json");
const captcha = fixture("google-serp-captcha.json");
const empty = fixture("google-serp-empty.json");
-// S1: redirect unwrapping + internal/javascript anchors dropped
-{
- const results = parseGoogleSerp(ok.anchors, 10);
- const urls = results.map((r) => r.url);
- check(urls.includes("https://real.example/x"), "S1: /url?q= redirect is unwrapped to the real target");
- check(!urls.some((u) => u.includes("google.com")), "S1: google-internal anchors are dropped");
- check(!urls.some((u) => u.startsWith("javascript:")), "S1: javascript: anchors are dropped");
-}
-
-// S2: dedupe + rank + limit
-{
- const results = parseGoogleSerp(ok.anchors, 10);
- const realExampleCount = results.filter((r) => r.url.startsWith("https://real.example/x")).length;
- check(realExampleCount === 1, "S2: trailing-slash duplicate collapses to one result");
- check(
- results.every((r, i) => r.rank === i + 1),
- "S2: rank runs 1..n in input order",
- );
- const capped = parseGoogleSerp(ok.anchors, 2);
- check(capped.length === 2 && capped[capped.length - 1]?.rank === 2, "S2: limit truncates and ranks stay 1..limit");
-}
-
-// S3: CAPTCHA / no-results classification
-{
- check(classifySerp(ok.pageText, parseGoogleSerp(ok.anchors, 10).length) === "ok", "S3: populated SERP classifies as ok");
- check(classifySerp(captcha.pageText, 0) === "captcha", "S3: captcha page classifies as captcha");
- check(classifySerp(empty.pageText, 0) === "no_results", "S3: empty results classify as no_results");
-}
-
-console.log(`\n${passed} passed, ${failed} failed`);
-if (failed > 0) process.exit(1);
+describe("pure Google SERP parser", () => {
+ // S1: redirect unwrapping + internal/javascript anchors dropped
+ test("S1: /url?q= redirect is unwrapped to the real target", () => {
+ const results = parseGoogleSerp(ok.anchors, 10);
+ const urls = results.map((r) => r.url);
+ assert.ok(urls.includes("https://real.example/x"));
+ });
+
+ test("S1: google-internal anchors are dropped", () => {
+ const results = parseGoogleSerp(ok.anchors, 10);
+ const urls = results.map((r) => r.url);
+ assert.ok(!urls.some((u) => u.includes("google.com")));
+ });
+
+ test("S1: javascript: anchors are dropped", () => {
+ const results = parseGoogleSerp(ok.anchors, 10);
+ const urls = results.map((r) => r.url);
+ assert.ok(!urls.some((u) => u.startsWith("javascript:")));
+ });
+
+ // S2: dedupe + rank + limit
+ test("S2: trailing-slash duplicate collapses to one result", () => {
+ const results = parseGoogleSerp(ok.anchors, 10);
+ const realExampleCount = results.filter((r) => r.url.startsWith("https://real.example/x")).length;
+ assert.equal(realExampleCount, 1);
+ });
+
+ test("S2: rank runs 1..n in input order", () => {
+ const results = parseGoogleSerp(ok.anchors, 10);
+ assert.ok(results.every((r, i) => r.rank === i + 1));
+ });
+
+ test("S2: limit truncates and ranks stay 1..limit", () => {
+ const capped = parseGoogleSerp(ok.anchors, 2);
+ assert.ok(capped.length === 2 && capped[capped.length - 1]?.rank === 2);
+ });
+
+ // S3: CAPTCHA / no-results classification
+ test("S3: populated SERP classifies as ok", () => {
+ assert.equal(classifySerp(ok.pageText, parseGoogleSerp(ok.anchors, 10).length), "ok");
+ });
+
+ test("S3: captcha page classifies as captcha", () => {
+ assert.equal(classifySerp(captcha.pageText, 0), "captcha");
+ });
+
+ test("S3: empty results classify as no_results", () => {
+ assert.equal(classifySerp(empty.pageText, 0), "no_results");
+ });
+});