|
2 | 2 | * @vitest-environment node |
3 | 3 | */ |
4 | 4 | import { renderToStaticMarkup } from 'react-dom/server' |
5 | | -import { describe, expect, it, vi } from 'vitest' |
| 5 | +import { beforeEach, describe, expect, it, vi } from 'vitest' |
| 6 | +import type { SubBlockConfig } from '@/blocks/types' |
6 | 7 |
|
7 | | -const { fetched } = vi.hoisted(() => ({ |
| 8 | +const { fetched, editor } = vi.hoisted(() => ({ |
| 9 | + editor: { |
| 10 | + blocks: {} as Record<string, unknown>, |
| 11 | + values: {} as Record<string, unknown>, |
| 12 | + subBlocks: [] as SubBlockConfig[], |
| 13 | + credentials: {} as Record<string, { type: 'oauth' | 'service_account' }>, |
| 14 | + }, |
8 | 15 | fetched: { |
9 | 16 | options: [ |
10 | 17 | { id: 'col_a', label: 'Email' }, |
11 | 18 | { id: 'col_b', label: 'Name' }, |
12 | 19 | ] as { id: string; label: string }[], |
| 20 | + isDynamic: true, |
13 | 21 | isLoadingOptions: false, |
14 | 22 | hasLoadedOptions: true, |
15 | 23 | fetchError: null as string | null, |
@@ -49,7 +57,7 @@ vi.mock( |
49 | 57 | () => ({ |
50 | 58 | useFetchedOptions: () => ({ |
51 | 59 | fetchedOptions: fetched.options, |
52 | | - isDynamic: true, |
| 60 | + isDynamic: fetched.isDynamic, |
53 | 61 | isLoadingOptions: fetched.isLoadingOptions, |
54 | 62 | hasLoadedOptions: fetched.hasLoadedOptions, |
55 | 63 | fetchError: fetched.fetchError, |
@@ -88,17 +96,28 @@ vi.mock('@/hooks/use-operation-access', () => ({ |
88 | 96 | })) |
89 | 97 | vi.mock('@/executor/handlers/response/response-handler', () => ({ ResponseBlockHandler: {} })) |
90 | 98 | vi.mock('@/stores/workflows/workflow/store', () => ({ |
91 | | - useWorkflowStore: (selector: (state: unknown) => unknown) => selector({ blocks: {} }), |
| 99 | + useWorkflowStore: (selector: (state: unknown) => unknown) => selector({ blocks: editor.blocks }), |
92 | 100 | })) |
93 | 101 | vi.mock('@/stores/workflows/registry/store', () => ({ |
94 | 102 | useWorkflowRegistry: (selector: (state: unknown) => unknown) => |
95 | 103 | selector({ activeWorkflowId: 'wf-1', hydration: { workspaceId: 'workspace-1' } }), |
96 | 104 | })) |
97 | 105 | vi.mock('@/stores/workflows/subblock/store', () => ({ |
98 | | - useSubBlockStore: (selector: (state: unknown) => unknown) => selector({ workflowValues: {} }), |
| 106 | + EMPTY_BLOCK_SUBBLOCK_VALUES: {}, |
| 107 | + useSubBlockStore: (selector: (state: unknown) => unknown) => |
| 108 | + selector({ workflowValues: { 'wf-1': { 'block-1': editor.values } } }), |
| 109 | +})) |
| 110 | + |
| 111 | +vi.mock('@/blocks/registry', () => ({ |
| 112 | + getBlock: () => ({ subBlocks: editor.subBlocks }), |
| 113 | +})) |
| 114 | +vi.mock('@/hooks/queries/credentials', () => ({ |
| 115 | + useWorkspaceCredential: (id?: string) => ({ data: id ? editor.credentials[id] : undefined }), |
99 | 116 | })) |
100 | 117 |
|
101 | 118 | import { Dropdown } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown' |
| 119 | +import { slackOAuthTrigger } from '@/triggers/slack/oauth' |
| 120 | +import { SLACK_ALL_EVENT_OPTIONS } from '@/triggers/slack/shared' |
102 | 121 |
|
103 | 122 | function render(): string { |
104 | 123 | return renderToStaticMarkup( |
@@ -180,3 +199,64 @@ describe('Dropdown multi-select stale selections', () => { |
180 | 199 | } |
181 | 200 | }) |
182 | 201 | }) |
| 202 | + |
| 203 | +describe('Slack event credential options', () => { |
| 204 | + beforeEach(() => { |
| 205 | + fetched.isDynamic = false |
| 206 | + editor.subBlocks = slackOAuthTrigger.subBlocks |
| 207 | + editor.credentials = { |
| 208 | + native: { type: 'oauth' }, |
| 209 | + custom: { type: 'service_account' }, |
| 210 | + } |
| 211 | + editor.values = {} |
| 212 | + editor.blocks = { |
| 213 | + 'block-1': { type: 'slack_v2', triggerMode: true, data: { canonicalModes: {} } }, |
| 214 | + } |
| 215 | + }) |
| 216 | + |
| 217 | + function renderEvents() { |
| 218 | + return renderToStaticMarkup( |
| 219 | + <Dropdown |
| 220 | + blockId='block-1' |
| 221 | + subBlockId='eventType' |
| 222 | + options={[...SLACK_ALL_EVENT_OPTIONS]} |
| 223 | + value='message' |
| 224 | + /> |
| 225 | + ) |
| 226 | + } |
| 227 | + |
| 228 | + it.each([ |
| 229 | + ['native', true], |
| 230 | + ['custom', false], |
| 231 | + ['unresolved', false], |
| 232 | + ['', false], |
| 233 | + ])('shows native Assistant options only for a resolved OAuth credential (%s)', (id, visible) => { |
| 234 | + editor.values = { customBotCredential: id } |
| 235 | + const html = renderEvents() |
| 236 | + for (const event of ['assistant_thread_started', 'assistant_thread_context_changed']) { |
| 237 | + expect(html.includes(`data-value="${event}"`)).toBe(visible) |
| 238 | + } |
| 239 | + expect(html).toContain('data-value="message"') |
| 240 | + expect(html).toContain('data-value="agent_session_stopped"') |
| 241 | + }) |
| 242 | + |
| 243 | + it.each([ |
| 244 | + ['basic', 'native', 'custom', true], |
| 245 | + ['basic', 'custom', 'native', false], |
| 246 | + ['advanced', 'custom', 'native', true], |
| 247 | + ['advanced', 'native', 'custom', false], |
| 248 | + ])( |
| 249 | + 'uses the active %s credential rather than its stale counterpart', |
| 250 | + (mode, basic, advanced, visible) => { |
| 251 | + editor.blocks = { |
| 252 | + 'block-1': { |
| 253 | + type: 'slack_v2', |
| 254 | + triggerMode: true, |
| 255 | + data: { canonicalModes: { botCredential: mode } }, |
| 256 | + }, |
| 257 | + } |
| 258 | + editor.values = { customBotCredential: basic, manualBotCredential: advanced } |
| 259 | + expect(renderEvents().includes('data-value="assistant_thread_started"')).toBe(visible) |
| 260 | + } |
| 261 | + ) |
| 262 | +}) |
0 commit comments