d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
315 lines
9.4 KiB
TypeScript
315 lines
9.4 KiB
TypeScript
import '@sim/testing/mocks/executor'
|
|
|
|
import { beforeEach, describe, expect, it } from 'vitest'
|
|
import { TriggerBlockHandler } from '@/executor/handlers/trigger/trigger-handler'
|
|
import type { ExecutionContext } from '@/executor/types'
|
|
import type { SerializedBlock } from '@/serializer/types'
|
|
|
|
describe('TriggerBlockHandler', () => {
|
|
let handler: TriggerBlockHandler
|
|
let mockContext: ExecutionContext
|
|
|
|
beforeEach(() => {
|
|
handler = new TriggerBlockHandler()
|
|
|
|
mockContext = {
|
|
workflowId: 'test-workflow-id',
|
|
blockStates: new Map(),
|
|
blockLogs: [],
|
|
metadata: { duration: 0 },
|
|
environmentVariables: {},
|
|
decisions: { router: new Map(), condition: new Map() },
|
|
loopExecutions: new Map(),
|
|
executedBlocks: new Set(),
|
|
activeExecutionPath: new Set(),
|
|
completedLoops: new Set(),
|
|
}
|
|
})
|
|
|
|
describe('canHandle', () => {
|
|
it.concurrent('should handle blocks with triggers category', () => {
|
|
const triggerBlock: SerializedBlock = {
|
|
id: 'trigger-1',
|
|
metadata: { id: 'schedule', name: 'Schedule Block', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'schedule', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
expect(handler.canHandle(triggerBlock)).toBe(true)
|
|
})
|
|
|
|
it.concurrent('should handle blocks with triggerMode enabled', () => {
|
|
const gmailTriggerBlock: SerializedBlock = {
|
|
id: 'gmail-1',
|
|
metadata: { id: 'gmail', name: 'Gmail Block', category: 'tools' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'gmail', params: { triggerMode: true } },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
expect(handler.canHandle(gmailTriggerBlock)).toBe(true)
|
|
})
|
|
|
|
it.concurrent('should not handle regular tool blocks without triggerMode', () => {
|
|
const toolBlock: SerializedBlock = {
|
|
id: 'tool-1',
|
|
metadata: { id: 'gmail', name: 'Gmail Block', category: 'tools' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'gmail', params: { triggerMode: false } },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
expect(handler.canHandle(toolBlock)).toBe(false)
|
|
})
|
|
|
|
it.concurrent('should not handle blocks without trigger indicators', () => {
|
|
const regularBlock: SerializedBlock = {
|
|
id: 'regular-1',
|
|
metadata: { id: 'api', name: 'API Block', category: 'tools' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'api', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
expect(handler.canHandle(regularBlock)).toBe(false)
|
|
})
|
|
|
|
it.concurrent('should handle generic webhook blocks', () => {
|
|
const webhookBlock: SerializedBlock = {
|
|
id: 'webhook-1',
|
|
metadata: { id: 'generic_webhook', name: 'Generic Webhook', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'generic_webhook', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
expect(handler.canHandle(webhookBlock)).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('execute', () => {
|
|
it.concurrent('should return inputs directly when provided', async () => {
|
|
const triggerBlock: SerializedBlock = {
|
|
id: 'trigger-1',
|
|
metadata: { id: 'gmail', name: 'Gmail Trigger', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'gmail', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
const triggerInputs = {
|
|
email: {
|
|
id: '12345',
|
|
subject: 'Test Email',
|
|
from: 'test@example.com',
|
|
body: 'Hello world',
|
|
},
|
|
timestamp: '2023-01-01T12:00:00Z',
|
|
}
|
|
|
|
const result = await handler.execute(mockContext, triggerBlock, triggerInputs)
|
|
|
|
expect(result).toEqual(triggerInputs)
|
|
})
|
|
|
|
it.concurrent('should return empty object when no inputs provided', async () => {
|
|
const triggerBlock: SerializedBlock = {
|
|
id: 'trigger-1',
|
|
metadata: { id: 'schedule', name: 'Schedule Trigger', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'schedule', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
const result = await handler.execute(mockContext, triggerBlock, {})
|
|
|
|
expect(result).toEqual({})
|
|
})
|
|
|
|
it.concurrent('should handle webhook payload inputs', async () => {
|
|
const webhookBlock: SerializedBlock = {
|
|
id: 'webhook-1',
|
|
metadata: { id: 'generic_webhook', name: 'Generic Webhook', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'generic_webhook', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
const webhookInputs = {
|
|
webhook: {
|
|
data: {
|
|
provider: 'github',
|
|
payload: { event: 'push', repo: 'test-repo' },
|
|
},
|
|
},
|
|
}
|
|
|
|
const result = await handler.execute(mockContext, webhookBlock, webhookInputs)
|
|
|
|
expect(result).toEqual(webhookInputs)
|
|
})
|
|
|
|
it.concurrent('should handle Outlook trigger inputs', async () => {
|
|
const outlookBlock: SerializedBlock = {
|
|
id: 'outlook-1',
|
|
metadata: { id: 'outlook', name: 'Outlook Block', category: 'tools' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'outlook', params: { triggerMode: true } },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
const outlookInputs = {
|
|
email: {
|
|
id: 'outlook123',
|
|
subject: 'Meeting Invitation',
|
|
from: 'colleague@company.com',
|
|
bodyPreview: 'Join us for the quarterly review...',
|
|
},
|
|
timestamp: '2023-01-01T14:30:00Z',
|
|
}
|
|
|
|
const result = await handler.execute(mockContext, outlookBlock, outlookInputs)
|
|
|
|
expect(result).toEqual(outlookInputs)
|
|
})
|
|
|
|
it.concurrent('should handle schedule trigger with no inputs', async () => {
|
|
const scheduleBlock: SerializedBlock = {
|
|
id: 'schedule-1',
|
|
metadata: { id: 'schedule', name: 'Daily Schedule', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'schedule', params: { scheduleType: 'daily' } },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
const result = await handler.execute(mockContext, scheduleBlock, {})
|
|
|
|
expect(result).toEqual({})
|
|
})
|
|
|
|
it.concurrent('should handle complex nested trigger data', async () => {
|
|
const triggerBlock: SerializedBlock = {
|
|
id: 'complex-trigger-1',
|
|
metadata: { id: 'webhook', name: 'Complex Webhook', category: 'triggers' },
|
|
position: { x: 0, y: 0 },
|
|
config: { tool: 'webhook', params: {} },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
}
|
|
|
|
const complexInputs = {
|
|
webhook: {
|
|
data: {
|
|
provider: 'github',
|
|
payload: {
|
|
action: 'opened',
|
|
pull_request: {
|
|
id: 123,
|
|
title: 'Fix bug in authentication',
|
|
user: { login: 'developer' },
|
|
base: { ref: 'main' },
|
|
head: { ref: 'fix-auth-bug' },
|
|
},
|
|
},
|
|
headers: { 'x-github-event': 'pull_request' },
|
|
},
|
|
},
|
|
timestamp: '2023-01-01T15:45:00Z',
|
|
}
|
|
|
|
const result = await handler.execute(mockContext, triggerBlock, complexInputs)
|
|
|
|
expect(result).toEqual(complexInputs)
|
|
})
|
|
})
|
|
|
|
describe('integration scenarios', () => {
|
|
it.concurrent('should work with different trigger block types', () => {
|
|
const testCases = [
|
|
{
|
|
name: 'Gmail in trigger mode',
|
|
block: {
|
|
id: 'gmail-trigger',
|
|
metadata: { id: 'gmail', category: 'tools' },
|
|
config: { tool: 'gmail', params: { triggerMode: true } },
|
|
},
|
|
shouldHandle: true,
|
|
},
|
|
{
|
|
name: 'Generic webhook',
|
|
block: {
|
|
id: 'webhook-trigger',
|
|
metadata: { id: 'generic_webhook', category: 'triggers' },
|
|
config: { tool: 'generic_webhook', params: {} },
|
|
},
|
|
shouldHandle: true,
|
|
},
|
|
{
|
|
name: 'Schedule block',
|
|
block: {
|
|
id: 'schedule-trigger',
|
|
metadata: { id: 'schedule', category: 'triggers' },
|
|
config: { tool: 'schedule', params: {} },
|
|
},
|
|
shouldHandle: true,
|
|
},
|
|
{
|
|
name: 'Regular API block',
|
|
block: {
|
|
id: 'api-block',
|
|
metadata: { id: 'api', category: 'tools' },
|
|
config: { tool: 'api', params: {} },
|
|
},
|
|
shouldHandle: false,
|
|
},
|
|
{
|
|
name: 'Gmail in tool mode',
|
|
block: {
|
|
id: 'gmail-tool',
|
|
metadata: { id: 'gmail', category: 'tools' },
|
|
config: { tool: 'gmail', params: { triggerMode: false } },
|
|
},
|
|
shouldHandle: false,
|
|
},
|
|
]
|
|
|
|
testCases.forEach(({ name, block, shouldHandle }) => {
|
|
const serializedBlock: SerializedBlock = {
|
|
...block,
|
|
position: { x: 0, y: 0 },
|
|
inputs: {},
|
|
outputs: {},
|
|
enabled: true,
|
|
} as SerializedBlock
|
|
|
|
expect(
|
|
handler.canHandle(serializedBlock),
|
|
`${name} should ${shouldHandle ? '' : 'not '}be handled`
|
|
).toBe(shouldHandle)
|
|
})
|
|
})
|
|
})
|
|
})
|