diff options
| author | amankumarsingh77 <amankumarsingh7702@gmail.com> | 2026-07-08 21:24:32 +0530 |
|---|---|---|
| committer | amankumarsingh77 <amankumarsingh7702@gmail.com> | 2026-07-08 21:24:32 +0530 |
| commit | 68bf7fd2988e42343833be09e4115cd7175029d0 (patch) | |
| tree | 52b8eaf99fa7e4d383ff169dd3bdccfe13911217 /test/deep-research/readability-test.ts | |
| parent | c5c42df5976ed63faac2adcf3b04a4ad2f519b32 (diff) | |
feat: add browser_read_page reader-mode tool
URL (or owned targetId) → clean main-article text with nav/ads/footer
boilerplate stripped, via a dependency-free readability heuristic. DOM walk
lives in an in-page capture expression; scoring/selection is a pure, fixture-
tested function (link-density + boilerplate-ancestor filtering, body-text
fallback for structure-less pages). Reuses the isolated-attach lifecycle;
registered unserialized (safe concurrent read). 10 extractor unit scenarios.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'test/deep-research/readability-test.ts')
| -rw-r--r-- | test/deep-research/readability-test.ts | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/test/deep-research/readability-test.ts b/test/deep-research/readability-test.ts new file mode 100644 index 0000000..10f9a8b --- /dev/null +++ b/test/deep-research/readability-test.ts @@ -0,0 +1,46 @@ +/** + * Unit tests for the pure readability extractor — no browser required. + * + * Run: npx tsx test/deep-research/readability-test.ts + */ +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); |
