From eefd59407426a64a6981518390f34ed496c00498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Thu, 14 Jul 2022 22:07:07 +0200 Subject: [PATCH] test: Mock mailer service (#3711) * :test_tube: Mock mailer service * :fire: Remove unneeded imports --- .../integration/passwordReset.api.test.ts | 51 +++--- .../cli/test/integration/shared/constants.ts | 5 - .../cli/test/integration/shared/types.d.ts | 19 +-- packages/cli/test/integration/shared/utils.ts | 51 +----- .../cli/test/integration/users.api.test.ts | 157 ++++++++---------- 5 files changed, 96 insertions(+), 187 deletions(-) diff --git a/packages/cli/test/integration/passwordReset.api.test.ts b/packages/cli/test/integration/passwordReset.api.test.ts index 4b6a4256c5..abc9bf227f 100644 --- a/packages/cli/test/integration/passwordReset.api.test.ts +++ b/packages/cli/test/integration/passwordReset.api.test.ts @@ -13,15 +13,14 @@ import { } from './shared/random'; import * as testDb from './shared/testDb'; import type { Role } from '../../src/databases/entities/Role'; -import { SMTP_TEST_TIMEOUT } from './shared/constants'; jest.mock('../../src/telemetry'); +jest.mock('../../src/UserManagement/email/NodeMailer'); let app: express.Application; let testDbName = ''; let globalOwnerRole: Role; let globalMemberRole: Role; -let isSmtpAvailable = false; beforeAll(async () => { app = await utils.initTestServer({ endpointGroups: ['passwordReset'], applyAuth: true }); @@ -33,9 +32,7 @@ beforeAll(async () => { utils.initTestTelemetry(); utils.initTestLogger(); - - isSmtpAvailable = await utils.isTestSmtpServiceAvailable(); -}, SMTP_TEST_TIMEOUT); +}); beforeEach(async () => { await testDb.truncate(['User'], testDbName); @@ -50,36 +47,30 @@ afterAll(async () => { await testDb.terminate(testDbName); }); -test( - 'POST /forgot-password should send password reset email', - async () => { - if (!isSmtpAvailable) utils.skipSmtpTest(expect); +test('POST /forgot-password should send password reset email', async () => { + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); + const authlessAgent = utils.createAgent(app); + const member = await testDb.createUser({ + email: 'test@test.com', + globalRole: globalMemberRole, + }); - const authlessAgent = utils.createAgent(app); - const member = await testDb.createUser({ - email: 'test@test.com', - globalRole: globalMemberRole, - }); + config.set('userManagement.emails.mode', 'smtp'); - await utils.configureSmtp(); + await Promise.all( + [{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => { + const response = await authlessAgent.post('/forgot-password').send(payload); - await Promise.all( - [{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => { - const response = await authlessAgent.post('/forgot-password').send(payload); + expect(response.statusCode).toBe(200); + expect(response.body).toEqual({}); - expect(response.statusCode).toBe(200); - expect(response.body).toEqual({}); - - const user = await Db.collections.User.findOneOrFail({ email: payload.email }); - expect(user.resetPasswordToken).toBeDefined(); - expect(user.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000)); - }), - ); - }, - SMTP_TEST_TIMEOUT, -); + const user = await Db.collections.User.findOneOrFail({ email: payload.email }); + expect(user.resetPasswordToken).toBeDefined(); + expect(user.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000)); + }), + ); +}); test('POST /forgot-password should fail if emailing is not set up', async () => { const owner = await testDb.createUser({ globalRole: globalOwnerRole }); diff --git a/packages/cli/test/integration/shared/constants.ts b/packages/cli/test/integration/shared/constants.ts index d68ef00e1e..1817789a15 100644 --- a/packages/cli/test/integration/shared/constants.ts +++ b/packages/cli/test/integration/shared/constants.ts @@ -71,11 +71,6 @@ export const BOOTSTRAP_POSTGRES_CONNECTION_NAME: Readonly = 'n8n_bs_post */ export const BOOTSTRAP_MYSQL_CONNECTION_NAME: Readonly = 'n8n_bs_mysql'; -/** - * Timeout (in milliseconds) to account for fake SMTP service being slow to respond. - */ -export const SMTP_TEST_TIMEOUT = 30_000; - /** * Timeout (in milliseconds) to account for DB being slow to initialize. */ diff --git a/packages/cli/test/integration/shared/types.d.ts b/packages/cli/test/integration/shared/types.d.ts index a711c4b036..1b31e598a4 100644 --- a/packages/cli/test/integration/shared/types.d.ts +++ b/packages/cli/test/integration/shared/types.d.ts @@ -8,19 +8,16 @@ export type CollectionName = keyof IDatabaseCollections; export type MappingName = keyof typeof MAPPING_TABLES; -export type SmtpTestAccount = { - user: string; - pass: string; - smtp: { - host: string; - port: number; - secure: boolean; - }; -}; - export type ApiPath = 'internal' | 'public'; -type EndpointGroup = 'me' | 'users' | 'auth' | 'owner' | 'passwordReset' | 'credentials' | 'publicApi'; +type EndpointGroup = + | 'me' + | 'users' + | 'auth' + | 'owner' + | 'passwordReset' + | 'credentials' + | 'publicApi'; export type CredentialPayload = { name: string; diff --git a/packages/cli/test/integration/shared/utils.ts b/packages/cli/test/integration/shared/utils.ts index 723bf11900..cfd681187e 100644 --- a/packages/cli/test/integration/shared/utils.ts +++ b/packages/cli/test/integration/shared/utils.ts @@ -6,8 +6,6 @@ import superagent from 'superagent'; import request from 'supertest'; import { URL } from 'url'; import bodyParser from 'body-parser'; -import util from 'util'; -import { createTestAccount } from 'nodemailer'; import { set } from 'lodash'; import { CronJob } from 'cron'; import { BinaryDataManager, UserSettings } from 'n8n-core'; @@ -45,18 +43,10 @@ import { issueJWT } from '../../../src/UserManagement/auth/jwt'; import { getLogger } from '../../../src/Logger'; import { credentialsController } from '../../../src/api/credentials.api'; import { loadPublicApiVersions } from '../../../src/PublicApi/'; -import * as UserManagementMailer from '../../../src/UserManagement/email/UserManagementMailer'; import type { User } from '../../../src/databases/entities/User'; -import type { - ApiPath, - EndpointGroup, - PostgresSchemaSection, - SmtpTestAccount, - TriggerTime, -} from './types'; +import type { ApiPath, EndpointGroup, PostgresSchemaSection, TriggerTime } from './types'; import type { N8nApp } from '../../../src/UserManagement/Interfaces'; - /** * Initialize a test server. * @@ -860,45 +850,6 @@ export async function isInstanceOwnerSetUp() { return Boolean(value); } -// ---------------------------------- -// SMTP -// ---------------------------------- - -/** - * Get an SMTP test account from https://ethereal.email to test sending emails. - */ -const getSmtpTestAccount = util.promisify(createTestAccount); - -export async function configureSmtp() { - const { - user, - pass, - smtp: { host, port, secure }, - } = await getSmtpTestAccount(); - - config.set('userManagement.emails.mode', 'smtp'); - config.set('userManagement.emails.smtp.host', host); - config.set('userManagement.emails.smtp.port', port); - config.set('userManagement.emails.smtp.secure', secure); - config.set('userManagement.emails.smtp.auth.user', user); - config.set('userManagement.emails.smtp.auth.pass', pass); -} - -export async function isTestSmtpServiceAvailable() { - try { - await configureSmtp(); - await UserManagementMailer.getInstance(); - return true; - } catch (_) { - return false; - } -} - -export function skipSmtpTest(expect: jest.Expect) { - console.warn(`SMTP service unavailable - Skipping test ${expect.getState().currentTestName}`); - return; -} - // ---------------------------------- // misc // ---------------------------------- diff --git a/packages/cli/test/integration/users.api.test.ts b/packages/cli/test/integration/users.api.test.ts index a9cd270a1d..77f7cd36bc 100644 --- a/packages/cli/test/integration/users.api.test.ts +++ b/packages/cli/test/integration/users.api.test.ts @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid'; import { Db } from '../../src'; import config from '../../config'; -import { SMTP_TEST_TIMEOUT, SUCCESS_RESPONSE_BODY } from './shared/constants'; +import { SUCCESS_RESPONSE_BODY } from './shared/constants'; import { randomEmail, randomValidPassword, @@ -20,6 +20,7 @@ import * as testDb from './shared/testDb'; import { compareHash } from '../../src/UserManagement/UserManagementHelper'; jest.mock('../../src/telemetry'); +jest.mock('../../src/UserManagement/email/NodeMailer'); let app: express.Application; let testDbName = ''; @@ -27,7 +28,6 @@ let globalMemberRole: Role; let globalOwnerRole: Role; let workflowOwnerRole: Role; let credentialOwnerRole: Role; -let isSmtpAvailable = false; beforeAll(async () => { app = await utils.initTestServer({ endpointGroups: ['users'], applyAuth: true }); @@ -48,9 +48,7 @@ beforeAll(async () => { utils.initTestTelemetry(); utils.initTestLogger(); - - isSmtpAvailable = await utils.isTestSmtpServiceAvailable(); -}, SMTP_TEST_TIMEOUT); +}); beforeEach(async () => { await testDb.truncate( @@ -487,114 +485,91 @@ test('POST /users should fail if user management is disabled', async () => { expect(response.statusCode).toBe(500); }); -test( - 'POST /users should email invites and create user shells but ignore existing', - async () => { - if (!isSmtpAvailable) utils.skipSmtpTest(expect); +test('POST /users should email invites and create user shells but ignore existing', async () => { + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); + const member = await testDb.createUser({ globalRole: globalMemberRole }); + const memberShell = await testDb.createUserShell(globalMemberRole); + const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const member = await testDb.createUser({ globalRole: globalMemberRole }); - const memberShell = await testDb.createUserShell(globalMemberRole); - const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); + config.set('userManagement.emails.mode', 'smtp'); - await utils.configureSmtp(); + const testEmails = [randomEmail(), randomEmail().toUpperCase(), memberShell.email, member.email]; - const testEmails = [ - randomEmail(), - randomEmail().toUpperCase(), - memberShell.email, - member.email, - ]; + const payload = testEmails.map((e) => ({ email: e })); - const payload = testEmails.map((e) => ({ email: e })); + const response = await authOwnerAgent.post('/users').send(payload); - const response = await authOwnerAgent.post('/users').send(payload); + expect(response.statusCode).toBe(200); - expect(response.statusCode).toBe(200); + for (const { + user: { id, email: receivedEmail }, + error, + } of response.body.data) { + expect(validator.isUUID(id)).toBe(true); + expect(id).not.toBe(member.id); - for (const { - user: { id, email: receivedEmail }, - error, - } of response.body.data) { - expect(validator.isUUID(id)).toBe(true); - expect(id).not.toBe(member.id); + const lowerCasedEmail = receivedEmail.toLowerCase(); + expect(receivedEmail).toBe(lowerCasedEmail); + expect(payload.some(({ email }) => email.toLowerCase() === lowerCasedEmail)).toBe(true); - const lowerCasedEmail = receivedEmail.toLowerCase(); - expect(receivedEmail).toBe(lowerCasedEmail); - expect(payload.some(({ email }) => email.toLowerCase() === lowerCasedEmail)).toBe(true); - - if (error) { - expect(error).toBe('Email could not be sent'); - } - - const storedUser = await Db.collections.User.findOneOrFail(id); - const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } = - storedUser; - - expect(firstName).toBeNull(); - expect(lastName).toBeNull(); - expect(personalizationAnswers).toBeNull(); - expect(password).toBeNull(); - expect(resetPasswordToken).toBeNull(); + if (error) { + expect(error).toBe('Email could not be sent'); } - }, - SMTP_TEST_TIMEOUT, -); -test( - 'POST /users should fail with invalid inputs', - async () => { - if (!isSmtpAvailable) utils.skipSmtpTest(expect); + const storedUser = await Db.collections.User.findOneOrFail(id); + const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } = + storedUser; - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); + expect(firstName).toBeNull(); + expect(lastName).toBeNull(); + expect(personalizationAnswers).toBeNull(); + expect(password).toBeNull(); + expect(resetPasswordToken).toBeNull(); + } +}); - await utils.configureSmtp(); +test('POST /users should fail with invalid inputs', async () => { + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); + const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); - const invalidPayloads = [ - randomEmail(), - [randomEmail()], - {}, - [{ name: randomName() }], - [{ email: randomName() }], - ]; + config.set('userManagement.emails.mode', 'smtp'); - await Promise.all( - invalidPayloads.map(async (invalidPayload) => { - const response = await authOwnerAgent.post('/users').send(invalidPayload); - expect(response.statusCode).toBe(400); + const invalidPayloads = [ + randomEmail(), + [randomEmail()], + {}, + [{ name: randomName() }], + [{ email: randomName() }], + ]; - const users = await Db.collections.User.find(); - expect(users.length).toBe(1); // DB unaffected - }), - ); - }, - SMTP_TEST_TIMEOUT, -); + await Promise.all( + invalidPayloads.map(async (invalidPayload) => { + const response = await authOwnerAgent.post('/users').send(invalidPayload); + expect(response.statusCode).toBe(400); -test( - 'POST /users should ignore an empty payload', - async () => { - if (!isSmtpAvailable) utils.skipSmtpTest(expect); + const users = await Db.collections.User.find(); + expect(users.length).toBe(1); // DB unaffected + }), + ); +}); - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); +test('POST /users should ignore an empty payload', async () => { + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); + const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); - await utils.configureSmtp(); + config.set('userManagement.emails.mode', 'smtp'); - const response = await authOwnerAgent.post('/users').send([]); + const response = await authOwnerAgent.post('/users').send([]); - const { data } = response.body; + const { data } = response.body; - expect(response.statusCode).toBe(200); - expect(Array.isArray(data)).toBe(true); - expect(data.length).toBe(0); + expect(response.statusCode).toBe(200); + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBe(0); - const users = await Db.collections.User.find(); - expect(users.length).toBe(1); - }, - SMTP_TEST_TIMEOUT, -); + const users = await Db.collections.User.find(); + expect(users.length).toBe(1); +}); // TODO: /users/:id/reinvite route tests missing