|
1 | 1 | import { afterEach, beforeEach, describe, expect, it, type MockInstance, vi } from 'vitest' |
2 | 2 | import { ZohoDeskBlock } from '@/blocks/blocks/zoho-desk' |
| 3 | +import * as blockRegistry from '@/blocks/registry' |
3 | 4 | import { prepareToolExecution, transformBlockTool } from '@/providers/utils' |
| 5 | +import { prepareBlockState } from '@/stores/workflows/prepare-block-state' |
4 | 6 | import * as toolMetadata from '@/tools/metadata' |
5 | 7 | import { getSubBlocksForToolInput } from '@/tools/params' |
6 | 8 | import { zohoDeskCreateTicketTool } from '@/tools/zoho_desk/create_ticket' |
7 | 9 | import { zohoDeskListTicketsTool } from '@/tools/zoho_desk/list_tickets' |
| 10 | +import { zohoDeskSearchAccountsTool } from '@/tools/zoho_desk/search_accounts' |
| 11 | +import { zohoDeskSearchContactsTool } from '@/tools/zoho_desk/search_contacts' |
| 12 | +import { zohoDeskSearchTicketsTool } from '@/tools/zoho_desk/search_tickets' |
8 | 13 | import { zohoDeskSendReplyTool } from '@/tools/zoho_desk/send_reply' |
| 14 | +import { zohoDeskUpdateAccountTool } from '@/tools/zoho_desk/update_account' |
| 15 | +import { zohoDeskUpdateContactTool } from '@/tools/zoho_desk/update_contact' |
| 16 | +import { zohoDeskUpdateTicketTool } from '@/tools/zoho_desk/update_ticket' |
9 | 17 |
|
10 | 18 | let metadataSpy: MockInstance<typeof toolMetadata.getToolMetadata> |
11 | 19 |
|
12 | 20 | beforeEach(() => { |
13 | 21 | metadataSpy = vi |
14 | 22 | .spyOn(toolMetadata, 'getToolMetadata') |
15 | 23 | .mockImplementation((id) => |
16 | | - [zohoDeskCreateTicketTool, zohoDeskListTicketsTool, zohoDeskSendReplyTool].find( |
17 | | - (tool) => tool.id === id |
18 | | - ) |
| 24 | + [ |
| 25 | + zohoDeskCreateTicketTool, |
| 26 | + zohoDeskListTicketsTool, |
| 27 | + zohoDeskSendReplyTool, |
| 28 | + zohoDeskSearchTicketsTool, |
| 29 | + zohoDeskSearchContactsTool, |
| 30 | + zohoDeskSearchAccountsTool, |
| 31 | + ].find((tool) => tool.id === id) |
19 | 32 | ) |
20 | 33 | }) |
21 | 34 |
|
@@ -156,3 +169,109 @@ describe('Zoho Desk configured agent requests', () => { |
156 | 169 | expect(query.get('priority')).toBe('High') |
157 | 170 | }) |
158 | 171 | }) |
| 172 | + |
| 173 | +describe('Zoho Desk operation transitions', () => { |
| 174 | + it.each([ |
| 175 | + { |
| 176 | + operation: 'search_tickets', |
| 177 | + target: 'update_ticket', |
| 178 | + title: 'Subject', |
| 179 | + filter: 'billing*', |
| 180 | + replacement: { priority: 'High' }, |
| 181 | + buildBody: (params: Record<string, unknown>) => { |
| 182 | + const body = zohoDeskUpdateTicketTool.request.body |
| 183 | + if (typeof body !== 'function') throw new Error('Update body missing') |
| 184 | + return body({ |
| 185 | + accessToken: 'fixture', |
| 186 | + orgId: 'org-fixture', |
| 187 | + ticketId: 'ticket-fixture', |
| 188 | + ...params, |
| 189 | + }) |
| 190 | + }, |
| 191 | + }, |
| 192 | + { |
| 193 | + operation: 'search_contacts', |
| 194 | + target: 'update_contact', |
| 195 | + title: 'Email', |
| 196 | + filter: 'person*', |
| 197 | + replacement: { firstName: 'Updated' }, |
| 198 | + buildBody: (params: Record<string, unknown>) => { |
| 199 | + const body = zohoDeskUpdateContactTool.request.body |
| 200 | + if (typeof body !== 'function') throw new Error('Update body missing') |
| 201 | + return body({ |
| 202 | + accessToken: 'fixture', |
| 203 | + orgId: 'org-fixture', |
| 204 | + contactId: 'contact-fixture', |
| 205 | + ...params, |
| 206 | + }) |
| 207 | + }, |
| 208 | + }, |
| 209 | + { |
| 210 | + operation: 'search_accounts', |
| 211 | + target: 'update_account', |
| 212 | + title: 'Account Name', |
| 213 | + filter: 'Example*', |
| 214 | + replacement: { website: 'https://example.com' }, |
| 215 | + buildBody: (params: Record<string, unknown>) => { |
| 216 | + const body = zohoDeskUpdateAccountTool.request.body |
| 217 | + if (typeof body !== 'function') throw new Error('Update body missing') |
| 218 | + return body({ |
| 219 | + accessToken: 'fixture', |
| 220 | + orgId: 'org-fixture', |
| 221 | + accountId: 'account-fixture', |
| 222 | + ...params, |
| 223 | + }) |
| 224 | + }, |
| 225 | + }, |
| 226 | + ])( |
| 227 | + 'does not send retained $operation filters in a later update', |
| 228 | + ({ operation, target, title, filter, replacement, buildBody }) => { |
| 229 | + const editor = getSubBlocksForToolInput( |
| 230 | + `zoho_desk_${operation}`, |
| 231 | + 'zoho_desk', |
| 232 | + { operation }, |
| 233 | + undefined, |
| 234 | + ZohoDeskBlock |
| 235 | + ) |
| 236 | + const input = editor?.subBlocks.find((field) => field.title === title) |
| 237 | + if (!input) throw new Error(`Search input missing: ${title}`) |
| 238 | + const mapper = ZohoDeskBlock.tools.config?.params |
| 239 | + if (!mapper) throw new Error('Request mapping missing') |
| 240 | + const stored = { operation: target, [input.id]: filter, ...replacement } |
| 241 | + const mapped = mapper(stored) |
| 242 | + expect(buildBody(mapped)).toEqual(replacement) |
| 243 | + } |
| 244 | + ) |
| 245 | + |
| 246 | + it('does not send a webhook direction default in a newly created reply action', () => { |
| 247 | + vi.spyOn(blockRegistry, 'getBlock').mockReturnValue(ZohoDeskBlock) |
| 248 | + const state = prepareBlockState({ |
| 249 | + id: 'block-fixture', |
| 250 | + type: 'zoho_desk', |
| 251 | + name: 'Zoho Desk', |
| 252 | + position: { x: 0, y: 0 }, |
| 253 | + }) |
| 254 | + const mapper = ZohoDeskBlock.tools.config?.params |
| 255 | + const body = zohoDeskSendReplyTool.request.body |
| 256 | + if (!mapper || typeof body !== 'function') throw new Error('Reply mapping missing') |
| 257 | + const values = Object.fromEntries( |
| 258 | + Object.entries(state.subBlocks).map(([key, field]) => [key, field.value]) |
| 259 | + ) |
| 260 | + const mapped = mapper({ |
| 261 | + ...values, |
| 262 | + operation: 'send_reply', |
| 263 | + content: 'Reply', |
| 264 | + fromEmailAddress: 'support@example.com', |
| 265 | + }) |
| 266 | + expect( |
| 267 | + body({ |
| 268 | + accessToken: 'fixture', |
| 269 | + orgId: 'org-fixture', |
| 270 | + ticketId: 'ticket-fixture', |
| 271 | + content: '', |
| 272 | + fromEmailAddress: '', |
| 273 | + ...mapped, |
| 274 | + }) |
| 275 | + ).not.toHaveProperty('direction') |
| 276 | + }) |
| 277 | +}) |
0 commit comments