aboutsummaryrefslogtreecommitdiff
path: root/test/deep-research
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
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')
-rw-r--r--test/deep-research/agent-config-test.ts72
-rw-r--r--test/deep-research/readability-test.ts91
-rw-r--r--test/deep-research/serp-parser-test.ts97
3 files changed, 150 insertions, 110 deletions
diff --git a/test/deep-research/agent-config-test.ts b/test/deep-research/agent-config-test.ts
index 0e9dfe4..5859060 100644
--- a/test/deep-research/agent-config-test.ts
+++ b/test/deep-research/agent-config-test.ts
@@ -5,38 +5,48 @@
* non-existent web_search / web_fetch tools. Pure string checks over the
* markdown file — no browser, no subagent runtime.
*
- * Run: npx tsx test/deep-research/agent-config-test.ts
+ * Run: npm test
*/
+import { test, before, describe } from "node:test";
+import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { join } from "node:path";
-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 agentPath = join(import.meta.dirname, "..", "..", ".pi", "agents", "web-search-researcher.md");
-const raw = readFileSync(agentPath, "utf8");
-
-const fmMatch = raw.match(/^---\n([\s\S]*?)\n---/);
-const frontmatter = fmMatch ? (fmMatch[1] ?? "") : "";
-const body = fmMatch ? raw.slice(fmMatch[0].length) : raw;
-const toolsLine = frontmatter.split("\n").find((l) => l.startsWith("tools:")) ?? "";
-
-// S20
-check(toolsLine.includes("browser_web_search"), "S20: tools includes browser_web_search");
-check(toolsLine.includes("browser_read_page"), "S20: tools includes browser_read_page");
-check(!/\bweb_search\b/.test(toolsLine), "S20: tools does NOT include web_search");
-check(!/\bweb_fetch\b/.test(toolsLine), "S20: tools does NOT include web_fetch");
-check(/^\s*isolated:\s*true\s*$/m.test(frontmatter), "S20: isolated: true is present");
-check(!/WebSearch|WebFetch/.test(body), "S20: body has no WebSearch/WebFetch references");
-
-console.log(`\n${passed} passed, ${failed} failed`);
-if (failed > 0) process.exit(1);
+describe("web-search-researcher subagent config references only real tools", () => {
+ let frontmatter: string;
+ let body: string;
+ let toolsLine: string;
+
+ before(() => {
+ const agentPath = join(import.meta.dirname, "..", "..", ".pi", "agents", "web-search-researcher.md");
+ const raw = readFileSync(agentPath, "utf8");
+ const fmMatch = raw.match(/^---\n([\s\S]*?)\n---/);
+ frontmatter = fmMatch ? (fmMatch[1] ?? "") : "";
+ body = fmMatch ? raw.slice(fmMatch[0].length) : raw;
+ toolsLine = frontmatter.split("\n").find((l) => l.startsWith("tools:")) ?? "";
+ });
+
+ test("S20: tools includes browser_web_search", () => {
+ assert.ok(toolsLine.includes("browser_web_search"));
+ });
+
+ test("S20: tools includes browser_read_page", () => {
+ assert.ok(toolsLine.includes("browser_read_page"));
+ });
+
+ test("S20: tools does NOT include web_search", () => {
+ assert.ok(!/\bweb_search\b/.test(toolsLine));
+ });
+
+ test("S20: tools does NOT include web_fetch", () => {
+ assert.ok(!/\bweb_fetch\b/.test(toolsLine));
+ });
+
+ test("S20: isolated: true is present", () => {
+ assert.ok(/^\s*isolated:\s*true\s*$/m.test(frontmatter));
+ });
+
+ test("S20: body has no WebSearch/WebFetch references", () => {
+ assert.ok(!/WebSearch|WebFetch/.test(body));
+ });
+});
diff --git a/test/deep-research/readability-test.ts b/test/deep-research/readability-test.ts
index 10f9a8b..ba0e0e0 100644
--- a/test/deep-research/readability-test.ts
+++ b/test/deep-research/readability-test.ts
@@ -1,46 +1,67 @@
/**
* Unit tests for the pure readability extractor — no browser required.
*
- * Run: npx tsx test/deep-research/readability-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 { extractReadable, type PageCapture } from "../../src/domains/readpage/readability";
-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): PageCapture =>
JSON.parse(readFileSync(join(import.meta.dirname, "fixtures", name), "utf8")) as PageCapture;
-// S10: boilerplate stripped, article content preserved
-{
- const page = extractReadable(fixture("article-capture.json"));
- check(page.text.includes("Chrome DevTools Protocol lets tools instrument"), "S10: article body text is present");
- check(page.text.includes("Sessions and Targets"), "S10: article headings are preserved");
- check(!page.text.includes("Home Products Blog"), "S10: nav boilerplate is dropped");
- check(!page.text.includes("Copyright 2026"), "S10: footer boilerplate is dropped");
- check(!page.text.includes("Subscribe here for our newsletter"), "S10: high-link-density promo block is dropped");
- check(page.text.includes("## Sessions and Targets"), "S10: paragraph/heading structure preserved as markdown");
- check(page.title === "How the Chrome DevTools Protocol Works" && page.url.startsWith("https://"), "S10: title and url passed through");
- check(page.wordCount > 40, "S10: word count reflects the article body");
-}
-
-// S11: no clear article node falls back to bounded body text
-{
- const page = extractReadable(fixture("no-article-capture.json"));
- check(page.text.length > 0, "S11: structure-less page falls back to non-empty body text");
- check(page.text.includes("Your account is active"), "S11: fallback body text carries the real content");
-}
-
-console.log(`\n${passed} passed, ${failed} failed`);
-if (failed > 0) process.exit(1);
+describe("pure readability extractor", () => {
+ // S10: boilerplate stripped, article content preserved
+ test("S10: article body text is present", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(page.text.includes("Chrome DevTools Protocol lets tools instrument"));
+ });
+
+ test("S10: article headings are preserved", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(page.text.includes("Sessions and Targets"));
+ });
+
+ test("S10: nav boilerplate is dropped", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(!page.text.includes("Home Products Blog"));
+ });
+
+ test("S10: footer boilerplate is dropped", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(!page.text.includes("Copyright 2026"));
+ });
+
+ test("S10: high-link-density promo block is dropped", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(!page.text.includes("Subscribe here for our newsletter"));
+ });
+
+ test("S10: paragraph/heading structure preserved as markdown", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(page.text.includes("## Sessions and Targets"));
+ });
+
+ test("S10: title and url passed through", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(page.title === "How the Chrome DevTools Protocol Works" && page.url.startsWith("https://"));
+ });
+
+ test("S10: word count reflects the article body", () => {
+ const page = extractReadable(fixture("article-capture.json"));
+ assert.ok(page.wordCount > 40);
+ });
+
+ // S11: no clear article node falls back to bounded body text
+ test("S11: structure-less page falls back to non-empty body text", () => {
+ const page = extractReadable(fixture("no-article-capture.json"));
+ assert.ok(page.text.length > 0);
+ });
+
+ test("S11: fallback body text carries the real content", () => {
+ const page = extractReadable(fixture("no-article-capture.json"));
+ assert.ok(page.text.includes("Your account is active"));
+ });
+});
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");
+ });
+});