@debriefer/sources 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +59 -0
  2. package/dist/__tests__/archives/chronicling-america.test.d.ts +8 -0
  3. package/dist/__tests__/archives/chronicling-america.test.d.ts.map +1 -0
  4. package/dist/__tests__/archives/chronicling-america.test.js +151 -0
  5. package/dist/__tests__/archives/chronicling-america.test.js.map +1 -0
  6. package/dist/__tests__/archives/europeana.test.d.ts +8 -0
  7. package/dist/__tests__/archives/europeana.test.d.ts.map +1 -0
  8. package/dist/__tests__/archives/europeana.test.js +200 -0
  9. package/dist/__tests__/archives/europeana.test.js.map +1 -0
  10. package/dist/__tests__/archives/internet-archive.test.d.ts +8 -0
  11. package/dist/__tests__/archives/internet-archive.test.d.ts.map +1 -0
  12. package/dist/__tests__/archives/internet-archive.test.js +189 -0
  13. package/dist/__tests__/archives/internet-archive.test.js.map +1 -0
  14. package/dist/__tests__/archives/trove.test.d.ts +8 -0
  15. package/dist/__tests__/archives/trove.test.d.ts.map +1 -0
  16. package/dist/__tests__/archives/trove.test.js +202 -0
  17. package/dist/__tests__/archives/trove.test.js.map +1 -0
  18. package/dist/__tests__/books/google-books.test.d.ts +8 -0
  19. package/dist/__tests__/books/google-books.test.d.ts.map +1 -0
  20. package/dist/__tests__/books/google-books.test.js +221 -0
  21. package/dist/__tests__/books/google-books.test.js.map +1 -0
  22. package/dist/__tests__/books/open-library.test.d.ts +8 -0
  23. package/dist/__tests__/books/open-library.test.d.ts.map +1 -0
  24. package/dist/__tests__/books/open-library.test.js +159 -0
  25. package/dist/__tests__/books/open-library.test.js.map +1 -0
  26. package/dist/__tests__/news/guardian.test.d.ts +9 -0
  27. package/dist/__tests__/news/guardian.test.d.ts.map +1 -0
  28. package/dist/__tests__/news/guardian.test.js +224 -0
  29. package/dist/__tests__/news/guardian.test.js.map +1 -0
  30. package/dist/__tests__/news/nytimes.test.d.ts +9 -0
  31. package/dist/__tests__/news/nytimes.test.d.ts.map +1 -0
  32. package/dist/__tests__/news/nytimes.test.js +271 -0
  33. package/dist/__tests__/news/nytimes.test.js.map +1 -0
  34. package/dist/__tests__/news/site-search-source.test.d.ts +9 -0
  35. package/dist/__tests__/news/site-search-source.test.d.ts.map +1 -0
  36. package/dist/__tests__/news/site-search-source.test.js +342 -0
  37. package/dist/__tests__/news/site-search-source.test.js.map +1 -0
  38. package/dist/__tests__/obituary/find-a-grave.test.d.ts +8 -0
  39. package/dist/__tests__/obituary/find-a-grave.test.d.ts.map +1 -0
  40. package/dist/__tests__/obituary/find-a-grave.test.js +238 -0
  41. package/dist/__tests__/obituary/find-a-grave.test.js.map +1 -0
  42. package/dist/__tests__/shared/duckduckgo-search.test.d.ts +9 -0
  43. package/dist/__tests__/shared/duckduckgo-search.test.d.ts.map +1 -0
  44. package/dist/__tests__/shared/duckduckgo-search.test.js +218 -0
  45. package/dist/__tests__/shared/duckduckgo-search.test.js.map +1 -0
  46. package/dist/__tests__/shared/fetch-page.test.d.ts +9 -0
  47. package/dist/__tests__/shared/fetch-page.test.d.ts.map +1 -0
  48. package/dist/__tests__/shared/fetch-page.test.js +281 -0
  49. package/dist/__tests__/shared/fetch-page.test.js.map +1 -0
  50. package/dist/__tests__/shared/html-utils.test.d.ts +2 -0
  51. package/dist/__tests__/shared/html-utils.test.d.ts.map +1 -0
  52. package/dist/__tests__/shared/html-utils.test.js +169 -0
  53. package/dist/__tests__/shared/html-utils.test.js.map +1 -0
  54. package/dist/__tests__/shared/readability-extract.test.d.ts +2 -0
  55. package/dist/__tests__/shared/readability-extract.test.d.ts.map +1 -0
  56. package/dist/__tests__/shared/readability-extract.test.js +107 -0
  57. package/dist/__tests__/shared/readability-extract.test.js.map +1 -0
  58. package/dist/__tests__/shared/sanitize-text.test.d.ts +2 -0
  59. package/dist/__tests__/shared/sanitize-text.test.d.ts.map +1 -0
  60. package/dist/__tests__/shared/sanitize-text.test.js +77 -0
  61. package/dist/__tests__/shared/sanitize-text.test.js.map +1 -0
  62. package/dist/__tests__/shared/search-utils.test.d.ts +2 -0
  63. package/dist/__tests__/shared/search-utils.test.d.ts.map +1 -0
  64. package/dist/__tests__/shared/search-utils.test.js +26 -0
  65. package/dist/__tests__/shared/search-utils.test.js.map +1 -0
  66. package/dist/__tests__/structured/wikidata.test.d.ts +9 -0
  67. package/dist/__tests__/structured/wikidata.test.d.ts.map +1 -0
  68. package/dist/__tests__/structured/wikidata.test.js +509 -0
  69. package/dist/__tests__/structured/wikidata.test.js.map +1 -0
  70. package/dist/__tests__/structured/wikipedia.test.d.ts +9 -0
  71. package/dist/__tests__/structured/wikipedia.test.d.ts.map +1 -0
  72. package/dist/__tests__/structured/wikipedia.test.js +643 -0
  73. package/dist/__tests__/structured/wikipedia.test.js.map +1 -0
  74. package/dist/__tests__/web-search/base.test.d.ts +9 -0
  75. package/dist/__tests__/web-search/base.test.d.ts.map +1 -0
  76. package/dist/__tests__/web-search/base.test.js +622 -0
  77. package/dist/__tests__/web-search/base.test.js.map +1 -0
  78. package/dist/__tests__/web-search/bing.test.d.ts +10 -0
  79. package/dist/__tests__/web-search/bing.test.d.ts.map +1 -0
  80. package/dist/__tests__/web-search/bing.test.js +277 -0
  81. package/dist/__tests__/web-search/bing.test.js.map +1 -0
  82. package/dist/__tests__/web-search/brave.test.d.ts +10 -0
  83. package/dist/__tests__/web-search/brave.test.d.ts.map +1 -0
  84. package/dist/__tests__/web-search/brave.test.js +264 -0
  85. package/dist/__tests__/web-search/brave.test.js.map +1 -0
  86. package/dist/__tests__/web-search/duckduckgo.test.d.ts +10 -0
  87. package/dist/__tests__/web-search/duckduckgo.test.d.ts.map +1 -0
  88. package/dist/__tests__/web-search/duckduckgo.test.js +107 -0
  89. package/dist/__tests__/web-search/duckduckgo.test.js.map +1 -0
  90. package/dist/__tests__/web-search/google.test.d.ts +9 -0
  91. package/dist/__tests__/web-search/google.test.d.ts.map +1 -0
  92. package/dist/__tests__/web-search/google.test.js +189 -0
  93. package/dist/__tests__/web-search/google.test.js.map +1 -0
  94. package/dist/archives/chronicling-america.d.ts +33 -0
  95. package/dist/archives/chronicling-america.d.ts.map +1 -0
  96. package/dist/archives/chronicling-america.js +85 -0
  97. package/dist/archives/chronicling-america.js.map +1 -0
  98. package/dist/archives/europeana.d.ts +37 -0
  99. package/dist/archives/europeana.d.ts.map +1 -0
  100. package/dist/archives/europeana.js +92 -0
  101. package/dist/archives/europeana.js.map +1 -0
  102. package/dist/archives/internet-archive.d.ts +32 -0
  103. package/dist/archives/internet-archive.d.ts.map +1 -0
  104. package/dist/archives/internet-archive.js +90 -0
  105. package/dist/archives/internet-archive.js.map +1 -0
  106. package/dist/archives/trove.d.ts +37 -0
  107. package/dist/archives/trove.d.ts.map +1 -0
  108. package/dist/archives/trove.js +97 -0
  109. package/dist/archives/trove.js.map +1 -0
  110. package/dist/books/google-books.d.ts +48 -0
  111. package/dist/books/google-books.d.ts.map +1 -0
  112. package/dist/books/google-books.js +111 -0
  113. package/dist/books/google-books.js.map +1 -0
  114. package/dist/books/open-library.d.ts +44 -0
  115. package/dist/books/open-library.d.ts.map +1 -0
  116. package/dist/books/open-library.js +103 -0
  117. package/dist/books/open-library.js.map +1 -0
  118. package/dist/index.d.ts +45 -0
  119. package/dist/index.d.ts.map +1 -0
  120. package/dist/index.js +35 -0
  121. package/dist/index.js.map +1 -0
  122. package/dist/news/guardian.d.ts +51 -0
  123. package/dist/news/guardian.d.ts.map +1 -0
  124. package/dist/news/guardian.js +131 -0
  125. package/dist/news/guardian.js.map +1 -0
  126. package/dist/news/nytimes.d.ts +27 -0
  127. package/dist/news/nytimes.d.ts.map +1 -0
  128. package/dist/news/nytimes.js +104 -0
  129. package/dist/news/nytimes.js.map +1 -0
  130. package/dist/news/site-search-source.d.ts +89 -0
  131. package/dist/news/site-search-source.d.ts.map +1 -0
  132. package/dist/news/site-search-source.js +182 -0
  133. package/dist/news/site-search-source.js.map +1 -0
  134. package/dist/news/sources.d.ts +52 -0
  135. package/dist/news/sources.d.ts.map +1 -0
  136. package/dist/news/sources.js +276 -0
  137. package/dist/news/sources.js.map +1 -0
  138. package/dist/obituary/find-a-grave.d.ts +43 -0
  139. package/dist/obituary/find-a-grave.d.ts.map +1 -0
  140. package/dist/obituary/find-a-grave.js +173 -0
  141. package/dist/obituary/find-a-grave.js.map +1 -0
  142. package/dist/shared/duckduckgo-search.d.ts +86 -0
  143. package/dist/shared/duckduckgo-search.d.ts.map +1 -0
  144. package/dist/shared/duckduckgo-search.js +218 -0
  145. package/dist/shared/duckduckgo-search.js.map +1 -0
  146. package/dist/shared/fetch-page.d.ts +50 -0
  147. package/dist/shared/fetch-page.d.ts.map +1 -0
  148. package/dist/shared/fetch-page.js +212 -0
  149. package/dist/shared/fetch-page.js.map +1 -0
  150. package/dist/shared/html-utils.d.ts +99 -0
  151. package/dist/shared/html-utils.d.ts.map +1 -0
  152. package/dist/shared/html-utils.js +246 -0
  153. package/dist/shared/html-utils.js.map +1 -0
  154. package/dist/shared/readability-extract.d.ts +33 -0
  155. package/dist/shared/readability-extract.d.ts.map +1 -0
  156. package/dist/shared/readability-extract.js +45 -0
  157. package/dist/shared/readability-extract.js.map +1 -0
  158. package/dist/shared/sanitize-text.d.ts +24 -0
  159. package/dist/shared/sanitize-text.d.ts.map +1 -0
  160. package/dist/shared/sanitize-text.js +49 -0
  161. package/dist/shared/sanitize-text.js.map +1 -0
  162. package/dist/shared/search-utils.d.ts +18 -0
  163. package/dist/shared/search-utils.d.ts.map +1 -0
  164. package/dist/shared/search-utils.js +20 -0
  165. package/dist/shared/search-utils.js.map +1 -0
  166. package/dist/structured/wikidata.d.ts +128 -0
  167. package/dist/structured/wikidata.d.ts.map +1 -0
  168. package/dist/structured/wikidata.js +361 -0
  169. package/dist/structured/wikidata.js.map +1 -0
  170. package/dist/structured/wikipedia.d.ts +184 -0
  171. package/dist/structured/wikipedia.d.ts.map +1 -0
  172. package/dist/structured/wikipedia.js +275 -0
  173. package/dist/structured/wikipedia.js.map +1 -0
  174. package/dist/web-search/base.d.ts +128 -0
  175. package/dist/web-search/base.d.ts.map +1 -0
  176. package/dist/web-search/base.js +251 -0
  177. package/dist/web-search/base.js.map +1 -0
  178. package/dist/web-search/bing.d.ts +21 -0
  179. package/dist/web-search/bing.d.ts.map +1 -0
  180. package/dist/web-search/bing.js +53 -0
  181. package/dist/web-search/bing.js.map +1 -0
  182. package/dist/web-search/brave.d.ts +21 -0
  183. package/dist/web-search/brave.d.ts.map +1 -0
  184. package/dist/web-search/brave.js +56 -0
  185. package/dist/web-search/brave.js.map +1 -0
  186. package/dist/web-search/duckduckgo.d.ts +15 -0
  187. package/dist/web-search/duckduckgo.d.ts.map +1 -0
  188. package/dist/web-search/duckduckgo.js +21 -0
  189. package/dist/web-search/duckduckgo.js.map +1 -0
  190. package/dist/web-search/google.d.ts +24 -0
  191. package/dist/web-search/google.d.ts.map +1 -0
  192. package/dist/web-search/google.js +48 -0
  193. package/dist/web-search/google.js.map +1 -0
  194. package/package.json +58 -0
