mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
* feat(logs): add additional metadata for workflow execution logs
* Revert "Feat(logs) upgrade mothership chat messages to error (#3772)"
This reverts commit 9d1b9763c5.
* Fix lint, address greptile comments
* improvement(sidebar): expand sidebar by hovering and clicking the edge (#3830)
* improvement(sidebar): expand sidebar by hovering and clicking the edge
* improvement(sidebar): add keyboard shortcuts for new workflow/task, center search modal, fix edge ARIA
* improvement(sidebar): use Tooltip.Shortcut for inline shortcut display
* fix(sidebar): change new workflow shortcut from Mod+Shift+W to Mod+Shift+P to avoid browser close-window conflict
* fix(hotkeys): fall back to event.code for international keyboard layout compatibility
* fix(sidebar): guard add-workflow shortcut with canEdit and isCreatingWorkflow checks
* feat(ui): handle image paste (#3826)
* feat(ui): handle image paste
* Fix lint
* Fix type error
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* feat(files): interactive markdown checkbox toggling in preview (#3829)
* feat(files): interactive markdown checkbox toggling in preview
* fix(files): handle ordered-list checkboxes and fix index drift
* lint
* fix(files): remove counter offset that prevented checkbox toggling
* fix(files): apply task-list styling to ordered lists too
* fix(files): render single pass when interactive to avoid index drift
* fix(files): move useMemo above conditional return to fix Rules of Hooks
* fix(files): pass content directly to preview when not streaming to avoid stale frame
* improvement(home): position @ mention popup at caret and fix icon consistency (#3831)
* improvement(home): position @ mention popup at caret and fix icon consistency
* fix(home): pin mirror div to document origin and guard button anchor
* chore(auth): restore hybrid.ts to staging
* improvement(ui): sidebar (#3832)
* Fix logger tests
* Add metadata to mothership logs
---------
Co-authored-by: Theodore Li <theo@sim.ai>
Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: Theodore Li <theo@sim.ai>
172 lines
4.6 KiB
TypeScript
172 lines
4.6 KiB
TypeScript
/**
|
|
* @vitest-environment node
|
|
*/
|
|
|
|
import { createMockRequest } from '@sim/testing'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const {
|
|
mockCheckHybridAuth,
|
|
mockAuthorizeWorkflowByWorkspacePermission,
|
|
mockPreprocessExecution,
|
|
mockEnqueue,
|
|
mockEnqueueWorkspaceDispatch,
|
|
} = vi.hoisted(() => ({
|
|
mockCheckHybridAuth: vi.fn(),
|
|
mockAuthorizeWorkflowByWorkspacePermission: vi.fn(),
|
|
mockPreprocessExecution: vi.fn(),
|
|
mockEnqueue: vi.fn().mockResolvedValue('job-123'),
|
|
mockEnqueueWorkspaceDispatch: vi.fn().mockResolvedValue('job-123'),
|
|
}))
|
|
|
|
vi.mock('@/lib/auth/hybrid', () => ({
|
|
checkHybridAuth: mockCheckHybridAuth,
|
|
hasExternalApiCredentials: vi.fn().mockReturnValue(true),
|
|
AuthType: {
|
|
SESSION: 'session',
|
|
API_KEY: 'api_key',
|
|
INTERNAL_JWT: 'internal_jwt',
|
|
},
|
|
}))
|
|
|
|
vi.mock('@/lib/workflows/utils', () => ({
|
|
authorizeWorkflowByWorkspacePermission: mockAuthorizeWorkflowByWorkspacePermission,
|
|
createHttpResponseFromBlock: vi.fn(),
|
|
workflowHasResponseBlock: vi.fn().mockReturnValue(false),
|
|
}))
|
|
|
|
vi.mock('@/lib/execution/preprocessing', () => ({
|
|
preprocessExecution: mockPreprocessExecution,
|
|
}))
|
|
|
|
vi.mock('@/lib/core/async-jobs', () => ({
|
|
getJobQueue: vi.fn().mockResolvedValue({
|
|
enqueue: mockEnqueue,
|
|
startJob: vi.fn(),
|
|
completeJob: vi.fn(),
|
|
markJobFailed: vi.fn(),
|
|
}),
|
|
shouldExecuteInline: vi.fn().mockReturnValue(false),
|
|
shouldUseBullMQ: vi.fn().mockReturnValue(true),
|
|
}))
|
|
|
|
vi.mock('@/lib/core/bullmq', () => ({
|
|
createBullMQJobData: vi.fn((payload: unknown, metadata?: unknown) => ({ payload, metadata })),
|
|
}))
|
|
|
|
vi.mock('@/lib/core/workspace-dispatch', () => ({
|
|
enqueueWorkspaceDispatch: mockEnqueueWorkspaceDispatch,
|
|
waitForDispatchJob: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('@/lib/core/utils/request', () => ({
|
|
generateRequestId: vi.fn().mockReturnValue('req-12345678'),
|
|
}))
|
|
|
|
vi.mock('@/lib/core/utils/urls', () => ({
|
|
getBaseUrl: vi.fn().mockReturnValue('http://localhost:3000'),
|
|
}))
|
|
|
|
vi.mock('@/lib/execution/call-chain', () => ({
|
|
SIM_VIA_HEADER: 'x-sim-via',
|
|
parseCallChain: vi.fn().mockReturnValue([]),
|
|
validateCallChain: vi.fn().mockReturnValue(null),
|
|
buildNextCallChain: vi.fn().mockReturnValue(['workflow-1']),
|
|
}))
|
|
|
|
vi.mock('@/lib/logs/execution/logging-session', () => ({
|
|
LoggingSession: vi.fn().mockImplementation(() => ({})),
|
|
}))
|
|
|
|
vi.mock('@/background/workflow-execution', () => ({
|
|
executeWorkflowJob: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('@sim/logger', () => {
|
|
const createMockLogger = (): Record<string, any> => ({
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
debug: vi.fn(),
|
|
withMetadata: vi.fn(() => createMockLogger()),
|
|
})
|
|
return { createLogger: vi.fn(() => createMockLogger()) }
|
|
})
|
|
|
|
vi.mock('uuid', () => ({
|
|
validate: vi.fn().mockReturnValue(true),
|
|
v4: vi.fn().mockReturnValue('execution-123'),
|
|
}))
|
|
|
|
import { POST } from './route'
|
|
|
|
describe('workflow execute async route', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
|
|
mockCheckHybridAuth.mockResolvedValue({
|
|
success: true,
|
|
userId: 'session-user-1',
|
|
authType: 'session',
|
|
})
|
|
|
|
mockAuthorizeWorkflowByWorkspacePermission.mockResolvedValue({
|
|
allowed: true,
|
|
workflow: {
|
|
id: 'workflow-1',
|
|
userId: 'owner-1',
|
|
workspaceId: 'workspace-1',
|
|
},
|
|
})
|
|
|
|
mockPreprocessExecution.mockResolvedValue({
|
|
success: true,
|
|
actorUserId: 'actor-1',
|
|
workflowRecord: {
|
|
id: 'workflow-1',
|
|
userId: 'owner-1',
|
|
workspaceId: 'workspace-1',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('queues async execution with matching correlation metadata', async () => {
|
|
const req = createMockRequest(
|
|
'POST',
|
|
{ input: { hello: 'world' } },
|
|
{
|
|
'Content-Type': 'application/json',
|
|
'X-Execution-Mode': 'async',
|
|
}
|
|
)
|
|
const params = Promise.resolve({ id: 'workflow-1' })
|
|
|
|
const response = await POST(req as any, { params })
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(202)
|
|
expect(body.executionId).toBe('execution-123')
|
|
expect(body.jobId).toBe('job-123')
|
|
expect(mockEnqueueWorkspaceDispatch).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
id: 'execution-123',
|
|
workspaceId: 'workspace-1',
|
|
lane: 'runtime',
|
|
queueName: 'workflow-execution',
|
|
bullmqJobName: 'workflow-execution',
|
|
metadata: {
|
|
workflowId: 'workflow-1',
|
|
userId: 'actor-1',
|
|
correlation: {
|
|
executionId: 'execution-123',
|
|
requestId: 'req-12345678',
|
|
source: 'workflow',
|
|
workflowId: 'workflow-1',
|
|
triggerType: 'manual',
|
|
},
|
|
},
|
|
})
|
|
)
|
|
})
|
|
})
|