mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-03-22 02:13:09 +00:00
Add transferWorkflow diff operation to move workflows between n8n projects:
- TransferWorkflowOperation type with destinationProjectId field
- WorkflowDiffEngine validates and tracks transfer intent
- Handler calls PUT /workflows/{id}/transfer after update
- N8nApiClient.transferWorkflow() method
- Zod schema validates destinationProjectId is non-empty
- Tool description and documentation updated
- inferIntentFromOperations case for transfer
Also fixes two pre-existing bugs found during review:
- continueOnError path now properly extracts/propagates activation flags
- Debug log in updateConnectionReferences shows correct old name
Based on work by @djakielski in PR #645.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
This commit is contained in:
committed by
GitHub
parent
14962a39b6
commit
47a1cb135d
@@ -1250,6 +1250,56 @@ describe('N8nApiClient', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferWorkflow', () => {
|
||||
beforeEach(() => {
|
||||
client = new N8nApiClient(defaultConfig);
|
||||
});
|
||||
|
||||
it('should transfer workflow successfully via PUT', async () => {
|
||||
mockAxiosInstance.put.mockResolvedValue({ data: undefined });
|
||||
|
||||
await client.transferWorkflow('123', 'project-456');
|
||||
|
||||
expect(mockAxiosInstance.put).toHaveBeenCalledWith(
|
||||
'/workflows/123/transfer',
|
||||
{ destinationProjectId: 'project-456' }
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw N8nNotFoundError on 404', async () => {
|
||||
const error = {
|
||||
message: 'Request failed',
|
||||
response: { status: 404, data: { message: 'Workflow not found' } }
|
||||
};
|
||||
await mockAxiosInstance.simulateError('put', error);
|
||||
|
||||
try {
|
||||
await client.transferWorkflow('123', 'project-456');
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(N8nNotFoundError);
|
||||
expect((err as N8nNotFoundError).message).toContain('not found');
|
||||
expect((err as N8nNotFoundError).statusCode).toBe(404);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw appropriate error on 403 forbidden', async () => {
|
||||
const error = {
|
||||
message: 'Request failed',
|
||||
response: { status: 403, data: { message: 'Forbidden' } }
|
||||
};
|
||||
await mockAxiosInstance.simulateError('put', error);
|
||||
|
||||
try {
|
||||
await client.transferWorkflow('123', 'project-456');
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(N8nApiError);
|
||||
expect((err as N8nApiError).statusCode).toBe(403);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('interceptors', () => {
|
||||
let requestInterceptor: any;
|
||||
let responseInterceptor: any;
|
||||
@@ -1317,4 +1367,4 @@ describe('N8nApiClient', () => {
|
||||
expect(result.message).toBe('Bad request');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user