-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(Gmail Trigger Node): Add tests (no-changelog) (#11076)
- Loading branch information
Showing
4 changed files
with
362 additions
and
9 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
packages/nodes-base/nodes/ExecuteWorkflowTrigger/test/ExecuteWorkflowTrigger.node.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,19 @@ | ||
import { mock } from 'jest-mock-extended'; | ||
import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; | ||
|
||
import { ExecuteWorkflowTrigger } from '../ExecuteWorkflowTrigger.node'; | ||
|
||
describe('ExecuteWorkflowTrigger', () => { | ||
it('should return its input data', async () => { | ||
const mockInputData: INodeExecutionData[] = [ | ||
{ json: { item: 0, foo: 'bar' } }, | ||
{ json: { item: 1, foo: 'quz' } }, | ||
]; | ||
const executeFns = mock<IExecuteFunctions>({ | ||
getInputData: () => mockInputData, | ||
}); | ||
const result = await new ExecuteWorkflowTrigger().execute.call(executeFns); | ||
|
||
expect(result).toEqual([mockInputData]); | ||
}); | ||
}); |
221 changes: 221 additions & 0 deletions
221
packages/nodes-base/nodes/Google/Gmail/test/GmailTrigger.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,221 @@ | ||
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> = {}): 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> = {}): 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: '<p>test</p>', | ||
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: '<p>test</p>', | ||
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: '<p>test</p>', | ||
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); | ||
}); | ||
}); |
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,39 @@ | ||
export type Message = { | ||
id: string; | ||
threadId: string; | ||
labelIds: string[]; | ||
snippet: string; | ||
historyId: string; | ||
internalDate: string; | ||
sizeEstimate: number; | ||
raw: string; | ||
payload: MessagePart; | ||
}; | ||
|
||
export type ListMessage = Pick<Message, 'id' | 'threadId'>; | ||
|
||
export type MessageListResponse = { | ||
messages: ListMessage[]; | ||
nextPageToken?: string; | ||
resultSizeEstimate: number; | ||
}; | ||
|
||
type GmailHeader = { | ||
name: string; | ||
value: string; | ||
}; | ||
|
||
type MessagePart = { | ||
partId: string; | ||
mimeType: string; | ||
filename: string; | ||
headers: GmailHeader[]; | ||
body: MessagePartBody; | ||
parts: MessagePart[]; | ||
}; | ||
|
||
type MessagePartBody = { | ||
attachmentId: string; | ||
size: number; | ||
data: string; | ||
}; |
Oops, something went wrong.