🔀 Merge master

This commit is contained in:
Iván Ovejero 2022-04-22 12:49:03 +02:00
commit 8e65e46e8b
5 changed files with 119 additions and 90 deletions

View file

@ -13,6 +13,7 @@ import {
} from './shared/random'; } from './shared/random';
import * as testDb from './shared/testDb'; import * as testDb from './shared/testDb';
import type { Role } from '../../src/databases/entities/Role'; import type { Role } from '../../src/databases/entities/Role';
import { SMTP_TEST_TIMEOUT } from './shared/constants';
jest.mock('../../src/telemetry'); jest.mock('../../src/telemetry');
@ -40,35 +41,40 @@ beforeEach(async () => {
config.set('userManagement.isInstanceOwnerSetUp', true); config.set('userManagement.isInstanceOwnerSetUp', true);
config.set('userManagement.emails.mode', ''); config.set('userManagement.emails.mode', '');
jest.setTimeout(30000); // fake SMTP service might be slow
}); });
afterAll(async () => { afterAll(async () => {
await testDb.terminate(testDbName); await testDb.terminate(testDbName);
}); });
test('POST /forgot-password should send password reset email', async () => { test(
const owner = await testDb.createUser({ globalRole: globalOwnerRole }); 'POST /forgot-password should send password reset email',
async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
const authlessAgent = utils.createAgent(app); const authlessAgent = utils.createAgent(app);
const member = await testDb.createUser({ email: 'test@test.com', globalRole: globalMemberRole }); const member = await testDb.createUser({
email: 'test@test.com',
globalRole: globalMemberRole,
});
await utils.configureSmtp(); await utils.configureSmtp();
await Promise.all( await Promise.all(
[{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => { [{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => {
const response = await authlessAgent.post('/forgot-password').send(payload); const response = await authlessAgent.post('/forgot-password').send(payload);
expect(response.statusCode).toBe(200); expect(response.statusCode).toBe(200);
expect(response.body).toEqual({}); expect(response.body).toEqual({});
const user = await Db.collections.User!.findOneOrFail({ email: payload.email }); const user = await Db.collections.User!.findOneOrFail({ email: payload.email });
expect(user.resetPasswordToken).toBeDefined(); expect(user.resetPasswordToken).toBeDefined();
expect(user.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000)); 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 () => { test('POST /forgot-password should fail if emailing is not set up', async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole }); const owner = await testDb.createUser({ globalRole: globalOwnerRole });

View file

@ -57,3 +57,8 @@ export const BOOTSTRAP_POSTGRES_CONNECTION_NAME: Readonly<string> = 'n8n_bs_post
* for each suite test run. * for each suite test run.
*/ */
export const BOOTSTRAP_MYSQL_CONNECTION_NAME: Readonly<string> = 'n8n_bs_mysql'; 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;

View file

@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid';
import { Db } from '../../src'; import { Db } from '../../src';
import config from '../../config'; import config from '../../config';
import { SUCCESS_RESPONSE_BODY } from './shared/constants'; import { SMTP_TEST_TIMEOUT, SUCCESS_RESPONSE_BODY } from './shared/constants';
import { import {
randomEmail, randomEmail,
randomValidPassword, randomValidPassword,
@ -47,8 +47,6 @@ beforeAll(async () => {
utils.initTestTelemetry(); utils.initTestTelemetry();
utils.initTestLogger(); utils.initTestLogger();
jest.setTimeout(30000); // fake SMTP service might be slow
}); });
beforeEach(async () => { beforeEach(async () => {
@ -481,91 +479,108 @@ test('POST /users should fail if user management is disabled', async () => {
expect(response.statusCode).toBe(500); expect(response.statusCode).toBe(500);
}); });
test('POST /users should email invites and create user shells but ignore existing', async () => { test(
const owner = await testDb.createUser({ globalRole: globalOwnerRole }); 'POST /users should email invites and create user shells but ignore existing',
const member = await testDb.createUser({ globalRole: globalMemberRole }); async () => {
const memberShell = await testDb.createUserShell(globalMemberRole); const owner = await testDb.createUser({ globalRole: globalOwnerRole });
const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); 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 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 { for (const {
user: { id, email: receivedEmail }, user: { id, email: receivedEmail },
error, error,
} of response.body.data) { } of response.body.data) {
expect(validator.isUUID(id)).toBe(true); expect(validator.isUUID(id)).toBe(true);
expect(id).not.toBe(member.id); expect(id).not.toBe(member.id);
const lowerCasedEmail = receivedEmail.toLowerCase(); const lowerCasedEmail = receivedEmail.toLowerCase();
expect(receivedEmail).toBe(lowerCasedEmail); expect(receivedEmail).toBe(lowerCasedEmail);
expect(payload.some(({ email }) => email.toLowerCase() === lowerCasedEmail)).toBe(true); expect(payload.some(({ email }) => email.toLowerCase() === lowerCasedEmail)).toBe(true);
if (error) { if (error) {
expect(error).toBe('Email could not be sent'); 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();
} }
},
SMTP_TEST_TIMEOUT,
);
const storedUser = await Db.collections.User!.findOneOrFail(id); test(
const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } = 'POST /users should fail with invalid inputs',
storedUser; async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner });
expect(firstName).toBeNull(); await utils.configureSmtp();
expect(lastName).toBeNull();
expect(personalizationAnswers).toBeNull();
expect(password).toBeNull();
expect(resetPasswordToken).toBeNull();
}
});
test('POST /users should fail with invalid inputs', async () => { const invalidPayloads = [
const owner = await testDb.createUser({ globalRole: globalOwnerRole }); randomEmail(),
const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner }); [randomEmail()],
{},
[{ name: randomName() }],
[{ email: randomName() }],
];
await utils.configureSmtp(); await Promise.all(
invalidPayloads.map(async (invalidPayload) => {
const response = await authOwnerAgent.post('/users').send(invalidPayload);
expect(response.statusCode).toBe(400);
const invalidPayloads = [ const users = await Db.collections.User!.find();
randomEmail(), expect(users.length).toBe(1); // DB unaffected
[randomEmail()], }),
{}, );
[{ name: randomName() }], },
[{ email: randomName() }], SMTP_TEST_TIMEOUT,
]; );
await Promise.all( test(
invalidPayloads.map(async (invalidPayload) => { 'POST /users should ignore an empty payload',
const response = await authOwnerAgent.post('/users').send(invalidPayload); async () => {
expect(response.statusCode).toBe(400); const owner = await testDb.createUser({ globalRole: globalOwnerRole });
const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner });
const users = await Db.collections.User!.find(); await utils.configureSmtp();
expect(users.length).toBe(1); // DB unaffected
}),
);
});
test('POST /users should ignore an empty payload', async () => { const response = await authOwnerAgent.post('/users').send([]);
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
const authOwnerAgent = utils.createAgent(app, { auth: true, user: owner });
await utils.configureSmtp(); const { data } = response.body;
const response = await authOwnerAgent.post('/users').send([]); expect(response.statusCode).toBe(200);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBe(0);
const { data } = response.body; const users = await Db.collections.User!.find();
expect(users.length).toBe(1);
expect(response.statusCode).toBe(200); },
expect(Array.isArray(data)).toBe(true); SMTP_TEST_TIMEOUT,
expect(data.length).toBe(0); );
const users = await Db.collections.User!.find();
expect(users.length).toBe(1);
});
// TODO: /users/:id/reinvite route tests missing // TODO: /users/:id/reinvite route tests missing

View file

@ -34,8 +34,8 @@ export class SlackApi implements ICredentialType {
{ {
type: 'responseSuccessBody', type: 'responseSuccessBody',
properties: { properties: {
key: 'ok', key: 'error',
value: false, value: 'invalid_auth',
message: 'Invalid access token', message: 'Invalid access token',
}, },
}, },

View file

@ -7,7 +7,6 @@ import {
IDataObject, IDataObject,
ILoadOptionsFunctions, ILoadOptionsFunctions,
INodeExecutionData, INodeExecutionData,
INodeProperties,
INodePropertyOptions, INodePropertyOptions,
NodeApiError, NodeApiError,
} from 'n8n-workflow'; } from 'n8n-workflow';
@ -126,7 +125,11 @@ export async function quickBooksApiRequestAllItems(
const maxResults = 1000; const maxResults = 1000;
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
const maxCount = await getCount.call(this, method, endpoint, qs); const maxCountQuery = {
query: `SELECT COUNT(*) FROM ${resource}`,
} as IDataObject;
const maxCount = await getCount.call(this, method, endpoint, maxCountQuery);
const originalQuery = qs.query as string; const originalQuery = qs.query as string;