get-execution.test.tsβ’11.7 kB
/**
* Integration Tests: handleGetExecution
*
* Tests execution retrieval against a real n8n instance.
* Covers all retrieval modes, filtering options, and error handling.
*/
import { describe, it, expect, beforeAll } from 'vitest';
import { createMcpContext } from '../utils/mcp-context';
import { InstanceContext } from '../../../../src/types/instance-context';
import { handleGetExecution, handleTriggerWebhookWorkflow } from '../../../../src/mcp/handlers-n8n-manager';
import { getN8nCredentials } from '../utils/credentials';
describe('Integration: handleGetExecution', () => {
let mcpContext: InstanceContext;
let executionId: string;
let webhookUrl: string;
beforeAll(async () => {
mcpContext = createMcpContext();
const creds = getN8nCredentials();
webhookUrl = creds.webhookUrls.get;
// Trigger a webhook to create an execution for testing
const triggerResponse = await handleTriggerWebhookWorkflow(
{
webhookUrl,
httpMethod: 'GET',
waitForResponse: true
},
mcpContext
);
// Extract execution ID from the response
if (triggerResponse.success && triggerResponse.data) {
const responseData = triggerResponse.data as any;
// Try to get execution ID from various possible locations
executionId = responseData.executionId ||
responseData.id ||
responseData.execution?.id ||
responseData.workflowData?.executionId;
if (!executionId) {
// If no execution ID in response, we'll use error handling tests
console.warn('Could not extract execution ID from webhook response');
}
}
}, 30000);
// ======================================================================
// Preview Mode
// ======================================================================
describe('Preview Mode', () => {
it('should get execution in preview mode (structure only)', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'preview'
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
// Preview mode should return structure and counts
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
// Should have basic execution info
if (data.status) {
expect(['success', 'error', 'running', 'waiting']).toContain(data.status);
}
});
});
// ======================================================================
// Summary Mode (Default)
// ======================================================================
describe('Summary Mode', () => {
it('should get execution in summary mode (2 samples per node)', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'summary'
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
it('should default to summary mode when mode not specified', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
});
// ======================================================================
// Filtered Mode
// ======================================================================
describe('Filtered Mode', () => {
it('should get execution with custom items limit', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'filtered',
itemsLimit: 5
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
it('should get execution with itemsLimit 0 (structure only)', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'filtered',
itemsLimit: 0
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
it('should get execution with unlimited items (itemsLimit: -1)', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'filtered',
itemsLimit: -1
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
it('should get execution filtered by node names', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'filtered',
nodeNames: ['Webhook']
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
});
// ======================================================================
// Full Mode
// ======================================================================
describe('Full Mode', () => {
it('should get complete execution data', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'full'
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
// Full mode should include complete execution data
if (data.data) {
expect(typeof data.data).toBe('object');
}
});
});
// ======================================================================
// Input Data Inclusion
// ======================================================================
describe('Input Data Inclusion', () => {
it('should include input data when requested', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'summary',
includeInputData: true
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
it('should exclude input data by default', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'summary',
includeInputData: false
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
});
// ======================================================================
// Legacy Parameter Compatibility
// ======================================================================
describe('Legacy Parameter Compatibility', () => {
it('should support legacy includeData parameter', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
includeData: true
},
mcpContext
);
expect(response.success).toBe(true);
const data = response.data as any;
expect(data).toBeDefined();
expect(data.id).toBe(executionId);
});
});
// ======================================================================
// Error Handling
// ======================================================================
describe('Error Handling', () => {
it('should handle non-existent execution ID', async () => {
const response = await handleGetExecution(
{
id: '99999999'
},
mcpContext
);
expect(response.success).toBe(false);
expect(response.error).toBeDefined();
});
it('should handle invalid execution ID format', async () => {
const response = await handleGetExecution(
{
id: 'invalid-id-format'
},
mcpContext
);
expect(response.success).toBe(false);
expect(response.error).toBeDefined();
});
it('should handle missing execution ID', async () => {
const response = await handleGetExecution(
{} as any,
mcpContext
);
expect(response.success).toBe(false);
expect(response.error).toBeDefined();
});
it('should handle invalid mode parameter', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'invalid-mode' as any
},
mcpContext
);
expect(response.success).toBe(false);
expect(response.error).toBeDefined();
});
});
// ======================================================================
// Response Format Verification
// ======================================================================
describe('Response Format', () => {
it('should return complete execution response structure', async () => {
if (!executionId) {
console.warn('Skipping test: No execution ID available');
return;
}
const response = await handleGetExecution(
{
id: executionId,
mode: 'summary'
},
mcpContext
);
expect(response.success).toBe(true);
expect(response.data).toBeDefined();
const data = response.data as any;
expect(data.id).toBeDefined();
// Should have execution metadata
if (data.status) {
expect(typeof data.status).toBe('string');
}
if (data.mode) {
expect(typeof data.mode).toBe('string');
}
if (data.startedAt) {
expect(typeof data.startedAt).toBe('string');
}
});
});
});