import { test } from "node:test"; import assert from "node:assert/strict"; import { searchPapers, mergePapers } from "../src/papers.js"; const ARXIV_XML = ` http://arxiv.org/abs/2005.03464v5 Optimal supply chains and power sector benefits of green hydrogen 2020-05-07T16:24:15Z A study of green hydrogen supply chains and their power sector benefits. John Doe http://arxiv.org/abs/2205.11901v5 Endogenous learning for green hydrogen in a sector-coupled energy model 2022-05-24T10:00:00Z Learning curves for green hydrogen electrolysis in energy systems. Jane Smith `; const CROSSREF_JSON = { message: { items: [ { DOI: "10.1016/j.ijhydene.2023.01.001", title: ["Green hydrogen production: a comprehensive review of electrolysis"], URL: "https://doi.org/10.1016/j.ijhydene.2023.01.001", published: { "date-parts": [[2023]] }, abstract: "A review of electrolysis technologies for green hydrogen.", author: [{ given: "Alice", family: "Brown" }], "container-title": ["International Journal of Hydrogen Energy"], }, ], }, }; function mockFetch(records) { return async (url, options) => { const u = String(url); if (u.startsWith("https://export.arxiv.org")) { return { ok: true, status: 200, text: async () => records.arxiv, headers: { get: () => "application/atom+xml" }, }; } if (u.startsWith("https://api.crossref.org")) { return { ok: true, status: 200, json: async () => records.crossref, headers: { get: () => "application/json" }, }; } throw new Error(`unexpected fetch: ${u}`); }; } test("searchPapers queries arXiv and Crossref and dedupes by canonical id", async () => { const orig = globalThis.fetch; globalThis.fetch = mockFetch({ arxiv: ARXIV_XML, crossref: CROSSREF_JSON }); try { const r = await searchPapers("green hydrogen electrolysis"); // 2 arXiv + 1 Crossref, all distinct. assert.equal(r.errors.length, 0); const papers = r.papers; assert.ok(papers.length >= 3); const arxiv = papers.find((p) => p.id === "2005.03464v5"); assert.ok(arxiv, "arXiv id recorded"); assert.equal(arxiv.kind, "paper"); const doi = papers.find((p) => p.doi === "10.1016/j.ijhydene.2023.01.001"); assert.ok(doi, "DOI recorded"); // Relevance-ranked: the paper matching the brief's terms ranks above the rest. const ranked = [...papers].sort((a, b) => b.score - a.score); assert.ok(ranked[0].score >= ranked[ranked.length - 1].score); } finally { globalThis.fetch = orig; } }); test("searchPapers degrades to an error record when an API fails", async () => { const orig = globalThis.fetch; globalThis.fetch = async (url) => { if (String(url).startsWith("https://export.arxiv.org")) return { ok: false, status: 503, text: async () => "" }; return { ok: true, status: 200, json: async () => CROSSREF_JSON, headers: { get: () => "application/json" } }; }; try { const r = await searchPapers("green hydrogen"); assert.ok(r.errors.length >= 1, "the failed arXiv call surfaces as a paper_error"); assert.ok(r.papers.length >= 1, "Crossref still contributes papers"); } finally { globalThis.fetch = orig; } }); test("mergePapers tags paper sources with kind, doi and arxivId", () => { const papers = [ { kind: "paper", id: "2205.11901v5", url: "https://arxiv.org/pdf/2205.11901v5", title: "T1", doi: null, year: "2022" }, { kind: "paper", doi: "10.1016/j.x", url: "https://doi.org/10.1016/j.x", title: "T2", id: null, year: "2023", journal: "IJHE" }, ]; const merged = mergePapers([{ url: "https://web.example/a", title: "web" }], papers); assert.equal(merged.length, 3); assert.equal(merged[1].kind, "paper"); assert.equal(merged[1].arxivId, "2205.11901v5"); assert.equal(merged[2].doi, "10.1016/j.x"); assert.equal(merged[2].journal, "IJHE"); assert.equal(merged[0].kind, undefined); });