/ tests / slash-command-web-handlers.test.ts
slash-command-web-handlers.test.ts
  1  import { beforeEach, describe, expect, it, vi } from 'vitest'
  2  
  3  import {
  4    buildWebHelpSlashCommandResult,
  5    runWebFetchSlashCommand,
  6    runWebSearchSlashCommand,
  7  } from '@/server/chat/slash-command-web-handlers'
  8  import {
  9    executeWebFetchTool,
 10    executeWebSearchTool,
 11  } from '@/server/tools/web-tool-execution'
 12  
 13  vi.mock('@/server/tools/web-tool-execution', () => ({
 14    executeWebSearchTool: vi.fn(),
 15    executeWebFetchTool: vi.fn(),
 16  }))
 17  
 18  describe('slash-command-web-handlers', () => {
 19    beforeEach(() => {
 20      vi.clearAllMocks()
 21    })
 22  
 23    it('renders web search results with image fields and cache marker', async () => {
 24      vi.mocked(executeWebSearchTool).mockResolvedValue({
 25        ok: true,
 26        response: {
 27          provider: 'duckduckgo',
 28          cached: true,
 29          searchTimeMs: 10,
 30          results: [
 31            {
 32              title: 'Result A',
 33              url: 'https://example.com/a',
 34              snippet: 'A snippet',
 35              imageUrl: 'https://img.example.com/a.jpg',
 36              thumbnailUrl: 'https://img.example.com/a-thumb.jpg',
 37            },
 38          ],
 39        },
 40        results: [
 41          {
 42            title: 'Result A',
 43            url: 'https://example.com/a',
 44            snippet: 'A snippet',
 45            imageUrl: 'https://img.example.com/a.jpg',
 46            thumbnailUrl: 'https://img.example.com/a-thumb.jpg',
 47          },
 48        ],
 49      })
 50  
 51      const result = await runWebSearchSlashCommand({
 52        query: 'kittens',
 53        searchType: 'image',
 54        attachmentNote: '\n\nNote: attachments ignored.',
 55      })
 56  
 57      expect(result.provider).toBe('web-search')
 58      expect(result.mocked).toBe(false)
 59      expect(result.text).toContain('**Web Search Results** (image) (duckduckgo)')
 60      expect(result.text).toContain('![image](https://img.example.com/a-thumb.jpg)')
 61      expect(result.text).toContain('*Results from cache*')
 62      expect(result.text).toContain('Note: attachments ignored.')
 63    })
 64  
 65    it('renders web search errors', async () => {
 66      vi.mocked(executeWebSearchTool).mockResolvedValue({
 67        ok: false,
 68        error: 'search unavailable',
 69      })
 70  
 71      const result = await runWebSearchSlashCommand({
 72        query: 'kittens',
 73        attachmentNote: '',
 74      })
 75  
 76      expect(result).toEqual({
 77        text: 'Web search failed: search unavailable',
 78        provider: 'web-search',
 79        mocked: false,
 80      })
 81    })
 82  
 83    it('renders web fetch preview and truncation markers', async () => {
 84      vi.mocked(executeWebFetchTool).mockResolvedValue({
 85        ok: true,
 86        response: {
 87          cached: true,
 88          fetchTimeMs: 20,
 89          result: {
 90            title: 'Example Page',
 91            url: 'https://example.com',
 92            content: `${'x'.repeat(7501)}`,
 93            contentType: 'markdown',
 94            truncated: true,
 95            bytesRead: 1234,
 96          },
 97        },
 98      })
 99  
100      const result = await runWebFetchSlashCommand({
101        url: 'https://example.com',
102        attachmentNote: '',
103      })
104  
105      expect(result.provider).toBe('web-fetch')
106      expect(result.text).toContain('**Example Page**')
107      expect(result.text).toContain('URL: https://example.com')
108      expect(result.text).toContain('*... content truncated*')
109      expect(result.text).toContain('*Content was truncated to 1234 bytes*')
110      expect(result.text).toContain('*Results from cache*')
111    })
112  
113    it('renders web fetch errors', async () => {
114      vi.mocked(executeWebFetchTool).mockResolvedValue({
115        ok: false,
116        error: 'fetch unavailable',
117      })
118  
119      const result = await runWebFetchSlashCommand({
120        url: 'https://example.com',
121        attachmentNote: '',
122      })
123  
124      expect(result).toEqual({
125        text: 'Web fetch failed: fetch unavailable',
126        provider: 'web-fetch',
127        mocked: false,
128      })
129    })
130  
131    it('renders web help text', () => {
132      const result = buildWebHelpSlashCommandResult({
133        attachmentNote: '\n\nNote: attachments ignored.',
134      })
135  
136      expect(result.provider).toBe('web-help')
137      expect(result.text).toContain('/websearch --image <query>')
138      expect(result.text).toContain('/webfetch <url>')
139      expect(result.text).toContain('Note: attachments ignored.')
140    })
141  })