Skip to content

Commit a544293

Browse files
waleedlatif1claude
andcommitted
test(console-store): cover blockExecutionId keying and idempotency
Locks in the new console store invariants: - Primary lookup via entryIdByBlockExecutionId fires no legacy warn - Unknown blockExecutionId falls back to legacy keying and warns - No-blockExecutionId updates use legacy path silently - addConsole twice with same blockExecutionId returns the existing entry - Distinct blockExecutionIds (loop iterations) produce distinct entries Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b442f6f commit a544293

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

apps/sim/stores/terminal/console/store.test.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
/**
22
* @vitest-environment node
33
*/
4+
import { createLogger } from '@sim/logger'
45
import { beforeEach, describe, expect, it, vi } from 'vitest'
56

67
vi.unmock('@/stores/terminal')
78
vi.unmock('@/stores/terminal/console/store')
89

910
import { useTerminalConsoleStore } from '@/stores/terminal/console/store'
1011

12+
const storeLogger = vi
13+
.mocked(createLogger)
14+
.mock.results.map((result) => result.value)
15+
.find((value) => value && typeof value.warn === 'function')
16+
1117
describe('terminal console store', () => {
1218
beforeEach(() => {
1319
useTerminalConsoleStore.setState({
1420
workflowEntries: {},
1521
entryIdsByBlockExecution: {},
22+
entryIdByBlockExecutionId: {},
1623
entryLocationById: {},
1724
isOpen: false,
1825
_hasHydrated: true,
1926
})
27+
storeLogger?.warn.mockClear()
2028
})
2129

2230
it('normalizes oversized payloads when adding console entries', () => {
@@ -117,6 +125,148 @@ describe('terminal console store', () => {
117125
expect(after.getWorkflowEntries('wf-1')[0].output).toMatchObject({ status: 'updated' })
118126
})
119127

128+
describe('blockExecutionId keying', () => {
129+
it('updates an entry via the primary index without firing legacy warn', () => {
130+
useTerminalConsoleStore.getState().addConsole({
131+
workflowId: 'wf-1',
132+
blockId: 'block-1',
133+
blockName: 'Function',
134+
blockType: 'function',
135+
executionId: 'exec-1',
136+
blockExecutionId: 'bex-1',
137+
executionOrder: 1,
138+
isRunning: true,
139+
})
140+
141+
useTerminalConsoleStore.getState().updateConsole(
142+
'block-1',
143+
{
144+
executionOrder: 1,
145+
blockExecutionId: 'bex-1',
146+
success: true,
147+
replaceOutput: { status: 'done' },
148+
},
149+
'exec-1'
150+
)
151+
152+
const [entry] = useTerminalConsoleStore.getState().getWorkflowEntries('wf-1')
153+
expect(entry.success).toBe(true)
154+
expect(entry.output).toMatchObject({ status: 'done' })
155+
expect(storeLogger?.warn).not.toHaveBeenCalled()
156+
})
157+
158+
it('falls back to legacy keying and warns when blockExecutionId is unknown', () => {
159+
useTerminalConsoleStore.getState().addConsole({
160+
workflowId: 'wf-1',
161+
blockId: 'block-1',
162+
blockName: 'Function',
163+
blockType: 'function',
164+
executionId: 'exec-1',
165+
executionOrder: 1,
166+
isRunning: true,
167+
})
168+
169+
useTerminalConsoleStore.getState().updateConsole(
170+
'block-1',
171+
{
172+
executionOrder: 1,
173+
blockExecutionId: 'bex-unknown',
174+
success: true,
175+
replaceOutput: { status: 'done' },
176+
},
177+
'exec-1'
178+
)
179+
180+
const [entry] = useTerminalConsoleStore.getState().getWorkflowEntries('wf-1')
181+
expect(entry.success).toBe(true)
182+
expect(storeLogger?.warn).toHaveBeenCalledWith(
183+
'updateConsole used legacy keying (hydrated or cross-deploy entry)',
184+
expect.objectContaining({ blockExecutionId: 'bex-unknown', blockId: 'block-1' })
185+
)
186+
})
187+
188+
it('uses legacy keying without warning when no blockExecutionId is provided', () => {
189+
useTerminalConsoleStore.getState().addConsole({
190+
workflowId: 'wf-1',
191+
blockId: 'block-1',
192+
blockName: 'Function',
193+
blockType: 'function',
194+
executionId: 'exec-1',
195+
executionOrder: 1,
196+
isRunning: true,
197+
})
198+
199+
useTerminalConsoleStore
200+
.getState()
201+
.updateConsole(
202+
'block-1',
203+
{ executionOrder: 1, success: true, replaceOutput: { status: 'done' } },
204+
'exec-1'
205+
)
206+
207+
const [entry] = useTerminalConsoleStore.getState().getWorkflowEntries('wf-1')
208+
expect(entry.success).toBe(true)
209+
expect(storeLogger?.warn).not.toHaveBeenCalled()
210+
})
211+
})
212+
213+
describe('addConsole idempotency', () => {
214+
it('returns the existing entry when called twice with the same blockExecutionId', () => {
215+
const first = useTerminalConsoleStore.getState().addConsole({
216+
workflowId: 'wf-1',
217+
blockId: 'block-1',
218+
blockName: 'Function',
219+
blockType: 'function',
220+
executionId: 'exec-1',
221+
blockExecutionId: 'bex-1',
222+
executionOrder: 1,
223+
isRunning: true,
224+
})
225+
226+
const second = useTerminalConsoleStore.getState().addConsole({
227+
workflowId: 'wf-1',
228+
blockId: 'block-1',
229+
blockName: 'Function',
230+
blockType: 'function',
231+
executionId: 'exec-1',
232+
blockExecutionId: 'bex-1',
233+
executionOrder: 1,
234+
isRunning: true,
235+
})
236+
237+
const entries = useTerminalConsoleStore.getState().getWorkflowEntries('wf-1')
238+
expect(entries).toHaveLength(1)
239+
expect(second?.id).toBe(first?.id)
240+
})
241+
242+
it('creates distinct entries for different blockExecutionIds (loop iterations)', () => {
243+
useTerminalConsoleStore.getState().addConsole({
244+
workflowId: 'wf-1',
245+
blockId: 'block-1',
246+
blockName: 'Function',
247+
blockType: 'function',
248+
executionId: 'exec-1',
249+
blockExecutionId: 'bex-iter-1',
250+
executionOrder: 1,
251+
isRunning: true,
252+
})
253+
254+
useTerminalConsoleStore.getState().addConsole({
255+
workflowId: 'wf-1',
256+
blockId: 'block-1',
257+
blockName: 'Function',
258+
blockType: 'function',
259+
executionId: 'exec-1',
260+
blockExecutionId: 'bex-iter-2',
261+
executionOrder: 2,
262+
isRunning: true,
263+
})
264+
265+
const entries = useTerminalConsoleStore.getState().getWorkflowEntries('wf-1')
266+
expect(entries).toHaveLength(2)
267+
})
268+
})
269+
120270
describe('cancelRunningEntries', () => {
121271
it('flips a plain running entry to canceled', () => {
122272
useTerminalConsoleStore.getState().addConsole({

0 commit comments

Comments
 (0)