From 396f7c1b8ecb8b24bbbb66151304317778a1a692 Mon Sep 17 00:00:00 2001 From: Adina Totorean Date: Wed, 5 Feb 2025 16:08:56 +0200 Subject: [PATCH] Added new tests --- .../CosmosDB/test/HandlePagination.test.ts | 116 ---------------- .../test/MicrosoftCosmosDbRequest.test.ts | 7 +- .../CosmosDB/test/SearchCollections.test.ts | 16 ++- .../CosmosDB/test/SearchItems.test.ts | 124 ++++++++++++++++++ 4 files changed, 139 insertions(+), 124 deletions(-) delete mode 100644 packages/nodes-base/nodes/Microsoft/CosmosDB/test/HandlePagination.test.ts create mode 100644 packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchItems.test.ts diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/HandlePagination.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/HandlePagination.test.ts deleted file mode 100644 index 0952ae09d1..0000000000 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/HandlePagination.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { handlePagination } from '../GenericFunctions'; - -describe('GenericFunctions - handlePagination', () => { - let mockContext: any; - let mockMakeRoutingRequest: jest.Mock; - let resultOptions: any; - - beforeEach(() => { - mockMakeRoutingRequest = jest.fn(); - mockContext = { - makeRoutingRequest: mockMakeRoutingRequest, - getNodeParameter: jest.fn(), - }; - - resultOptions = { - maxResults: 60, - options: { body: {} }, - }; - }); - - test('should aggregate results and handle pagination when returnAll is true', async () => { - mockMakeRoutingRequest - .mockResolvedValueOnce([ - { id: 1 }, - { id: 2 }, - { headers: { 'x-ms-continuation': 'token-1' } }, - ]) - .mockResolvedValueOnce([{ id: 3 }, { id: 4 }, { headers: {} }]); - - mockContext.getNodeParameter.mockImplementation((param: string) => { - if (param === 'returnAll') return true; - return undefined; - }); - - const result = await handlePagination.call(mockContext, resultOptions); - - expect(result).toEqual([ - { json: { id: 1 } }, - { json: { id: 2 } }, - { json: { id: 3 } }, - { json: { id: 4 } }, - ]); - - expect(mockMakeRoutingRequest).toHaveBeenCalledTimes(2); - expect(resultOptions.options.headers).toEqual({ - 'x-ms-continuation': 'token-1', - }); - }); - - test('should stop pagination after reaching limit when returnAll is false', async () => { - mockMakeRoutingRequest - .mockResolvedValueOnce([ - { id: 1 }, - { id: 2 }, - { headers: { 'x-ms-continuation': 'token-1' } }, - ]) - .mockResolvedValueOnce([{ id: 3 }, { id: 4 }, { headers: {} }]); - - mockContext.getNodeParameter.mockImplementation((param: string) => { - if (param === 'returnAll') return false; - if (param === 'limit') return 3; - return undefined; - }); - - const result = await handlePagination.call(mockContext, resultOptions); - - expect(result).toEqual([{ json: { id: 1 } }, { json: { id: 2 } }, { json: { id: 3 } }]); - - expect(mockMakeRoutingRequest).toHaveBeenCalledTimes(2); - }); - - test('should handle cases with no continuation token gracefully', async () => { - mockMakeRoutingRequest.mockResolvedValueOnce([{ id: 1 }, { id: 2 }]); - - mockContext.getNodeParameter.mockImplementation((param: string) => { - if (param === 'returnAll') return true; - return undefined; - }); - - const result = await handlePagination.call(mockContext, resultOptions); - - expect(result).toEqual([{ json: { id: 1 } }, { json: { id: 2 } }]); - - expect(mockMakeRoutingRequest).toHaveBeenCalledTimes(1); - }); - - test('should respect the limit even if fewer results are available', async () => { - mockMakeRoutingRequest.mockResolvedValueOnce([{ id: 1 }, { id: 2 }]); - - mockContext.getNodeParameter.mockImplementation((param: string) => { - if (param === 'returnAll') return false; - if (param === 'limit') return 5; - return undefined; - }); - - const result = await handlePagination.call(mockContext, resultOptions); - - expect(result).toEqual([{ json: { id: 1 } }, { json: { id: 2 } }]); - - expect(mockMakeRoutingRequest).toHaveBeenCalledTimes(1); - }); - - test('should break the loop if no results are returned', async () => { - mockMakeRoutingRequest.mockResolvedValueOnce([]); - - mockContext.getNodeParameter.mockImplementation((param: string) => { - if (param === 'returnAll') return true; - return undefined; - }); - - const result = await handlePagination.call(mockContext, resultOptions); - - expect(result).toEqual([]); - expect(mockMakeRoutingRequest).toHaveBeenCalledTimes(1); - }); -}); diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts index 5042bf4a20..523cfea187 100644 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts @@ -16,12 +16,11 @@ describe('GenericFunctions - microsoftCosmosDbRequest', () => { test('should make a successful request with correct options', async () => { mockRequestWithAuthentication.mockResolvedValueOnce({ success: true }); - (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ account: 'us-east-1' }); + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', database: 'first_database_1', - }); - (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ - baseUrl: 'https://us-east-1.documents.azure.com/dbs', + baseUrl: 'https://us-east-1.documents.azure.com/dbs/first_database_1', }); const requestOptions = { diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchCollections.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchCollections.test.ts index abdfacd3ee..7e75d847bb 100644 --- a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchCollections.test.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchCollections.test.ts @@ -18,7 +18,11 @@ describe('GenericFunctions - searchCollections', () => { }); it('should make a GET request to fetch collections and return results', async () => { - (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ account: 'us-east-1' }); + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', + database: 'first_database_1', + baseUrl: 'https://us-east-1.documents.azure.com', + }); mockRequestWithAuthentication.mockResolvedValueOnce({ DocumentCollections: [{ id: 'Collection1' }, { id: 'Collection2' }], @@ -27,7 +31,7 @@ describe('GenericFunctions - searchCollections', () => { const response = await searchCollections.call(mockContext); expect(mockRequestWithAuthentication).toHaveBeenCalledWith( - 'azureCosmosDbSharedKeyApi', + 'microsoftCosmosDbSharedKeyApi', expect.objectContaining({ baseURL: 'https://us-east-1.documents.azure.com', method: 'GET', @@ -49,7 +53,11 @@ describe('GenericFunctions - searchCollections', () => { }); it('should filter collections by the provided filter string', async () => { - (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ account: 'us-east-1' }); + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', + database: 'first_database_1', + baseUrl: 'https://us-east-1.documents.azure.com', + }); mockRequestWithAuthentication.mockResolvedValueOnce({ DocumentCollections: [{ id: 'Test-Col-1' }, { id: 'Prod-Col-1' }], @@ -58,7 +66,7 @@ describe('GenericFunctions - searchCollections', () => { const response = await searchCollections.call(mockContext, 'Test'); expect(mockRequestWithAuthentication).toHaveBeenCalledWith( - 'azureCosmosDbSharedKeyApi', + 'microsoftCosmosDbSharedKeyApi', expect.objectContaining({ baseURL: 'https://us-east-1.documents.azure.com', method: 'GET', diff --git a/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchItems.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchItems.test.ts new file mode 100644 index 0000000000..e1d4510275 --- /dev/null +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchItems.test.ts @@ -0,0 +1,124 @@ +import type { ILoadOptionsFunctions } from 'n8n-workflow'; + +import { searchItems } from '../GenericFunctions'; + +describe('GenericFunctions - searchItems', () => { + const mockRequestWithAuthentication = jest.fn(); + + const mockContext = { + helpers: { + requestWithAuthentication: mockRequestWithAuthentication, + }, + getNodeParameter: jest.fn(), + getCredentials: jest.fn(), + } as unknown as ILoadOptionsFunctions; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should fetch documents and return formatted results', async () => { + (mockContext.getNodeParameter as jest.Mock).mockReturnValueOnce({ + mode: 'list', + value: 'coll-1', + }); + + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', + database: 'first_database_1', + baseUrl: 'https://us-east-1.documents.azure.com', + }); + + mockRequestWithAuthentication.mockResolvedValueOnce({ + Documents: [{ id: 'Item 1' }, { id: 'Item 2' }], + }); + + const response = await searchItems.call(mockContext); + + expect(mockRequestWithAuthentication).toHaveBeenCalledWith( + 'microsoftCosmosDbSharedKeyApi', + expect.objectContaining({ + method: 'GET', + url: '/colls/coll-1/docs', + }), + ); + + expect(response).toEqual({ + results: [ + { name: 'Item1', value: 'Item 1' }, // Space removed from 'Item 1' + { name: 'Item2', value: 'Item 2' }, + ], + }); + }); + + it('should filter results based on the provided filter string', async () => { + (mockContext.getNodeParameter as jest.Mock).mockReturnValueOnce({ + mode: 'list', + value: 'coll-1', + }); + + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', + database: 'first_database_1', + baseUrl: 'https://us-east-1.documents.azure.com', + }); + + mockRequestWithAuthentication.mockResolvedValueOnce({ + Documents: [{ id: 'TestItem' }, { id: 'ProdItem' }], + }); + + const response = await searchItems.call(mockContext, 'Test'); + + expect(response).toEqual({ + results: [{ name: 'TestItem', value: 'TestItem' }], + }); + }); + + it('should return an empty array if no documents are found', async () => { + (mockContext.getNodeParameter as jest.Mock).mockReturnValueOnce({ + mode: 'list', + value: 'coll-1', + }); + + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', + database: 'first_database_1', + baseUrl: 'https://us-east-1.documents.azure.com', + }); + + mockRequestWithAuthentication.mockResolvedValueOnce({ + Documents: [], + }); + + const response = await searchItems.call(mockContext); + + expect(response).toEqual({ results: [] }); + }); + + it('should handle missing Documents property gracefully', async () => { + (mockContext.getNodeParameter as jest.Mock).mockReturnValueOnce({ + mode: 'list', + value: 'coll-1', + }); + + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + account: 'us-east-1', + database: 'first_database_1', + baseUrl: 'https://us-east-1.documents.azure.com', + }); + + mockRequestWithAuthentication.mockResolvedValueOnce({ + unexpectedKey: 'value', + }); + + const response = await searchItems.call(mockContext); + + expect(response).toEqual({ results: [] }); + }); + + it('should throw an error when collection ID is missing', async () => { + (mockContext.getNodeParameter as jest.Mock).mockReturnValueOnce({ mode: 'list', value: '' }); + + await expect(searchItems.call(mockContext)).rejects.toThrow('Collection ID is required.'); + }); +});