mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
fix(Slack Node): Make sure paginated calls use the defined limits (#14185)
This commit is contained in:
@@ -124,7 +124,7 @@ export async function slackApiRequestAllItems(
|
|||||||
if (endpoint.includes('files.list')) {
|
if (endpoint.includes('files.list')) {
|
||||||
query.count = 100;
|
query.count = 100;
|
||||||
} else {
|
} else {
|
||||||
query.limit = 100;
|
query.limit = query.limit ?? 100;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
responseData = await slackApiRequest.call(this, method, endpoint, body as IDataObject, query);
|
responseData = await slackApiRequest.call(this, method, endpoint, body as IDataObject, query);
|
||||||
|
|||||||
219
packages/nodes-base/nodes/Slack/test/v2/GenericFunctions.test.ts
Normal file
219
packages/nodes-base/nodes/Slack/test/v2/GenericFunctions.test.ts
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
import type { IExecuteFunctions } from 'n8n-workflow';
|
||||||
|
|
||||||
|
import { slackApiRequest, slackApiRequestAllItems } from '../../V2/GenericFunctions';
|
||||||
|
|
||||||
|
jest.mock('n8n-workflow', () => ({
|
||||||
|
...jest.requireActual('n8n-workflow'),
|
||||||
|
NodeApiError: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('Slack V2 > GenericFunctions', () => {
|
||||||
|
let mockExecuteFunctions: IExecuteFunctions;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
mockExecuteFunctions = {
|
||||||
|
helpers: {
|
||||||
|
requestWithAuthentication: jest.fn(),
|
||||||
|
},
|
||||||
|
getNode: jest.fn().mockReturnValue({ type: 'n8n-nodes-base.slack', typeVersion: 2 }),
|
||||||
|
getNodeParameter: jest.fn().mockReturnValue('accessToken'),
|
||||||
|
} as unknown as IExecuteFunctions;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('slackApiRequest', () => {
|
||||||
|
it('should handle paid_teams_only error', async () => {
|
||||||
|
const mockResponse = { ok: false, error: 'paid_teams_only' };
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(mockResponse);
|
||||||
|
|
||||||
|
await expect(slackApiRequest.call(mockExecuteFunctions, 'GET', '/test')).rejects.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('slackApiRequestAllItems', () => {
|
||||||
|
it('should use default limit of 100 when no limit is provided', async () => {
|
||||||
|
const mockResponse = {
|
||||||
|
ok: true,
|
||||||
|
channels: [{ id: 'ch1' }],
|
||||||
|
response_metadata: { next_cursor: undefined },
|
||||||
|
};
|
||||||
|
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(mockResponse);
|
||||||
|
|
||||||
|
await slackApiRequestAllItems.bind(mockExecuteFunctions)(
|
||||||
|
'channels',
|
||||||
|
'GET',
|
||||||
|
'conversations.list',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||||
|
'slackApi',
|
||||||
|
expect.objectContaining({
|
||||||
|
headers: expect.any(Object),
|
||||||
|
qs: {
|
||||||
|
limit: 100,
|
||||||
|
page: 2,
|
||||||
|
cursor: undefined,
|
||||||
|
},
|
||||||
|
json: true,
|
||||||
|
method: 'GET',
|
||||||
|
uri: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.any(Object),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use provided limit value when specified', async () => {
|
||||||
|
const mockResponse = {
|
||||||
|
ok: true,
|
||||||
|
channels: [{ id: 'ch1' }],
|
||||||
|
response_metadata: { next_cursor: undefined },
|
||||||
|
};
|
||||||
|
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(mockResponse);
|
||||||
|
|
||||||
|
await slackApiRequestAllItems.call(
|
||||||
|
mockExecuteFunctions,
|
||||||
|
'channels',
|
||||||
|
'GET',
|
||||||
|
'conversations.list',
|
||||||
|
{},
|
||||||
|
{ limit: 50 },
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||||
|
'slackApi',
|
||||||
|
expect.objectContaining({
|
||||||
|
headers: expect.any(Object),
|
||||||
|
qs: {
|
||||||
|
limit: 50,
|
||||||
|
page: 2,
|
||||||
|
cursor: undefined,
|
||||||
|
},
|
||||||
|
json: true,
|
||||||
|
method: 'GET',
|
||||||
|
uri: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.any(Object),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use count instead of limit for files.list endpoint', async () => {
|
||||||
|
const mockResponse = {
|
||||||
|
ok: true,
|
||||||
|
files: [{ id: 'file1' }],
|
||||||
|
response_metadata: { next_cursor: undefined },
|
||||||
|
};
|
||||||
|
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(mockResponse);
|
||||||
|
|
||||||
|
await slackApiRequestAllItems.call(mockExecuteFunctions, 'files', 'GET', 'files.list');
|
||||||
|
|
||||||
|
expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||||
|
'slackApi',
|
||||||
|
expect.objectContaining({
|
||||||
|
headers: expect.any(Object),
|
||||||
|
qs: {
|
||||||
|
count: 100,
|
||||||
|
page: 2,
|
||||||
|
cursor: undefined,
|
||||||
|
},
|
||||||
|
json: true,
|
||||||
|
method: 'GET',
|
||||||
|
uri: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.any(Object),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle files.list pagination', async () => {
|
||||||
|
const responses = [
|
||||||
|
{
|
||||||
|
ok: true,
|
||||||
|
files: [{ id: '1' }],
|
||||||
|
response_metadata: { next_cursor: 'cursor1' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ok: true,
|
||||||
|
files: [{ id: '2' }],
|
||||||
|
response_metadata: { next_cursor: '' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementationOnce(() => responses[0])
|
||||||
|
.mockImplementationOnce(() => responses[1]);
|
||||||
|
|
||||||
|
const result = await slackApiRequestAllItems.call(
|
||||||
|
mockExecuteFunctions,
|
||||||
|
'files',
|
||||||
|
'GET',
|
||||||
|
'files.list',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual([{ id: '1' }, { id: '2' }]);
|
||||||
|
expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle regular pagination with paging info', async () => {
|
||||||
|
const responses = [
|
||||||
|
{
|
||||||
|
ok: true,
|
||||||
|
channels: [{ id: 'ch1' }],
|
||||||
|
paging: { pages: 2, page: 1 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ok: true,
|
||||||
|
channels: [{ id: 'ch2' }],
|
||||||
|
paging: { pages: 2, page: 2 },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementationOnce(() => responses[0])
|
||||||
|
.mockImplementationOnce(() => responses[1]);
|
||||||
|
|
||||||
|
const result = await slackApiRequestAllItems.call(
|
||||||
|
mockExecuteFunctions,
|
||||||
|
'channels',
|
||||||
|
'GET',
|
||||||
|
'conversations.list',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual([{ id: 'ch1' }, { id: 'ch2' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle matches in response', async () => {
|
||||||
|
const response = {
|
||||||
|
ok: true,
|
||||||
|
messages: {
|
||||||
|
matches: [{ text: 'test' }],
|
||||||
|
},
|
||||||
|
response_metadata: { next_cursor: '' },
|
||||||
|
};
|
||||||
|
|
||||||
|
mockExecuteFunctions.helpers.requestWithAuthentication = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(response);
|
||||||
|
|
||||||
|
const result = await slackApiRequestAllItems.call(
|
||||||
|
mockExecuteFunctions,
|
||||||
|
'messages',
|
||||||
|
'GET',
|
||||||
|
'search.messages',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual([{ text: 'test' }]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user