grokBotImport.test.ts 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. import {it,expect} from 'vitest'
  2. import {parseGrokBotPage,grokBotDraft,fetchGrokBotPage,GrokBotImportError} from '../../src/shared/grokBotImport'
  3. const tradbotHtml=`<!doctype html><html><head>
  4. <meta property="og:title" content="Tradbot">
  5. <meta property="og:description" content="Watches your personal email and calendar so school forms, bills, and RSVPs don't slip. Drafts the reply, catches the pickup clash, and never sends without you.">
  6. <meta property="og:image" content="https://x.ai/og/tradbot.png">
  7. </head><body></body></html>`
  8. const managerHtml=tradbotHtml.replace('Tradbot','Projects Manager').replace(/content="Watches[^"]*"/,'content="Runs your team\'s projects from Notion: one row per project, a channel per project, and tasks your specialist bots claim."')
  9. it('parses og metadata from a bot page',()=>{
  10. const meta=parseGrokBotPage(tradbotHtml)!
  11. expect(meta.name).toBe('Tradbot')
  12. expect(meta.description).toContain('never sends without you')
  13. expect(meta.imageUrl).toBe('https://x.ai/og/tradbot.png')
  14. })
  15. it('maps a housekeeper description onto the adapted template',()=>{
  16. const draft=grokBotDraft(parseGrokBotPage(tradbotHtml)!)
  17. expect(draft.kind).toBe('housekeeper')
  18. expect(draft.antiJobs).toContain('绝不直接发送邮件或回复邀请')
  19. expect(draft.instructions).toContain('desktop_shell')
  20. expect(draft.instructions).toContain('Tradbot')
  21. expect(draft.suggestions.join()).toContain('定时任务')
  22. })
  23. it('maps a manager description onto the team template',()=>{
  24. const draft=grokBotDraft(parseGrokBotPage(managerHtml)!)
  25. expect(draft.kind).toBe('manager')
  26. expect(draft.canManageTeam).toBe(true)
  27. expect(draft.job).toContain('任务计划')
  28. expect(draft.antiJobs).toContain('绝不替专家 Bot 完成具体工作')
  29. })
  30. it('validates the x.ai bot URL before fetching',async()=>{
  31. await expect(fetchGrokBotPage('https://example.com/bot/x')).rejects.toMatchObject({code:'invalid_grok_bot_url'})
  32. })
  33. it('rejects pages without bot metadata',async()=>{
  34. const fake=(async()=>new Response('<html><body>login</body></html>',{status:200})) as unknown as typeof fetch
  35. await expect(fetchGrokBotPage('https://x.ai/bot/_abc',fake)).rejects.toBeInstanceOf(GrokBotImportError)
  36. })
  37. it('fetches and parses through an injected fetch implementation',async()=>{
  38. const fake=(async()=>new Response(tradbotHtml,{status:200,headers:{'content-type':'text/html'}})) as unknown as typeof fetch
  39. const html=await fetchGrokBotPage('https://x.ai/bot/_abc',fake)
  40. expect(parseGrokBotPage(html)!.name).toBe('Tradbot')
  41. })