Skip to content

Commit

Permalink
test(core): Implement timeout in SMTP tests (#3152)
Browse files Browse the repository at this point in the history
* ⚡ Implement timeout in SMTP tests

* 🚚 Move timeout to constants
  • Loading branch information
ivov authored Apr 22, 2022
1 parent 1c2ca62 commit bc5749b
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 101 deletions.
52 changes: 29 additions & 23 deletions packages/cli/test/integration/passwordReset.api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ 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');

Expand Down Expand Up @@ -40,35 +41,40 @@ beforeEach(async () => {

config.set('userManagement.isInstanceOwnerSetUp', true);
config.set('userManagement.emails.mode', '');

jest.setTimeout(30000); // fake SMTP service might be slow
});

afterAll(async () => {
await testDb.terminate(testDbName);
});

test('POST /forgot-password should send password reset email', async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole });

const authlessAgent = utils.createAgent(app);
const member = await testDb.createUser({ email: 'test@test.com', globalRole: globalMemberRole });

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);

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));
}),
);
});
test(
'POST /forgot-password should send password reset email',
async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole });

const authlessAgent = utils.createAgent(app);
const member = await testDb.createUser({
email: 'test@test.com',
globalRole: globalMemberRole,
});

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);

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,
);

test('POST /forgot-password should fail if emailing is not set up', async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/test/integration/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,8 @@ export const BOOTSTRAP_POSTGRES_CONNECTION_NAME: Readonly<string> = 'n8n_bs_post
* for each suite test run.
*/
export const BOOTSTRAP_MYSQL_CONNECTION_NAME: Readonly<string> = 'n8n_bs_mysql';

/**
* Timeout (in milliseconds) to account for fake SMTP service being slow to respond.
*/
export const SMTP_TEST_TIMEOUT = 30_000;
171 changes: 93 additions & 78 deletions packages/cli/test/integration/users.api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid';

import { Db } from '../../src';
import config from '../../config';
import { SUCCESS_RESPONSE_BODY } from './shared/constants';
import { SMTP_TEST_TIMEOUT, SUCCESS_RESPONSE_BODY } from './shared/constants';
import {
randomEmail,
randomValidPassword,
Expand Down Expand Up @@ -47,8 +47,6 @@ beforeAll(async () => {

utils.initTestTelemetry();
utils.initTestLogger();

jest.setTimeout(30000); // fake SMTP service might be slow
});

beforeEach(async () => {
Expand Down Expand Up @@ -481,91 +479,108 @@ 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 () => {
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 });

await utils.configureSmtp();

const testEmails = [randomEmail(), randomEmail().toUpperCase(), memberShell.email, member.email];

const payload = testEmails.map((e) => ({ email: e }));

const response = await authOwnerAgent.post('/users').send(payload);

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);

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();
}
});

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 });
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 });

await utils.configureSmtp();
await utils.configureSmtp();

const invalidPayloads = [
randomEmail(),
[randomEmail()],
{},
[{ name: randomName() }],
[{ email: randomName() }],
];
const testEmails = [
randomEmail(),
randomEmail().toUpperCase(),
memberShell.email,
member.email,
];

await Promise.all(
invalidPayloads.map(async (invalidPayload) => {
const response = await authOwnerAgent.post('/users').send(invalidPayload);
expect(response.statusCode).toBe(400);
const payload = testEmails.map((e) => ({ email: e }));

const users = await Db.collections.User!.find();
expect(users.length).toBe(1); // DB unaffected
}),
);
});
const response = await authOwnerAgent.post('/users').send(payload);

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 });
expect(response.statusCode).toBe(200);

await utils.configureSmtp();
for (const {
user: { id, email: receivedEmail },
error,
} of response.body.data) {
expect(validator.isUUID(id)).toBe(true);
expect(id).not.toBe(member.id);

const response = await authOwnerAgent.post('/users').send([]);
const lowerCasedEmail = receivedEmail.toLowerCase();
expect(receivedEmail).toBe(lowerCasedEmail);
expect(payload.some(({ email }) => email.toLowerCase() === lowerCasedEmail)).toBe(true);

const { data } = response.body;
if (error) {
expect(error).toBe('Email could not be sent');
}

expect(response.statusCode).toBe(200);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBe(0);
const storedUser = await Db.collections.User!.findOneOrFail(id);
const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } =
storedUser;

const users = await Db.collections.User!.find();
expect(users.length).toBe(1);
});
expect(firstName).toBeNull();
expect(lastName).toBeNull();
expect(personalizationAnswers).toBeNull();
expect(password).toBeNull();
expect(resetPasswordToken).toBeNull();
}
},
SMTP_TEST_TIMEOUT,
);

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 });

await utils.configureSmtp();

const invalidPayloads = [
randomEmail(),
[randomEmail()],
{},
[{ name: randomName() }],
[{ email: randomName() }],
];

await Promise.all(
invalidPayloads.map(async (invalidPayload) => {
const response = await authOwnerAgent.post('/users').send(invalidPayload);
expect(response.statusCode).toBe(400);

const users = await Db.collections.User!.find();
expect(users.length).toBe(1); // DB unaffected
}),
);
},
SMTP_TEST_TIMEOUT,
);

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();

const response = await authOwnerAgent.post('/users').send([]);

const { data } = response.body;

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,
);

// TODO: /users/:id/reinvite route tests missing

Expand Down

0 comments on commit bc5749b

Please sign in to comment.