-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(Linear Node): Fix issue with error handling (#12191)
- Loading branch information
Showing
3 changed files
with
167 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
packages/nodes-base/nodes/Linear/test/GenericFunctions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import type { | ||
IExecuteFunctions, | ||
IHookFunctions, | ||
ILoadOptionsFunctions, | ||
IWebhookFunctions, | ||
} from 'n8n-workflow'; | ||
import { NodeApiError } from 'n8n-workflow'; | ||
|
||
import { capitalizeFirstLetter, linearApiRequest, sort } from '../GenericFunctions'; | ||
|
||
describe('Linear -> GenericFunctions', () => { | ||
const mockHttpRequestWithAuthentication = jest.fn(); | ||
|
||
describe('linearApiRequest', () => { | ||
let mockExecuteFunctions: | ||
| IExecuteFunctions | ||
| IWebhookFunctions | ||
| IHookFunctions | ||
| ILoadOptionsFunctions; | ||
|
||
const setupMockFunctions = (authentication: string) => { | ||
mockExecuteFunctions = { | ||
getNodeParameter: jest.fn().mockReturnValue(authentication), | ||
helpers: { | ||
httpRequestWithAuthentication: mockHttpRequestWithAuthentication, | ||
}, | ||
getNode: jest.fn().mockReturnValue({}), | ||
} as unknown as | ||
| IExecuteFunctions | ||
| IWebhookFunctions | ||
| IHookFunctions | ||
| ILoadOptionsFunctions; | ||
jest.clearAllMocks(); | ||
}; | ||
|
||
beforeEach(() => { | ||
setupMockFunctions('apiToken'); | ||
}); | ||
|
||
it('should make a successful API request', async () => { | ||
const response = { data: { success: true } }; | ||
|
||
mockHttpRequestWithAuthentication.mockResolvedValue(response); | ||
|
||
const result = await linearApiRequest.call(mockExecuteFunctions, { | ||
query: '{ viewer { id } }', | ||
}); | ||
|
||
expect(result).toEqual(response); | ||
expect(mockExecuteFunctions.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith( | ||
'linearApi', | ||
expect.objectContaining({ | ||
method: 'POST', | ||
url: 'https://api.linear.app/graphql', | ||
json: true, | ||
body: { query: '{ viewer { id } }' }, | ||
}), | ||
); | ||
}); | ||
|
||
it('should handle API request errors', async () => { | ||
const errorResponse = { | ||
errors: [ | ||
{ | ||
message: 'Access denied', | ||
extensions: { | ||
userPresentableMessage: 'You need to have the "Admin" scope to create webhooks.', | ||
}, | ||
}, | ||
], | ||
}; | ||
|
||
mockHttpRequestWithAuthentication.mockResolvedValue(errorResponse); | ||
|
||
await expect( | ||
linearApiRequest.call(mockExecuteFunctions, { query: '{ viewer { id } }' }), | ||
).rejects.toThrow(NodeApiError); | ||
|
||
expect(mockExecuteFunctions.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith( | ||
'linearApi', | ||
expect.objectContaining({ | ||
method: 'POST', | ||
url: 'https://api.linear.app/graphql', | ||
json: true, | ||
body: { query: '{ viewer { id } }' }, | ||
}), | ||
); | ||
}); | ||
}); | ||
|
||
describe('capitalizeFirstLetter', () => { | ||
it('should capitalize the first letter of a string', () => { | ||
expect(capitalizeFirstLetter('hello')).toBe('Hello'); | ||
expect(capitalizeFirstLetter('world')).toBe('World'); | ||
expect(capitalizeFirstLetter('capitalize')).toBe('Capitalize'); | ||
}); | ||
|
||
it('should return an empty string if input is empty', () => { | ||
expect(capitalizeFirstLetter('')).toBe(''); | ||
}); | ||
|
||
it('should handle single character strings', () => { | ||
expect(capitalizeFirstLetter('a')).toBe('A'); | ||
expect(capitalizeFirstLetter('b')).toBe('B'); | ||
}); | ||
|
||
it('should not change the case of the rest of the string', () => { | ||
expect(capitalizeFirstLetter('hELLO')).toBe('HELLO'); | ||
expect(capitalizeFirstLetter('wORLD')).toBe('WORLD'); | ||
}); | ||
}); | ||
|
||
describe('sort', () => { | ||
it('should sort objects by name in ascending order', () => { | ||
const array = [{ name: 'banana' }, { name: 'apple' }, { name: 'cherry' }]; | ||
|
||
const sortedArray = array.sort(sort); | ||
|
||
expect(sortedArray).toEqual([{ name: 'apple' }, { name: 'banana' }, { name: 'cherry' }]); | ||
}); | ||
|
||
it('should handle case insensitivity', () => { | ||
const array = [{ name: 'Banana' }, { name: 'apple' }, { name: 'cherry' }]; | ||
|
||
const sortedArray = array.sort(sort); | ||
|
||
expect(sortedArray).toEqual([{ name: 'apple' }, { name: 'Banana' }, { name: 'cherry' }]); | ||
}); | ||
|
||
it('should return 0 for objects with the same name', () => { | ||
const result = sort({ name: 'apple' }, { name: 'apple' }); | ||
expect(result).toBe(0); | ||
}); | ||
}); | ||
}); |