import nock from 'nock'; import * as mailparser from 'mailparser'; import { testPollingTriggerNode } from '@test/nodes/TriggerHelpers'; import { GmailTrigger } from '../GmailTrigger.node'; import type { Message, ListMessage, MessageListResponse } from '../types'; jest.mock('mailparser'); describe('GmailTrigger', () => { const baseUrl = 'https://www.googleapis.com'; function createMessage(message: Partial = {}): Message { const content = Buffer.from('test'); const contentBase64 = content.toString('base64'); const size = content.byteLength; return { historyId: 'testHistoryId', id: 'testId', internalDate: '1727777957863', raw: contentBase64, labelIds: ['testLabelId'], sizeEstimate: size, snippet: content.toString('utf-8'), threadId: 'testThreadId', payload: { body: { attachmentId: 'testAttachmentId', data: contentBase64, size }, filename: 'foo.txt', headers: [{ name: 'testHeader', value: 'testHeaderValue' }], mimeType: 'text/plain', partId: 'testPartId', parts: [], }, ...message, }; } function createListMessage(message: Partial = {}): ListMessage { return { id: 'testId', threadId: 'testThreadId', ...message }; } beforeAll(() => { nock.disableNetConnect(); jest.spyOn(mailparser, 'simpleParser').mockResolvedValue({ headers: new Map([['headerKey', 'headerValue']]), attachments: [], headerLines: [{ key: 'headerKey', line: 'headerValue' }], html: '

test

', date: new Date('2024-08-31'), from: { text: 'from@example.com', value: [{ name: 'From', address: 'from@example.com' }], html: 'from@example.com', }, to: { text: 'to@example.com', value: [{ name: 'To', address: 'to@example.com' }], html: 'to@example.com', }, }); }); afterAll(() => { nock.restore(); }); it('should return incoming emails', async () => { const messageListResponse: MessageListResponse = { messages: [createListMessage({ id: '1' }), createListMessage({ id: '2' })], resultSizeEstimate: 123, }; nock(baseUrl) .get('/gmail/v1/users/me/labels') .reply(200, { labels: [{ id: 'testLabelId', name: 'Test Label Name' }] }); nock(baseUrl).get(new RegExp('/gmail/v1/users/me/messages?.*')).reply(200, messageListResponse); nock(baseUrl) .get(new RegExp('/gmail/v1/users/me/messages/1?.*')) .reply(200, createMessage({ id: '1' })); nock(baseUrl) .get(new RegExp('/gmail/v1/users/me/messages/2?.*')) .reply(200, createMessage({ id: '2' })); const { response } = await testPollingTriggerNode(GmailTrigger); expect(response).toEqual([ [ { json: { date: '2024-08-31T00:00:00.000Z', from: { html: 'from@example.com', text: 'from@example.com', value: [{ address: 'from@example.com', name: 'From' }], }, headers: { headerKey: 'headerValue' }, html: '

test

', id: '1', labelIds: ['testLabelId'], sizeEstimate: 4, threadId: 'testThreadId', to: { html: 'to@example.com', text: 'to@example.com', value: [{ address: 'to@example.com', name: 'To' }], }, }, }, { json: { date: '2024-08-31T00:00:00.000Z', from: { html: 'from@example.com', text: 'from@example.com', value: [{ address: 'from@example.com', name: 'From' }], }, headers: { headerKey: 'headerValue' }, html: '

test

', id: '2', labelIds: ['testLabelId'], sizeEstimate: 4, threadId: 'testThreadId', to: { html: 'to@example.com', text: 'to@example.com', value: [{ address: 'to@example.com', name: 'To' }], }, }, }, ], ]); }); it('should simplify output when enabled', async () => { const messageListResponse: MessageListResponse = { messages: [createListMessage({ id: '1' }), createListMessage({ id: '2' })], resultSizeEstimate: 123, }; nock(baseUrl) .get('/gmail/v1/users/me/labels') .reply(200, { labels: [{ id: 'testLabelId', name: 'Test Label Name' }] }); nock(baseUrl).get(new RegExp('/gmail/v1/users/me/messages?.*')).reply(200, messageListResponse); nock(baseUrl) .get(new RegExp('/gmail/v1/users/me/messages/1?.*')) .reply(200, createMessage({ id: '1' })); nock(baseUrl) .get(new RegExp('/gmail/v1/users/me/messages/2?.*')) .reply(200, createMessage({ id: '2' })); const { response } = await testPollingTriggerNode(GmailTrigger, { node: { parameters: { simple: true } }, }); expect(response).toEqual([ [ { json: { historyId: 'testHistoryId', id: '1', internalDate: '1727777957863', labels: [{ id: 'testLabelId', name: 'Test Label Name' }], payload: { body: { attachmentId: 'testAttachmentId', data: 'dGVzdA==', size: 4 }, filename: 'foo.txt', mimeType: 'text/plain', partId: 'testPartId', parts: [], }, raw: 'dGVzdA==', sizeEstimate: 4, snippet: 'test', testHeader: 'testHeaderValue', threadId: 'testThreadId', }, }, { json: { historyId: 'testHistoryId', id: '2', internalDate: '1727777957863', labels: [{ id: 'testLabelId', name: 'Test Label Name' }], payload: { body: { attachmentId: 'testAttachmentId', data: 'dGVzdA==', size: 4 }, filename: 'foo.txt', mimeType: 'text/plain', partId: 'testPartId', parts: [], }, raw: 'dGVzdA==', sizeEstimate: 4, snippet: 'test', testHeader: 'testHeaderValue', threadId: 'testThreadId', }, }, ], ]); }); it('should filter out emails that were already processed', async () => { const messageListResponse: MessageListResponse = { messages: [], resultSizeEstimate: 0, }; nock(baseUrl) .get('/gmail/v1/users/me/labels') .reply(200, { labels: [{ id: 'testLabelId', name: 'Test Label Name' }] }); nock(baseUrl).get(new RegExp('/gmail/v1/users/me/messages?.*')).reply(200, messageListResponse); const { response } = await testPollingTriggerNode(GmailTrigger, { node: { parameters: { simple: true } }, workflowStaticData: { 'Gmail Trigger': { lastTimeChecked: new Date('2024-10-31').getTime() / 1000 }, }, }); expect(response).toEqual(null); }); });