import { describe, test, expect, mock, beforeEach, afterEach } from "bun:test";
import { queryWikipedia, fetchSummary, textResponse, jsonResponse, errorResponse, WikipediaApiError } from "../src/api.js";
describe("api helpers", () => {
describe("textResponse", () => {
test("returns properly formatted response", () => {
const result = textResponse("Hello");
expect(result).toEqual({
content: [{ type: "text", text: "Hello" }],
});
});
test("handles empty string", () => {
const result = textResponse("");
expect(result.content[0].text).toBe("");
});
test("handles multiline text", () => {
const result = textResponse("Line 1\nLine 2");
expect(result.content[0].text).toBe("Line 1\nLine 2");
});
});
describe("jsonResponse", () => {
test("stringifies objects with indentation", () => {
const result = jsonResponse({ foo: "bar" });
expect(result.content[0].text).toBe('{\n "foo": "bar"\n}');
});
test("stringifies arrays", () => {
const result = jsonResponse([1, 2, 3]);
expect(result.content[0].text).toBe("[\n 1,\n 2,\n 3\n]");
});
test("handles null", () => {
const result = jsonResponse(null);
expect(result.content[0].text).toBe("null");
});
test("handles nested objects", () => {
const result = jsonResponse({ a: { b: "c" } });
expect(JSON.parse(result.content[0].text)).toEqual({ a: { b: "c" } });
});
});
describe("errorResponse", () => {
test("handles WikipediaApiError", () => {
const error = new WikipediaApiError("Not found", 404);
const result = errorResponse(error);
expect(result.content[0].text).toBe("Error: Not found");
});
test("handles generic Error", () => {
const error = new Error("Something went wrong");
const result = errorResponse(error);
expect(result.content[0].text).toBe("Error: Something went wrong");
});
test("handles unknown error", () => {
const result = errorResponse("string error");
expect(result.content[0].text).toBe("An unknown error occurred");
});
test("handles null error", () => {
const result = errorResponse(null);
expect(result.content[0].text).toBe("An unknown error occurred");
});
});
describe("WikipediaApiError", () => {
test("stores status code", () => {
const error = new WikipediaApiError("Not found", 404);
expect(error.statusCode).toBe(404);
expect(error.message).toBe("Not found");
expect(error.name).toBe("WikipediaApiError");
});
test("works without status code", () => {
const error = new WikipediaApiError("Timeout");
expect(error.statusCode).toBeUndefined();
expect(error.message).toBe("Timeout");
});
});
});
describe("Wikipedia API calls", () => {
const originalFetch = global.fetch;
afterEach(() => {
global.fetch = originalFetch;
});
describe("queryWikipedia", () => {
test("sends correct parameters", async () => {
let capturedUrl = "";
global.fetch = mock(async (url: string) => {
capturedUrl = url;
return new Response(JSON.stringify({ query: {} }));
});
await queryWikipedia({ action: "query", titles: "Test" });
expect(capturedUrl).toContain("action=query");
expect(capturedUrl).toContain("titles=Test");
expect(capturedUrl).toContain("format=json");
});
test("throws on non-ok response", async () => {
global.fetch = mock(async () => {
return new Response("Error", { status: 500, statusText: "Server Error" });
});
await expect(queryWikipedia({ action: "query" })).rejects.toThrow(WikipediaApiError);
});
test("returns parsed JSON", async () => {
const mockData = { query: { search: [{ title: "Test" }] } };
global.fetch = mock(async () => new Response(JSON.stringify(mockData)));
const result = await queryWikipedia({ action: "query" });
expect(result).toEqual(mockData);
});
});
describe("fetchSummary", () => {
test("encodes title in URL", async () => {
let capturedUrl = "";
global.fetch = mock(async (url: string) => {
capturedUrl = url;
return new Response(JSON.stringify({ title: "Test Article" }));
});
await fetchSummary("Test Article");
expect(capturedUrl).toContain("/page/summary/Test%20Article");
});
test("throws on 404", async () => {
global.fetch = mock(async () => new Response("Not found", { status: 404 }));
await expect(fetchSummary("NonexistentPage")).rejects.toThrow(WikipediaApiError);
});
test("returns parsed summary data", async () => {
const mockData = { title: "Test", extract: "Summary text" };
global.fetch = mock(async () => new Response(JSON.stringify(mockData)));
const result = await fetchSummary("Test");
expect(result.title).toBe("Test");
expect(result.extract).toBe("Summary text");
});
});
});