fix(Gmail Node): Do not break threads while creating drafts (#16272)

Co-authored-by: Shireen Missi <94372015+ShireenMissi@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Dana
2025-06-16 10:03:10 +02:00
committed by GitHub
parent b1305fe5f1
commit 113d94cea2
6 changed files with 128 additions and 1 deletions

View File

@@ -2,7 +2,11 @@ import { mock } from 'jest-mock-extended';
import { DateTime } from 'luxon';
import type { IExecuteFunctions, INode } from 'n8n-workflow';
import type { IEmail } from '@utils/sendAndWait/interfaces';
import * as GenericFunctions from '../../GenericFunctions';
import { parseRawEmail, prepareTimestamp } from '../../GenericFunctions';
import { addThreadHeadersToEmail } from '../../v2/utils/draft';
const node: INode = {
id: '1',
@@ -128,3 +132,73 @@ describe('parseRawEmail', () => {
expect(typeof json.date).toBe('string');
});
});
describe('addThreadHeadersToEmail', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should set inReplyTo and reference on the email object', async () => {
const mockThreadId = 'thread123';
const mockMessageId = '<message-id@example.com>';
const mockThread = {
messages: [
{ payload: { headers: [{ value: '<old-id@example.com>' }] } },
{ payload: { headers: [{ value: mockMessageId }] } },
],
};
jest.spyOn(GenericFunctions, 'googleApiRequest').mockImplementation(async function () {
return mockThread;
});
const email = mock<IEmail>({});
const thisArg = mock<IExecuteFunctions>({});
await addThreadHeadersToEmail.call(thisArg, email, mockThreadId);
expect(email.inReplyTo).toBe(mockMessageId);
expect(email.reference).toBe(mockMessageId);
});
it('should set inReplyTo and reference on the email object even if the message has only one item', async () => {
const mockThreadId = 'thread123';
const mockMessageId = '<message-id@example.com>';
const mockThread = {
messages: [{ payload: { headers: [{ value: mockMessageId }] } }],
};
jest.spyOn(GenericFunctions, 'googleApiRequest').mockImplementation(async function () {
return mockThread;
});
const email = mock<IEmail>({});
const thisArg = mock<IExecuteFunctions>({});
await addThreadHeadersToEmail.call(thisArg, email, mockThreadId);
expect(email.inReplyTo).toBe(mockMessageId);
expect(email.reference).toBe(mockMessageId);
});
it('should not do anything if the thread has no messages', async () => {
const mockThreadId = 'thread123';
const mockThread = {};
jest.spyOn(GenericFunctions, 'googleApiRequest').mockImplementation(async function () {
return mockThread;
});
const email = mock<IEmail>({});
const thisArg = mock<IExecuteFunctions>({});
await addThreadHeadersToEmail.call(thisArg, email, mockThreadId);
// We are using mock<IEmail>({}) which means the value of these will be a mock function
expect(typeof email.inReplyTo).toBe('function');
expect(typeof email.reference).toBe('function');
});
});