fix(Slack Node): Sort messages manually (#21822)

This commit is contained in:
yehorkardash 2025-11-26 18:35:14 +01:00 committed by GitHub
parent 4319da6f1c
commit 52b93ed5b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 2 deletions

View File

@ -13,7 +13,7 @@ export class Slack extends VersionedNodeType {
group: ['output'],
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Slack API',
defaultVersion: 2.3,
defaultVersion: 2.4,
};
const nodeVersions: IVersionedNodeType['nodeVersions'] = {
@ -22,6 +22,7 @@ export class Slack extends VersionedNodeType {
2.1: new SlackV2(baseDescription),
2.2: new SlackV2(baseDescription),
2.3: new SlackV2(baseDescription),
2.4: new SlackV2(baseDescription),
};
super(nodeVersions, baseDescription);

View File

@ -56,7 +56,7 @@ export class SlackV2 implements INodeType {
constructor(baseDescription: INodeTypeBaseDescription) {
this.description = {
...baseDescription,
version: [2, 2.1, 2.2, 2.3],
version: [2, 2.1, 2.2, 2.3, 2.4],
defaults: {
name: 'Slack',
},
@ -574,6 +574,12 @@ export class SlackV2 implements INodeType {
);
responseData = responseData.messages;
}
// Slack API "feature" - messages sorting breaks in-between pages when oldest is provided
// Always sort manually in descending order to ensure consistent sorting
if (nodeVersion >= 2.4) {
responseData.sort((a: IDataObject, b: IDataObject) => +(b.ts ?? 0) - +(a.ts ?? 0));
}
}
//https://api.slack.com/methods/conversations.invite
if (operation === 'invite') {

View File

@ -194,6 +194,43 @@ describe('SlackV2', () => {
]);
});
it('should return channel history sorted by timestamp descending for node version >= 2.4', async () => {
mockExecuteFunctions.getNode.mockReturnValue({
...mockNode,
typeVersion: 2.4,
});
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
const params: Record<string, any> = {
resource: 'channel',
operation: 'history',
channelId: 'C123456789',
returnAll: true,
filters: {},
};
return params[paramName];
});
// Mock unsorted messages
const mockResponse = [
{ type: 'message', text: 'Message 2', ts: '1234567892.123456' },
{ type: 'message', text: 'Message 4', ts: '1234567894.123456' },
{ type: 'message', text: 'Message 1', ts: '1234567891.123456' },
{ type: 'message', text: 'Message 3', ts: '1234567893.123456' },
];
slackApiRequestAllItemsSpy.mockResolvedValue(mockResponse);
const result = await node.execute.call(mockExecuteFunctions);
// Verify messages are sorted by timestamp descending (newest first)
expect(result[0][0].json).toEqual([
{ type: 'message', text: 'Message 4', ts: '1234567894.123456' },
{ type: 'message', text: 'Message 3', ts: '1234567893.123456' },
{ type: 'message', text: 'Message 2', ts: '1234567892.123456' },
{ type: 'message', text: 'Message 1', ts: '1234567891.123456' },
]);
});
it('should get all channel history', async () => {
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
const params: Record<string, any> = {