@@ -0,0 +1,342 @@
1
+ /**
2
+ * Tests for SiteSearchSource and pickBestUrl.
3
+ *
4
+ * Mocks the shared utilities (searchDuckDuckGo, fetchPage,
5
+ * extractArticleContent, sanitizeSourceText) so the tests exercise
6
+ * only the SiteSearchSource pipeline logic and pickBestUrl scoring.
7
+ */
8
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
9
+ import { ReliabilityTier } from "@debriefer/core";
10
+ // ============================================================================
11
+ // Mocks — must be declared before importing the module under test
12
+ // ============================================================================
13
+ const mockSearchDDG = vi.fn();
14
+ const mockFetchPage = vi.fn();
15
+ const mockExtractArticle = vi.fn();
16
+ const mockSanitize = vi.fn();
17
+ vi.mock("../../shared/duckduckgo-search.js", () => ({
18
+ searchDuckDuckGo: (...args) => mockSearchDDG(...args),
19
+ }));
20
+ vi.mock("../../shared/fetch-page.js", () => ({
21
+ fetchPage: (...args) => mockFetchPage(...args),
22
+ }));
23
+ vi.mock("../../shared/readability-extract.js", () => ({
24
+ extractArticleContent: (...args) => mockExtractArticle(...args),
25
+ }));
26
+ vi.mock("../../shared/sanitize-text.js", () => ({
27
+ sanitizeSourceText: (...args) => mockSanitize(...args),
28
+ }));
29
+ import { SiteSearchSource, pickBestUrl, } from "../../news/site-search-source.js";
30
+ // ============================================================================
31
+ // Helpers
32
+ // ============================================================================
33
+ /** Minimal config for most tests. */
34
+ function makeConfig(overrides) {
35
+ return {
36
+ name: "AP News",
37
+ type: "ap-news",
38
+ domain: "apnews.com",
39
+ reliabilityTier: ReliabilityTier.TIER_1_NEWS,
40
+ ...overrides,
41
+ };
42
+ }
43
+ /** Standard test subject. */
44
+ const subject = { id: 1, name: "John Wayne" };
45
+ /** Standard abort signal for tests. */
46
+ const signal = AbortSignal.timeout(5000);
47
+ // ============================================================================
48
+ // Lifecycle
49
+ // ============================================================================
50
+ beforeEach(() => {
51
+ mockSearchDDG.mockReset();
52
+ mockFetchPage.mockReset();
53
+ mockExtractArticle.mockReset();
54
+ mockSanitize.mockReset();
55
+ });
56
+ afterEach(() => {
57
+ vi.restoreAllMocks();
58
+ });
59
+ // ============================================================================
60
+ // pickBestUrl
61
+ // ============================================================================
62
+ describe("pickBestUrl", () => {
63
+ it("returns first URL when no preferences are set", () => {
64
+ const results = [
65
+ { url: "https://apnews.com/first", title: "First", snippet: "" },
66
+ { url: "https://apnews.com/second", title: "Second", snippet: "" },
67
+ ];
68
+ expect(pickBestUrl(results)).toBe("https://apnews.com/first");
69
+ });
70
+ it("prefers URL matching preferredPaths", () => {
71
+ const results = [
72
+ { url: "https://apnews.com/gallery/photo-1", title: "Gallery", snippet: "" },
73
+ { url: "https://apnews.com/article/john-wayne", title: "Article", snippet: "" },
74
+ ];
75
+ expect(pickBestUrl(results, { preferredPaths: ["/article/"] })).toBe("https://apnews.com/article/john-wayne");
76
+ });
77
+ it("avoids URL matching avoidPaths", () => {
78
+ const results = [
79
+ { url: "https://apnews.com/gallery/photo-1", title: "Gallery", snippet: "" },
80
+ { url: "https://apnews.com/other/page", title: "Other", snippet: "" },
81
+ ];
82
+ expect(pickBestUrl(results, { avoidPaths: ["/gallery/"] })).toBe("https://apnews.com/other/page");
83
+ });
84
+ it("preferred beats avoid when both match different URLs", () => {
85
+ const results = [
86
+ { url: "https://apnews.com/gallery/photo-1", title: "Gallery", snippet: "" },
87
+ { url: "https://apnews.com/article/john-wayne", title: "Article", snippet: "" },
88
+ ];
89
+ expect(pickBestUrl(results, { preferredPaths: ["/article/"], avoidPaths: ["/gallery/"] })).toBe("https://apnews.com/article/john-wayne");
90
+ });
91
+ it("returns first URL when no paths match any preferences", () => {
92
+ const results = [
93
+ { url: "https://apnews.com/hub/politics", title: "Hub", snippet: "" },
94
+ { url: "https://apnews.com/hub/sports", title: "Sports", snippet: "" },
95
+ ];
96
+ expect(pickBestUrl(results, { preferredPaths: ["/article/"], avoidPaths: ["/gallery/"] })).toBe("https://apnews.com/hub/politics");
97
+ });
98
+ it("returns null for empty array", () => {
99
+ expect(pickBestUrl([])).toBeNull();
100
+ });
101
+ });
102
+ // ============================================================================
103
+ // SiteSearchSource — metadata
104
+ // ============================================================================
105
+ describe("SiteSearchSource", () => {
106
+ describe("metadata", () => {
107
+ it("derives all metadata from config", () => {
108
+ const source = new SiteSearchSource(makeConfig());
109
+ expect(source.name).toBe("AP News");
110
+ expect(source.type).toBe("ap-news");
111
+ expect(source.reliabilityTier).toBe(ReliabilityTier.TIER_1_NEWS);
112
+ expect(source.domain).toBe("apnews.com");
113
+ expect(source.isFree).toBe(true);
114
+ expect(source.estimatedCostPerQuery).toBe(0);
115
+ });
116
+ });
117
+ // ==========================================================================
118
+ // buildQuery
119
+ // ==========================================================================
120
+ describe("buildQuery", () => {
121
+ it("wraps subject name in quotes", () => {
122
+ const source = new SiteSearchSource(makeConfig());
123
+ expect(source.buildQuery(subject)).toBe('"John Wayne"');
124
+ });
125
+ it("appends queryTerms when configured", () => {
126
+ const source = new SiteSearchSource(makeConfig({ queryTerms: "biography OR profile" }));
127
+ expect(source.buildQuery(subject)).toBe('"John Wayne" (biography OR profile)');
128
+ });
129
+ });
130
+ // ==========================================================================
131
+ // fetchResult — full pipeline success
132
+ // ==========================================================================
133
+ describe("full pipeline", () => {
134
+ it("returns a finding on successful pipeline", async () => {
135
+ mockSearchDDG.mockResolvedValue([
136
+ { url: "https://apnews.com/article/john-wayne", title: "AP article", snippet: "..." },
137
+ ]);
138
+ mockFetchPage.mockResolvedValue({
139
+ content: "<html>content</html>",
140
+ url: "https://apnews.com/article/john-wayne",
141
+ fetchMethod: "direct",
142
+ });
143
+ mockExtractArticle.mockReturnValue({
144
+ text: "A".repeat(300),
145
+ title: "John Wayne obituary",
146
+ author: "AP Staff",
147
+ excerpt: "...",
148
+ siteName: "AP News",
149
+ });
150
+ mockSanitize.mockReturnValue("A".repeat(300));
151
+ const source = new SiteSearchSource(makeConfig());
152
+ const result = await source.lookup(subject, signal);
153
+ expect(result).not.toBeNull();
154
+ expect(result.text).toBe("A".repeat(300));
155
+ expect(result.confidence).toBe(-1);
156
+ expect(result.costUsd).toBe(0);
157
+ expect(result.url).toBe("https://apnews.com/article/john-wayne");
158
+ expect(result.publication).toBe("AP News");
159
+ expect(result.metadata).toEqual({
160
+ title: "John Wayne obituary",
161
+ author: "AP Staff",
162
+ siteName: "AP News",
163
+ domain: "apnews.com",
164
+ });
165
+ });
166
+ it("passes queryTerms to the DDG search query", async () => {
167
+ mockSearchDDG.mockResolvedValue([]);
168
+ const source = new SiteSearchSource(makeConfig({ queryTerms: "obituary" }));
169
+ await source.lookup(subject, signal);
170
+ const callArgs = mockSearchDDG.mock.calls[0][0];
171
+ expect(callArgs.query).toBe('"John Wayne" (obituary)');
172
+ });
173
+ it("passes domainFilter to searchDuckDuckGo", async () => {
174
+ mockSearchDDG.mockResolvedValue([]);
175
+ const source = new SiteSearchSource(makeConfig());
176
+ await source.lookup(subject, signal);
177
+ const callArgs = mockSearchDDG.mock.calls[0][0];
178
+ expect(callArgs.domainFilter).toBe("apnews.com");
179
+ });
180
+ it("uses preferredPaths in pickBestUrl", async () => {
181
+ mockSearchDDG.mockResolvedValue([
182
+ { url: "https://apnews.com/gallery/photo-1", title: "Gallery", snippet: "" },
183
+ { url: "https://apnews.com/article/john-wayne", title: "Article", snippet: "" },
184
+ ]);
185
+ mockFetchPage.mockResolvedValue({
186
+ content: "<html>content</html>",
187
+ url: "https://apnews.com/article/john-wayne",
188
+ fetchMethod: "direct",
189
+ });
190
+ mockExtractArticle.mockReturnValue({
191
+ text: "B".repeat(300),
192
+ title: "Article",
193
+ author: null,
194
+ excerpt: null,
195
+ siteName: "AP News",
196
+ });
197
+ mockSanitize.mockReturnValue("B".repeat(300));
198
+ const source = new SiteSearchSource(makeConfig({ preferredPaths: ["/article/"], avoidPaths: ["/gallery/"] }));
199
+ const result = await source.lookup(subject, signal);
200
+ // Should have fetched the /article/ URL, not the /gallery/ one
201
+ expect(mockFetchPage).toHaveBeenCalledWith(expect.objectContaining({ url: "https://apnews.com/article/john-wayne" }));
202
+ expect(result).not.toBeNull();
203
+ });
204
+ it("includes publication and url in result metadata", async () => {
205
+ mockSearchDDG.mockResolvedValue([
206
+ { url: "https://apnews.com/article/test", title: "Test", snippet: "" },
207
+ ]);
208
+ mockFetchPage.mockResolvedValue({
209
+ content: "<html>content</html>",
210
+ url: "https://apnews.com/article/test",
211
+ fetchMethod: "direct",
212
+ });
213
+ mockExtractArticle.mockReturnValue({
214
+ text: "C".repeat(300),
215
+ title: "Test Article",
216
+ author: "Author",
217
+ excerpt: "...",
218
+ siteName: "AP",
219
+ });
220
+ mockSanitize.mockReturnValue("C".repeat(300));
221
+ const source = new SiteSearchSource(makeConfig());
222
+ const result = await source.lookup(subject, signal);
223
+ expect(result.publication).toBe("AP News");
224
+ expect(result.url).toBe("https://apnews.com/article/test");
225
+ });
226
+ });
227
+ // ==========================================================================
228
+ // fetchResult — null returns
229
+ // ==========================================================================
230
+ describe("null returns", () => {
231
+ it("returns null when search returns empty results", async () => {
232
+ mockSearchDDG.mockResolvedValue([]);
233
+ const source = new SiteSearchSource(makeConfig());
234
+ const result = await source.lookup(subject, signal);
235
+ expect(result).toBeNull();
236
+ });
237
+ it("returns null when fetch fails", async () => {
238
+ mockSearchDDG.mockResolvedValue([
239
+ { url: "https://apnews.com/article/test", title: "Test", snippet: "" },
240
+ ]);
241
+ mockFetchPage.mockResolvedValue({
242
+ content: "",
243
+ url: "https://apnews.com/article/test",
244
+ fetchMethod: "none",
245
+ error: "HTTP 404",
246
+ });
247
+ const source = new SiteSearchSource(makeConfig());
248
+ const result = await source.lookup(subject, signal);
249
+ expect(result).toBeNull();
250
+ });
251
+ it("returns null when extraction fails", async () => {
252
+ mockSearchDDG.mockResolvedValue([
253
+ { url: "https://apnews.com/article/test", title: "Test", snippet: "" },
254
+ ]);
255
+ mockFetchPage.mockResolvedValue({
256
+ content: "<html>content</html>",
257
+ url: "https://apnews.com/article/test",
258
+ fetchMethod: "direct",
259
+ });
260
+ mockExtractArticle.mockReturnValue(null);
261
+ const source = new SiteSearchSource(makeConfig());
262
+ const result = await source.lookup(subject, signal);
263
+ expect(result).toBeNull();
264
+ });
265
+ it("returns null when extracted text is too short", async () => {
266
+ mockSearchDDG.mockResolvedValue([
267
+ { url: "https://apnews.com/article/test", title: "Test", snippet: "" },
268
+ ]);
269
+ mockFetchPage.mockResolvedValue({
270
+ content: "<html>content</html>",
271
+ url: "https://apnews.com/article/test",
272
+ fetchMethod: "direct",
273
+ });
274
+ mockExtractArticle.mockReturnValue({
275
+ text: "Short text",
276
+ title: "Test",
277
+ author: null,
278
+ excerpt: null,
279
+ siteName: null,
280
+ });
281
+ const source = new SiteSearchSource(makeConfig());
282
+ const result = await source.lookup(subject, signal);
283
+ expect(result).toBeNull();
284
+ // sanitize should not have been called
285
+ expect(mockSanitize).not.toHaveBeenCalled();
286
+ });
287
+ });
288
+ // ==========================================================================
289
+ // additionalDomains
290
+ // ==========================================================================
291
+ describe("additionalDomains", () => {
292
+ it("searches all domains when additionalDomains are configured", async () => {
293
+ mockSearchDDG.mockResolvedValue([]);
294
+ const source = new SiteSearchSource(makeConfig({
295
+ name: "BBC",
296
+ type: "bbc",
297
+ domain: "bbc.com",
298
+ additionalDomains: ["bbc.co.uk"],
299
+ }));
300
+ await source.lookup(subject, signal);
301
+ // Should call searchDDG twice — once per domain
302
+ expect(mockSearchDDG).toHaveBeenCalledTimes(2);
303
+ expect(mockSearchDDG.mock.calls[0][0]).toEqual(expect.objectContaining({ domainFilter: "bbc.com" }));
304
+ expect(mockSearchDDG.mock.calls[1][0]).toEqual(expect.objectContaining({ domainFilter: "bbc.co.uk" }));
305
+ });
306
+ it("combines results from multiple domains and picks best", async () => {
307
+ mockSearchDDG
308
+ .mockResolvedValueOnce([
309
+ { url: "https://bbc.com/gallery/photo", title: "Gallery", snippet: "" },
310
+ ])
311
+ .mockResolvedValueOnce([
312
+ { url: "https://bbc.co.uk/news/article-123", title: "Article", snippet: "" },
313
+ ]);
314
+ mockFetchPage.mockResolvedValue({
315
+ content: "<html>content</html>",
316
+ url: "https://bbc.co.uk/news/article-123",
317
+ fetchMethod: "direct",
318
+ });
319
+ mockExtractArticle.mockReturnValue({
320
+ text: "D".repeat(300),
321
+ title: "BBC Article",
322
+ author: null,
323
+ excerpt: null,
324
+ siteName: "BBC",
325
+ });
326
+ mockSanitize.mockReturnValue("D".repeat(300));
327
+ const source = new SiteSearchSource(makeConfig({
328
+ name: "BBC",
329
+ type: "bbc",
330
+ domain: "bbc.com",
331
+ additionalDomains: ["bbc.co.uk"],
332
+ preferredPaths: ["/news/"],
333
+ avoidPaths: ["/gallery/"],
334
+ }));
335
+ const result = await source.lookup(subject, signal);
336
+ expect(result).not.toBeNull();
337
+ // Should have picked the /news/ URL from bbc.co.uk over the /gallery/ one
338
+ expect(mockFetchPage).toHaveBeenCalledWith(expect.objectContaining({ url: "https://bbc.co.uk/news/article-123" }));
339
+ });
340
+ });
341
+ });
342
+ //# sourceMappingURL=site-search-source.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-search-source.test.js","sourceRoot":"","sources":["../../../src/__tests__/news/site-search-source.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests for the Find a Grave obituary source.
3
+ *
4
+ * Mocks shared utilities (fetchPage, extractArticleContent, sanitizeSourceText)
5
+ * so the tests exercise only the FindAGraveSource pipeline logic.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=find-a-grave.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-a-grave.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/obituary/find-a-grave.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Tests for the Find a Grave obituary source.
3
+ *
4
+ * Mocks shared utilities (fetchPage, extractArticleContent, sanitizeSourceText)
5
+ * so the tests exercise only the FindAGraveSource pipeline logic.
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from "vitest";
8
+ import { ReliabilityTier } from "@debriefer/core";
9
+ // ============================================================================
10
+ // Mocks — must be declared before importing the module under test
11
+ // ============================================================================
12
+ const mockFetchPage = vi.fn();
13
+ const mockExtractArticle = vi.fn();
14
+ const mockSanitize = vi.fn();
15
+ vi.mock("../../shared/fetch-page.js", () => ({
16
+ fetchPage: (...args) => mockFetchPage(...args),
17
+ }));
18
+ vi.mock("../../shared/readability-extract.js", () => ({
19
+ extractArticleContent: (...args) => mockExtractArticle(...args),
20
+ }));
21
+ vi.mock("../../shared/sanitize-text.js", () => ({
22
+ sanitizeSourceText: (...args) => mockSanitize(...args),
23
+ }));
24
+ import { FindAGraveSource, findAGrave } from "../../obituary/find-a-grave.js";
25
+ // ============================================================================
26
+ // Helpers
27
+ // ============================================================================
28
+ /** Standard test subject. */
29
+ const subject = { id: 1, name: "John Wayne" };
30
+ /** Standard abort signal for tests. */
31
+ const signal = AbortSignal.timeout(5000);
32
+ /**
33
+ * Build search results HTML containing memorial links.
34
+ * Each entry is a path like "/memorial/12345/john-wayne"
35
+ */
36
+ function makeSearchHtml(memorialPaths) {
37
+ const links = memorialPaths
38
+ .map((path) => `<a href="${path}" class="memorial-link">Memorial</a>`)
39
+ .join("\n");
40
+ return `<html><body><div class="search-results">${links}</div></body></html>`;
41
+ }
42
+ /**
43
+ * Mock the search step via fetchPage. The search is now the first fetchPage call.
44
+ * Returns a FetchPageResult-shaped object.
45
+ */
46
+ function mockSearchFetchPage(html, fetchMethod = "direct") {
47
+ mockFetchPage.mockResolvedValueOnce({
48
+ content: html,
49
+ url: "https://www.findagrave.com/memorial/search",
50
+ fetchMethod,
51
+ });
52
+ }
53
+ // ============================================================================
54
+ // Lifecycle
55
+ // ============================================================================
56
+ beforeEach(() => {
57
+ mockFetchPage.mockReset();
58
+ mockExtractArticle.mockReset();
59
+ mockSanitize.mockReset();
60
+ });
61
+ // ============================================================================
62
+ // Tests
63
+ // ============================================================================
64
+ describe("FindAGraveSource", () => {
65
+ describe("metadata", () => {
66
+ it("has correct name, type, reliability tier, isFree, and cost", () => {
67
+ const source = new FindAGraveSource();
68
+ expect(source.name).toBe("Find a Grave");
69
+ expect(source.type).toBe("find-a-grave");
70
+ expect(source.reliabilityTier).toBe(ReliabilityTier.UNRELIABLE_UGC);
71
+ expect(source.domain).toBe("www.findagrave.com");
72
+ expect(source.isFree).toBe(true);
73
+ expect(source.estimatedCostPerQuery).toBe(0);
74
+ });
75
+ it("always reports as available (no API key needed)", () => {
76
+ const source = new FindAGraveSource();
77
+ expect(source.isAvailable()).toBe(true);
78
+ });
79
+ });
80
+ describe("search URL construction", () => {
81
+ it("builds search URL with first and last name from subject", async () => {
82
+ mockSearchFetchPage("<html><body></body></html>");
83
+ const source = new FindAGraveSource();
84
+ await source.lookup(subject, signal);
85
+ expect(mockFetchPage).toHaveBeenCalledTimes(1);
86
+ const calledOpts = mockFetchPage.mock.calls[0][0];
87
+ expect(calledOpts.url).toContain("firstname=John");
88
+ expect(calledOpts.url).toContain("lastname=Wayne");
89
+ expect(calledOpts.url).toContain("orderby=r");
90
+ });
91
+ });
92
+ describe("memorial URL extraction", () => {
93
+ it("extracts memorial URLs from search result HTML", async () => {
94
+ const searchHtml = makeSearchHtml([
95
+ "/memorial/12345/john-wayne",
96
+ "/memorial/67890/john-wayne-gacy",
97
+ ]);
98
+ mockSearchFetchPage(searchHtml);
99
+ // The name-matching step will filter for "john-wayne" in URL
100
+ // Both URLs contain "john-wayne" but first one is an exact match
101
+ mockFetchPage.mockResolvedValueOnce({
102
+ content: '<html><body><div id="bio">Bio content here</div></body></html>',
103
+ url: "https://www.findagrave.com/memorial/12345/john-wayne",
104
+ fetchMethod: "direct",
105
+ });
106
+ mockExtractArticle.mockReturnValue({
107
+ text: "A".repeat(150),
108
+ title: "John Wayne",
109
+ author: null,
110
+ excerpt: null,
111
+ siteName: "Find a Grave",
112
+ });
113
+ mockSanitize.mockReturnValue("A".repeat(150));
114
+ const source = new FindAGraveSource();
115
+ const result = await source.lookup(subject, signal);
116
+ expect(result).not.toBeNull();
117
+ // Second fetchPage call should be for the memorial page
118
+ expect(mockFetchPage).toHaveBeenCalledTimes(2);
119
+ expect(mockFetchPage.mock.calls[1][0]).toEqual(expect.objectContaining({
120
+ url: "https://www.findagrave.com/memorial/12345/john-wayne",
121
+ }));
122
+ });
123
+ });
124
+ describe("name matching in memorial URLs", () => {
125
+ it("filters memorial URLs to those containing the subject name (normalized)", async () => {
126
+ const searchHtml = makeSearchHtml([
127
+ "/memorial/11111/jane-smith",
128
+ "/memorial/22222/john-wayne",
129
+ ]);
130
+ mockSearchFetchPage(searchHtml);
131
+ mockFetchPage.mockResolvedValueOnce({
132
+ content: "<html><body>content</body></html>",
133
+ url: "https://www.findagrave.com/memorial/22222/john-wayne",
134
+ fetchMethod: "direct",
135
+ });
136
+ mockExtractArticle.mockReturnValue({
137
+ text: "B".repeat(150),
138
+ title: "John Wayne",
139
+ author: null,
140
+ excerpt: null,
141
+ siteName: "Find a Grave",
142
+ });
143
+ mockSanitize.mockReturnValue("B".repeat(150));
144
+ const source = new FindAGraveSource();
145
+ const result = await source.lookup(subject, signal);
146
+ expect(result).not.toBeNull();
147
+ // Should have fetched the john-wayne URL, not jane-smith
148
+ expect(mockFetchPage.mock.calls[1][0]).toEqual(expect.objectContaining({
149
+ url: "https://www.findagrave.com/memorial/22222/john-wayne",
150
+ }));
151
+ });
152
+ });
153
+ describe("null returns", () => {
154
+ it("returns null when no matching memorials found (name mismatch)", async () => {
155
+ const searchHtml = makeSearchHtml(["/memorial/11111/jane-smith", "/memorial/22222/bob-jones"]);
156
+ mockSearchFetchPage(searchHtml);
157
+ const source = new FindAGraveSource();
158
+ const result = await source.lookup(subject, signal);
159
+ expect(result).toBeNull();
160
+ // Only the search fetchPage call should have been made
161
+ expect(mockFetchPage).toHaveBeenCalledTimes(1);
162
+ });
163
+ it("returns null when search returns no results", async () => {
164
+ const emptyHtml = '<html><body><div class="search-results"></div></body></html>';
165
+ mockSearchFetchPage(emptyHtml);
166
+ const source = new FindAGraveSource();
167
+ const result = await source.lookup(subject, signal);
168
+ expect(result).toBeNull();
169
+ expect(mockFetchPage).toHaveBeenCalledTimes(1);
170
+ });
171
+ it("returns null when search fetch fails", async () => {
172
+ mockSearchFetchPage("", "none");
173
+ const source = new FindAGraveSource();
174
+ const result = await source.lookup(subject, signal);
175
+ expect(result).toBeNull();
176
+ });
177
+ });
178
+ describe("bio extraction and sanitization", () => {
179
+ it("extracts bio via Readability and sanitizes output", async () => {
180
+ const searchHtml = makeSearchHtml(["/memorial/12345/john-wayne"]);
181
+ mockSearchFetchPage(searchHtml);
182
+ const bioContent = "John Wayne (born Marion Robert Morrison; May 26, 1907 – June 11, 1979) was an American actor who became a popular icon through his leading roles in films during Hollywood's Golden Age.";
183
+ mockFetchPage.mockResolvedValueOnce({
184
+ content: `<html><body><article>${bioContent}</article></body></html>`,
185
+ url: "https://www.findagrave.com/memorial/12345/john-wayne",
186
+ fetchMethod: "direct",
187
+ });
188
+ mockExtractArticle.mockReturnValue({
189
+ text: bioContent,
190
+ title: "John Wayne",
191
+ author: null,
192
+ excerpt: null,
193
+ siteName: "Find a Grave",
194
+ });
195
+ mockSanitize.mockReturnValue(bioContent);
196
+ const source = new FindAGraveSource();
197
+ const result = await source.lookup(subject, signal);
198
+ expect(result).not.toBeNull();
199
+ expect(result.text).toBe(bioContent);
200
+ expect(result.confidence).toBe(-1);
201
+ expect(result.costUsd).toBe(0);
202
+ expect(result.url).toBe("https://www.findagrave.com/memorial/12345/john-wayne");
203
+ expect(result.publication).toBe("Find a Grave");
204
+ expect(mockSanitize).toHaveBeenCalledWith(bioContent);
205
+ });
206
+ it("falls back to regex when Readability extraction fails", async () => {
207
+ const searchHtml = makeSearchHtml(["/memorial/12345/john-wayne"]);
208
+ mockSearchFetchPage(searchHtml);
209
+ const bioDivContent = "John Wayne was born Marion Robert Morrison on May 26, 1907. He was a famous American actor known for westerns and war films during Hollywood's Golden Age.";
210
+ const pageHtml = `<html><body><div id="bio">${bioDivContent}</div></body></html>`;
211
+ mockFetchPage.mockResolvedValueOnce({
212
+ content: pageHtml,
213
+ url: "https://www.findagrave.com/memorial/12345/john-wayne",
214
+ fetchMethod: "direct",
215
+ });
216
+ // Readability returns null
217
+ mockExtractArticle.mockReturnValue(null);
218
+ mockSanitize.mockReturnValue(bioDivContent);
219
+ const source = new FindAGraveSource();
220
+ const result = await source.lookup(subject, signal);
221
+ expect(result).not.toBeNull();
222
+ expect(mockSanitize).toHaveBeenCalled();
223
+ expect(result.text).toBe(bioDivContent);
224
+ });
225
+ });
226
+ });
227
+ // ============================================================================
228
+ // Factory Function
229
+ // ============================================================================
230
+ describe("findAGrave factory", () => {
231
+ it("creates a FindAGraveSource instance", () => {
232
+ const source = findAGrave();
233
+ expect(source).toBeInstanceOf(FindAGraveSource);
234
+ expect(source.name).toBe("Find a Grave");
235
+ expect(source.type).toBe("find-a-grave");
236
+ });
237
+ });
238
+ //# sourceMappingURL=find-a-grave.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-a-grave.test.js","sourceRoot":"","sources":["../../../src/__tests__/obituary/find-a-grave.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests for the DuckDuckGo HTML search utility.
3
+ *
4
+ * Mocks the global `fetch` function to avoid real HTTP calls.
5
+ * Tests CAPTCHA detection, URL cleaning, HTML result extraction,
6
+ * domain filtering, and the full search function.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=duckduckgo-search.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duckduckgo-search.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/shared/duckduckgo-search.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}