mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-03-22 18:33:08 +00:00
fix: resolve 5 bugs in n8n_manage_datatable row operations and error handling
Fix critical issues found during staging QA testing: 1. data parameter serialization: MCP transport sends JSON as strings — added z.preprocess coercers (coerceJsonArray, coerceJsonObject, coerceJsonFilter) to parse string→JSON before Zod validation 2. filter/sortBy URL encoding: n8n API requires URL-encoded query params — added encodeURIComponent() for filter and sortBy in getRows/deleteRows 3. json column type: n8n API only accepts string|number|boolean|date — removed json from enum in types, Zod schema, tool definition, and docs 4. 404 error messages: N8nNotFoundError was wrapping API messages in "Resource with ID <message> not found" — now passes through cleanly 5. Unit test expectations updated for URL-encoded filter/sortBy values Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -429,12 +429,12 @@ describe('Data Table Handlers (n8n_manage_datatable)', () => {
|
||||
|
||||
expect(mockApiClient.getDataTableRows).toHaveBeenCalledWith('dt-1', {
|
||||
limit: 50,
|
||||
sortBy: 'name:asc',
|
||||
sortBy: encodeURIComponent('name:asc'),
|
||||
search: 'john',
|
||||
});
|
||||
});
|
||||
|
||||
it('should serialize object filter to JSON string', async () => {
|
||||
it('should serialize object filter to URL-encoded JSON string', async () => {
|
||||
mockApiClient.getDataTableRows.mockResolvedValue({ data: [], nextCursor: null });
|
||||
|
||||
const objectFilter = {
|
||||
@@ -448,20 +448,21 @@ describe('Data Table Handlers (n8n_manage_datatable)', () => {
|
||||
});
|
||||
|
||||
expect(mockApiClient.getDataTableRows).toHaveBeenCalledWith('dt-1', {
|
||||
filter: JSON.stringify(objectFilter),
|
||||
filter: encodeURIComponent(JSON.stringify(objectFilter)),
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass through string filter as-is', async () => {
|
||||
it('should URL-encode string filter', async () => {
|
||||
mockApiClient.getDataTableRows.mockResolvedValue({ data: [], nextCursor: null });
|
||||
|
||||
const filterStr = '{"type":"and","filters":[]}';
|
||||
await handlers.handleGetRows({
|
||||
tableId: 'dt-1',
|
||||
filter: '{"type":"and","filters":[]}',
|
||||
filter: filterStr,
|
||||
});
|
||||
|
||||
expect(mockApiClient.getDataTableRows).toHaveBeenCalledWith('dt-1', {
|
||||
filter: '{"type":"and","filters":[]}',
|
||||
filter: encodeURIComponent(filterStr),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -680,11 +681,11 @@ describe('Data Table Handlers (n8n_manage_datatable)', () => {
|
||||
message: 'Rows deleted successfully',
|
||||
});
|
||||
expect(mockApiClient.deleteDataTableRows).toHaveBeenCalledWith('dt-1', {
|
||||
filter: JSON.stringify({ type: 'and', ...filter }),
|
||||
filter: encodeURIComponent(JSON.stringify({ type: 'and', ...filter })),
|
||||
});
|
||||
});
|
||||
|
||||
it('should serialize filter object to JSON string for API call', async () => {
|
||||
it('should URL-encode serialized filter for API call', async () => {
|
||||
mockApiClient.deleteDataTableRows.mockResolvedValue({ deletedCount: 1 });
|
||||
|
||||
const filter = {
|
||||
@@ -698,7 +699,7 @@ describe('Data Table Handlers (n8n_manage_datatable)', () => {
|
||||
await handlers.handleDeleteRows({ tableId: 'dt-1', filter });
|
||||
|
||||
expect(mockApiClient.deleteDataTableRows).toHaveBeenCalledWith('dt-1', {
|
||||
filter: JSON.stringify(filter),
|
||||
filter: encodeURIComponent(JSON.stringify(filter)),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -719,7 +720,7 @@ describe('Data Table Handlers (n8n_manage_datatable)', () => {
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.message).toBe('Dry run: rows matched for deletion (no changes applied)');
|
||||
expect(mockApiClient.deleteDataTableRows).toHaveBeenCalledWith('dt-1', {
|
||||
filter: JSON.stringify({ type: 'and', ...filter }),
|
||||
filter: encodeURIComponent(JSON.stringify({ type: 'and', ...filter })),
|
||||
dryRun: true,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user