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});