Initial commit of n8n MCP Server
A Model Context Protocol (MCP) server that integrates with n8n, providing tools for workflow and execution management via the n8n API.
This commit is contained in:
113
tests/mocks/axios-mock.ts
Normal file
113
tests/mocks/axios-mock.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Axios mock utilities for n8n MCP Server tests
|
||||
*/
|
||||
|
||||
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
|
||||
export interface MockResponse {
|
||||
data: any;
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers?: Record<string, string>;
|
||||
config?: AxiosRequestConfig;
|
||||
}
|
||||
|
||||
export const createMockAxiosResponse = (options: Partial<MockResponse> = {}): AxiosResponse => {
|
||||
return {
|
||||
data: options.data ?? {},
|
||||
status: options.status ?? 200,
|
||||
statusText: options.statusText ?? 'OK',
|
||||
headers: options.headers ?? {},
|
||||
config: options.config ?? {},
|
||||
} as AxiosResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a mock axios instance for testing
|
||||
*/
|
||||
export const createMockAxiosInstance = () => {
|
||||
const mockRequests: Record<string, any[]> = {};
|
||||
const mockResponses: Record<string, MockResponse[]> = {};
|
||||
|
||||
const mockInstance = {
|
||||
get: jest.fn(),
|
||||
post: jest.fn(),
|
||||
put: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
interceptors: {
|
||||
request: {
|
||||
use: jest.fn(),
|
||||
},
|
||||
response: {
|
||||
use: jest.fn(),
|
||||
},
|
||||
},
|
||||
defaults: {},
|
||||
|
||||
// Helper method to add mock response
|
||||
addMockResponse(method: string, url: string, response: MockResponse | Error) {
|
||||
if (!mockResponses[`${method}:${url}`]) {
|
||||
mockResponses[`${method}:${url}`] = [];
|
||||
}
|
||||
|
||||
if (response instanceof Error) {
|
||||
mockResponses[`${method}:${url}`].push(response as any);
|
||||
} else {
|
||||
mockResponses[`${method}:${url}`].push(response);
|
||||
}
|
||||
},
|
||||
|
||||
// Helper method to get request history
|
||||
getRequestHistory(method: string, url: string) {
|
||||
return mockRequests[`${method}:${url}`] || [];
|
||||
},
|
||||
|
||||
// Reset all mocks
|
||||
reset() {
|
||||
Object.keys(mockRequests).forEach(key => {
|
||||
delete mockRequests[key];
|
||||
});
|
||||
|
||||
Object.keys(mockResponses).forEach(key => {
|
||||
delete mockResponses[key];
|
||||
});
|
||||
|
||||
mockInstance.get.mockReset();
|
||||
mockInstance.post.mockReset();
|
||||
mockInstance.put.mockReset();
|
||||
mockInstance.delete.mockReset();
|
||||
}
|
||||
};
|
||||
|
||||
// Setup method implementations
|
||||
['get', 'post', 'put', 'delete'].forEach(method => {
|
||||
mockInstance[method].mockImplementation(async (url: string, data?: any) => {
|
||||
const requestKey = `${method}:${url}`;
|
||||
|
||||
if (!mockRequests[requestKey]) {
|
||||
mockRequests[requestKey] = [];
|
||||
}
|
||||
|
||||
mockRequests[requestKey].push(data);
|
||||
|
||||
if (mockResponses[requestKey] && mockResponses[requestKey].length > 0) {
|
||||
const response = mockResponses[requestKey].shift();
|
||||
|
||||
if (response instanceof Error) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
return createMockAxiosResponse(response);
|
||||
}
|
||||
|
||||
throw new Error(`No mock response defined for ${method.toUpperCase()} ${url}`);
|
||||
});
|
||||
});
|
||||
|
||||
return mockInstance;
|
||||
};
|
||||
|
||||
export default {
|
||||
createMockAxiosResponse,
|
||||
createMockAxiosInstance,
|
||||
};
|
||||
120
tests/mocks/n8n-fixtures.ts
Normal file
120
tests/mocks/n8n-fixtures.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Mock fixtures for n8n API responses
|
||||
*/
|
||||
|
||||
import { Workflow, Execution } from '../../src/types/index.js';
|
||||
|
||||
/**
|
||||
* Create a mock workflow for testing
|
||||
*/
|
||||
export const createMockWorkflow = (overrides: Partial<Workflow> = {}): Workflow => {
|
||||
const id = overrides.id ?? 'mock-workflow-1';
|
||||
|
||||
return {
|
||||
id,
|
||||
name: overrides.name ?? `Mock Workflow ${id}`,
|
||||
active: overrides.active ?? false,
|
||||
createdAt: overrides.createdAt ?? new Date().toISOString(),
|
||||
updatedAt: overrides.updatedAt ?? new Date().toISOString(),
|
||||
nodes: overrides.nodes ?? [
|
||||
{
|
||||
id: 'start',
|
||||
name: 'Start',
|
||||
type: 'n8n-nodes-base.start',
|
||||
parameters: {},
|
||||
position: [100, 300],
|
||||
},
|
||||
],
|
||||
connections: overrides.connections ?? {},
|
||||
settings: overrides.settings ?? {},
|
||||
staticData: overrides.staticData ?? null,
|
||||
pinData: overrides.pinData ?? {},
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Create multiple mock workflows
|
||||
*/
|
||||
export const createMockWorkflows = (count: number = 3): Workflow[] => {
|
||||
return Array.from({ length: count }, (_, i) =>
|
||||
createMockWorkflow({
|
||||
id: `mock-workflow-${i + 1}`,
|
||||
name: `Mock Workflow ${i + 1}`,
|
||||
active: i % 2 === 0, // Alternate active status
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a mock execution for testing
|
||||
*/
|
||||
export const createMockExecution = (overrides: Partial<Execution> = {}): Execution => {
|
||||
const id = overrides.id ?? 'mock-execution-1';
|
||||
const workflowId = overrides.workflowId ?? 'mock-workflow-1';
|
||||
|
||||
return {
|
||||
id,
|
||||
workflowId,
|
||||
finished: overrides.finished ?? true,
|
||||
mode: overrides.mode ?? 'manual',
|
||||
waitTill: overrides.waitTill ?? null,
|
||||
startedAt: overrides.startedAt ?? new Date().toISOString(),
|
||||
stoppedAt: overrides.stoppedAt ?? new Date().toISOString(),
|
||||
status: overrides.status ?? 'success',
|
||||
data: overrides.data ?? {
|
||||
resultData: {
|
||||
runData: {},
|
||||
},
|
||||
},
|
||||
workflowData: overrides.workflowData ?? createMockWorkflow({ id: workflowId }),
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Create multiple mock executions
|
||||
*/
|
||||
export const createMockExecutions = (count: number = 3): Execution[] => {
|
||||
return Array.from({ length: count }, (_, i) =>
|
||||
createMockExecution({
|
||||
id: `mock-execution-${i + 1}`,
|
||||
workflowId: `mock-workflow-${(i % 2) + 1}`, // Alternate between two workflows
|
||||
status: i % 3 === 0 ? 'success' : i % 3 === 1 ? 'error' : 'waiting',
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create mock n8n API responses
|
||||
*/
|
||||
export const mockApiResponses = {
|
||||
workflows: {
|
||||
list: {
|
||||
data: createMockWorkflows(),
|
||||
},
|
||||
single: (id: string = 'mock-workflow-1') => createMockWorkflow({ id }),
|
||||
create: (workflow: Partial<Workflow> = {}) => createMockWorkflow(workflow),
|
||||
update: (id: string = 'mock-workflow-1', workflow: Partial<Workflow> = {}) =>
|
||||
createMockWorkflow({ ...workflow, id }),
|
||||
delete: { success: true },
|
||||
activate: (id: string = 'mock-workflow-1') => createMockWorkflow({ id, active: true }),
|
||||
deactivate: (id: string = 'mock-workflow-1') => createMockWorkflow({ id, active: false }),
|
||||
},
|
||||
|
||||
executions: {
|
||||
list: {
|
||||
data: createMockExecutions(),
|
||||
},
|
||||
single: (id: string = 'mock-execution-1') => createMockExecution({ id }),
|
||||
delete: { success: true },
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
createMockWorkflow,
|
||||
createMockWorkflows,
|
||||
createMockExecution,
|
||||
createMockExecutions,
|
||||
mockApiResponses,
|
||||
};
|
||||
Reference in New Issue
Block a user