feature/pi-refactor
  1/**
  2 * Tests for Web Search Tool
  3 * 
  4 * RED phase: Write these tests first, verify they fail
  5 * GREEN phase: Implement web search functionality
  6 * REFACTOR phase: Improve structure
  7 */
  8
  9import { describe, it, expect } from "vitest";
 10import { webSearchTool } from "./websearch.js";
 11
 12describe("Web Search Tool", () => {
 13  it("should have correct tool metadata", () => {
 14    expect(webSearchTool.name).toBe("web_search");
 15    expect(webSearchTool.label).toBeDefined();
 16    expect(webSearchTool.description).toBeDefined();
 17    expect(webSearchTool.description.toLowerCase()).toContain("search");
 18  });
 19
 20  it("should require a query parameter", () => {
 21    expect(webSearchTool.parameters).toBeDefined();
 22    
 23    // Should have a 'query' property in the schema
 24    const schema = webSearchTool.parameters as any;
 25    expect(schema.properties).toBeDefined();
 26    expect(schema.properties.query).toBeDefined();
 27  });
 28
 29  it("should execute search and return results", async () => {
 30    const result = await webSearchTool.execute(
 31      "test-call-id",
 32      { query: "TypeScript testing" },
 33      new AbortController().signal,
 34      () => {}
 35    );
 36
 37    expect(result).toBeDefined();
 38    expect(result.content).toBeDefined();
 39    expect(Array.isArray(result.content)).toBe(true);
 40    expect(result.content.length).toBeGreaterThan(0);
 41  }, 30000); // Longer timeout for actual web search
 42
 43  it("should return text content with search results", async () => {
 44    const result = await webSearchTool.execute(
 45      "test-call-id",
 46      { query: "OpenAI GPT-4" },
 47      new AbortController().signal,
 48      () => {}
 49    );
 50
 51    const textContent = result.content.find((c: any) => c.type === "text");
 52    expect(textContent).toBeDefined();
 53    
 54    const text = (textContent as any).text;
 55    expect(text).toBeDefined();
 56    expect(text.length).toBeGreaterThan(0);
 57  }, 30000);
 58
 59  it("should include search result URLs", async () => {
 60    const result = await webSearchTool.execute(
 61      "test-call-id",
 62      { query: "Rust programming language" },
 63      new AbortController().signal,
 64      () => {}
 65    );
 66
 67    const textContent = result.content.find((c: any) => c.type === "text");
 68    const text = (textContent as any).text;
 69    
 70    // Should contain URLs (http or https)
 71    expect(text).toMatch(/https?:\/\//);
 72  }, 30000);
 73
 74  it("should handle empty query gracefully", async () => {
 75    const result = await webSearchTool.execute(
 76      "test-call-id",
 77      { query: "" },
 78      new AbortController().signal,
 79      () => {}
 80    );
 81
 82    expect(result).toBeDefined();
 83    expect(result.content).toBeDefined();
 84  });
 85
 86  it("should limit number of results", async () => {
 87    const result = await webSearchTool.execute(
 88      "test-call-id",
 89      { query: "Python programming", maxResults: 3 },
 90      new AbortController().signal,
 91      () => {}
 92    );
 93
 94    const textContent = result.content.find((c: any) => c.type === "text");
 95    const text = (textContent as any).text;
 96    
 97    // Should have limited results (check for result numbering or similar)
 98    expect(text).toBeDefined();
 99  }, 30000);
100});