ci: Expand ESLint to tests in BE packages (no-changelog) (#6147)

* 🔧 Adjust base ESLint config

* 🔧 Adjust `lint` and `lintfix` in `nodes-base`

* 🔧 Include `test` and `utils` in `nodes-base`

* 📘 Convert JS tests to TS

* 👕 Apply lintfixes
This commit is contained in:
Iván Ovejero
2023-05-02 10:37:19 +02:00
committed by GitHub
parent c63181b317
commit 06fa6f1fb3
59 changed files with 390 additions and 307 deletions

View File

@@ -25,7 +25,7 @@ test('import:workflow should import active workflow and deactivate it', async ()
['--separate', '--input=./test/integration/commands/importWorkflows/separate'],
config,
);
const mockExit = jest.spyOn(process, 'exit').mockImplementation((number) => {
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
throw new Error('process.exit');
});
@@ -52,7 +52,7 @@ test('import:workflow should import active workflow from combined file and deact
['--input=./test/integration/commands/importWorkflows/combined/combined.json'],
config,
);
const mockExit = jest.spyOn(process, 'exit').mockImplementation((number) => {
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
throw new Error('process.exit');
});

View File

@@ -415,7 +415,7 @@ describe('PUT /credentials/:id/share', () => {
test('should respond 403 for non-existing credentials', async () => {
const response = await authOwnerAgent
.put(`/credentials/1234567/share`)
.put('/credentials/1234567/share')
.send({ shareWithIds: [member.id] });
expect(response.statusCode).toBe(403);

View File

@@ -11,9 +11,8 @@ import type { Role } from '@db/entities/Role';
import type { User } from '@db/entities/User';
import { randomCredentialPayload, randomName, randomString } from './shared/random';
import * as testDb from './shared/testDb';
import type { SaveCredentialFunction } from './shared/types';
import type { AuthAgent, SaveCredentialFunction } from './shared/types';
import * as utils from './shared/utils';
import type { AuthAgent } from './shared/types';
// mock that credentialsSharing is not enabled
const mockIsCredentialsSharingEnabled = jest.spyOn(UserManagementHelpers, 'isSharingEnabled');
@@ -124,7 +123,7 @@ describe('POST /credentials', () => {
expect(credential.name).toBe(payload.name);
expect(credential.type).toBe(payload.type);
expect(credential.nodesAccess[0].nodeType).toBe(payload.nodesAccess![0].nodeType);
expect(credential.nodesAccess[0].nodeType).toBe(payload.nodesAccess[0].nodeType);
expect(credential.data).not.toBe(payload.data);
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
@@ -278,7 +277,7 @@ describe('PATCH /credentials/:id', () => {
expect(credential.name).toBe(patchPayload.name);
expect(credential.type).toBe(patchPayload.type);
expect(credential.nodesAccess[0].nodeType).toBe(patchPayload.nodesAccess![0].nodeType);
expect(credential.nodesAccess[0].nodeType).toBe(patchPayload.nodesAccess[0].nodeType);
expect(credential.data).not.toBe(patchPayload.data);
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
@@ -315,7 +314,7 @@ describe('PATCH /credentials/:id', () => {
expect(credential.name).toBe(patchPayload.name);
expect(credential.type).toBe(patchPayload.type);
expect(credential.nodesAccess[0].nodeType).toBe(patchPayload.nodesAccess![0].nodeType);
expect(credential.nodesAccess[0].nodeType).toBe(patchPayload.nodesAccess[0].nodeType);
expect(credential.data).not.toBe(patchPayload.data);
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
@@ -352,7 +351,7 @@ describe('PATCH /credentials/:id', () => {
expect(credential.name).toBe(patchPayload.name);
expect(credential.type).toBe(patchPayload.type);
expect(credential.nodesAccess[0].nodeType).toBe(patchPayload.nodesAccess![0].nodeType);
expect(credential.nodesAccess[0].nodeType).toBe(patchPayload.nodesAccess[0].nodeType);
expect(credential.data).not.toBe(patchPayload.data);
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({

View File

@@ -1,4 +1,4 @@
import express from 'express';
import type express from 'express';
import config from '@/config';
import axios from 'axios';
import syslog from 'syslog-client';
@@ -7,23 +7,25 @@ import { Container } from 'typedi';
import type { SuperAgentTest } from 'supertest';
import * as utils from './shared/utils';
import * as testDb from './shared/testDb';
import { Role } from '@db/entities/Role';
import { User } from '@db/entities/User';
import {
defaultMessageEventBusDestinationSentryOptions,
defaultMessageEventBusDestinationSyslogOptions,
defaultMessageEventBusDestinationWebhookOptions,
import type { Role } from '@db/entities/Role';
import type { User } from '@db/entities/User';
import type {
MessageEventBusDestinationSentryOptions,
MessageEventBusDestinationSyslogOptions,
MessageEventBusDestinationWebhookOptions,
} from 'n8n-workflow';
import {
defaultMessageEventBusDestinationSentryOptions,
defaultMessageEventBusDestinationSyslogOptions,
defaultMessageEventBusDestinationWebhookOptions,
} from 'n8n-workflow';
import { eventBus } from '@/eventbus';
import { EventMessageGeneric } from '@/eventbus/EventMessageClasses/EventMessageGeneric';
import { MessageEventBusDestinationSyslog } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSyslog.ee';
import { MessageEventBusDestinationWebhook } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationWebhook.ee';
import { MessageEventBusDestinationSentry } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSentry.ee';
import type { MessageEventBusDestinationSyslog } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSyslog.ee';
import type { MessageEventBusDestinationWebhook } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationWebhook.ee';
import type { MessageEventBusDestinationSentry } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSentry.ee';
import { EventMessageAudit } from '@/eventbus/EventMessageClasses/EventMessageAudit';
import { EventNamesTypes } from '@/eventbus/EventMessageClasses';
import type { EventNamesTypes } from '@/eventbus/EventMessageClasses';
import { License } from '@/License';
jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
@@ -51,7 +53,7 @@ const testWebhookDestination: MessageEventBusDestinationWebhookOptions = {
...defaultMessageEventBusDestinationWebhookOptions,
id: '88be6560-bfb4-455c-8aa1-06971e9e5522',
url: 'http://localhost:3456',
method: `POST`,
method: 'POST',
label: 'Test Webhook',
enabled: false,
subscribedEvents: ['n8n.test.message', 'n8n.audit.user.updated'],

View File

@@ -1,4 +1,4 @@
import express from 'express';
import type express from 'express';
import type { Entry as LdapUser } from 'ldapts';
import { Not } from 'typeorm';
import { Container } from 'typedi';

View File

@@ -1,7 +1,7 @@
import type { SuperAgentTest } from 'supertest';
import config from '@/config';
import type { User } from '@db/entities/User';
import { ILicensePostResponse, ILicenseReadResponse } from '@/Interfaces';
import type { ILicensePostResponse, ILicenseReadResponse } from '@/Interfaces';
import { License } from '@/License';
import * as testDb from './shared/testDb';
import * as utils from './shared/utils';

View File

@@ -23,7 +23,7 @@ let globalOwnerRole: Role;
let globalMemberRole: Role;
let owner: User;
let authlessAgent: SuperAgentTest;
let externalHooks = utils.mockInstance(ExternalHooks);
const externalHooks = utils.mockInstance(ExternalHooks);
beforeAll(async () => {
const app = await utils.initTestServer({ endpointGroups: ['passwordReset'] });

View File

@@ -213,7 +213,7 @@ describe('GET /executions', () => {
await testDb.createErrorExecution(workflow);
const response = await authOwnerAgent.get(`/executions`).query({
const response = await authOwnerAgent.get('/executions').query({
status: 'success',
});
@@ -254,7 +254,7 @@ describe('GET /executions', () => {
await testDb.createErrorExecution(workflow);
const firstExecutionResponse = await authOwnerAgent.get(`/executions`).query({
const firstExecutionResponse = await authOwnerAgent.get('/executions').query({
status: 'success',
limit: 1,
});
@@ -263,7 +263,7 @@ describe('GET /executions', () => {
expect(firstExecutionResponse.body.data.length).toBe(1);
expect(firstExecutionResponse.body.nextCursor).toBeDefined();
const secondExecutionResponse = await authOwnerAgent.get(`/executions`).query({
const secondExecutionResponse = await authOwnerAgent.get('/executions').query({
status: 'success',
limit: 1,
cursor: firstExecutionResponse.body.nextCursor,
@@ -308,7 +308,7 @@ describe('GET /executions', () => {
const errorExecution = await testDb.createErrorExecution(workflow);
const response = await authOwnerAgent.get(`/executions`).query({
const response = await authOwnerAgent.get('/executions').query({
status: 'error',
});
@@ -348,7 +348,7 @@ describe('GET /executions', () => {
const waitingExecution = await testDb.createWaitingExecution(workflow);
const response = await authOwnerAgent.get(`/executions`).query({
const response = await authOwnerAgent.get('/executions').query({
status: 'waiting',
});
@@ -389,7 +389,7 @@ describe('GET /executions', () => {
);
await testDb.createManyExecutions(2, workflow2, testDb.createSuccessfulExecution);
const response = await authOwnerAgent.get(`/executions`).query({
const response = await authOwnerAgent.get('/executions').query({
workflowId: workflow.id,
});
@@ -439,7 +439,7 @@ describe('GET /executions', () => {
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
const response = await authOwnerAgent.get(`/executions`);
const response = await authOwnerAgent.get('/executions');
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(8);
@@ -463,7 +463,7 @@ describe('GET /executions', () => {
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
const response = await authUser1Agent.get(`/executions`);
const response = await authUser1Agent.get('/executions');
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(4);
@@ -489,7 +489,7 @@ describe('GET /executions', () => {
await testDb.shareWorkflowWithUsers(firstWorkflowForUser2, [user1]);
const response = await authUser1Agent.get(`/executions`);
const response = await authUser1Agent.get('/executions');
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(6);

View File

@@ -309,7 +309,7 @@ describe('GET /workflows/:id', () => {
test('should fail due to invalid API Key', testWithAPIKey('get', '/workflows/2', 'abcXYZ'));
test('should fail due to non-existing workflow', async () => {
const response = await authOwnerAgent.get(`/workflows/2`);
const response = await authOwnerAgent.get('/workflows/2');
expect(response.statusCode).toBe(404);
});
@@ -375,7 +375,7 @@ describe('DELETE /workflows/:id', () => {
test('should fail due to invalid API Key', testWithAPIKey('delete', '/workflows/2', 'abcXYZ'));
test('should fail due to non-existing workflow', async () => {
const response = await authOwnerAgent.delete(`/workflows/2`);
const response = await authOwnerAgent.delete('/workflows/2');
expect(response.statusCode).toBe(404);
});
@@ -447,7 +447,7 @@ describe('POST /workflows/:id/activate', () => {
);
test('should fail due to non-existing workflow', async () => {
const response = await authOwnerAgent.post(`/workflows/2/activate`);
const response = await authOwnerAgent.post('/workflows/2/activate');
expect(response.statusCode).toBe(404);
});
@@ -549,7 +549,7 @@ describe('POST /workflows/:id/deactivate', () => {
);
test('should fail due to non-existing workflow', async () => {
const response = await authOwnerAgent.post(`/workflows/2/deactivate`);
const response = await authOwnerAgent.post('/workflows/2/deactivate');
expect(response.statusCode).toBe(404);
});
@@ -709,7 +709,7 @@ describe('PUT /workflows/:id', () => {
test('should fail due to invalid API Key', testWithAPIKey('put', '/workflows/1', 'abcXYZ'));
test('should fail due to non-existing workflow', async () => {
const response = await authOwnerAgent.put(`/workflows/1`).send({
const response = await authOwnerAgent.put('/workflows/1').send({
name: 'testing',
nodes: [
{
@@ -737,7 +737,7 @@ describe('PUT /workflows/:id', () => {
});
test('should fail due to invalid body', async () => {
const response = await authOwnerAgent.put(`/workflows/1`).send({
const response = await authOwnerAgent.put('/workflows/1').send({
nodes: [
{
id: 'uuid-1234',

View File

@@ -11,8 +11,8 @@ import * as utils from '../shared/utils';
import { sampleConfig } from './sampleMetadata';
import { InternalHooks } from '@/InternalHooks';
import { SamlService } from '@/sso/saml/saml.service.ee';
import { SamlUserAttributes } from '@/sso/saml/types/samlUserAttributes';
import { AuthenticationMethod } from 'n8n-workflow';
import type { SamlUserAttributes } from '@/sso/saml/types/samlUserAttributes';
import type { AuthenticationMethod } from 'n8n-workflow';
let someUser: User;
let owner: User;

View File

@@ -1,8 +1,8 @@
import config from '@/config';
export const REST_PATH_SEGMENT = config.getEnv('endpoints.rest') as Readonly<string>;
export const REST_PATH_SEGMENT = config.getEnv('endpoints.rest');
export const PUBLIC_API_REST_PATH_SEGMENT = config.getEnv('publicApi.path') as Readonly<string>;
export const PUBLIC_API_REST_PATH_SEGMENT = config.getEnv('publicApi.path');
export const AUTHLESS_ENDPOINTS: Readonly<string[]> = [
'healthz',

View File

@@ -1,9 +1,6 @@
import { UserSettings } from 'n8n-core';
import {
DataSource as Connection,
DataSourceOptions as ConnectionOptions,
Repository,
} from 'typeorm';
import type { DataSourceOptions as ConnectionOptions, Repository } from 'typeorm';
import { DataSource as Connection } from 'typeorm';
import { Container } from 'typedi';
import config from '@/config';
@@ -24,7 +21,7 @@ import type { TagEntity } from '@db/entities/TagEntity';
import type { User } from '@db/entities/User';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { RoleRepository } from '@db/repositories';
import { ICredentialsDb } from '@/Interfaces';
import type { ICredentialsDb } from '@/Interfaces';
import { DB_INITIALIZATION_TIMEOUT } from './constants';
import { randomApiKey, randomEmail, randomName, randomString, randomValidPassword } from './random';
@@ -211,6 +208,7 @@ export async function createManyUsers(
amount: number,
attributes: Partial<User> = {},
): Promise<User[]> {
// eslint-disable-next-line prefer-const
let { email, password, firstName, lastName, globalRole, ...rest } = attributes;
if (!globalRole) {
globalRole = await getGlobalMemberRole();

View File

@@ -7,25 +7,23 @@ import { CronJob } from 'cron';
import express from 'express';
import set from 'lodash.set';
import { BinaryDataManager, UserSettings } from 'n8n-core';
import {
import type {
ICredentialType,
IDataObject,
IExecuteFunctions,
INode,
INodeExecutionData,
INodeParameters,
ITriggerFunctions,
ITriggerResponse,
LoggerProxy,
NodeHelpers,
toCronExpression,
TriggerTime,
} from 'n8n-workflow';
import superagent from 'superagent';
import { deepCopy } from 'n8n-workflow';
import { LoggerProxy, NodeHelpers, toCronExpression } from 'n8n-workflow';
import type superagent from 'superagent';
import request from 'supertest';
import { URL } from 'url';
import { mock } from 'jest-mock-extended';
import { DeepPartial } from 'ts-essentials';
import type { DeepPartial } from 'ts-essentials';
import config from '@/config';
import * as Db from '@/Db';
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
@@ -368,7 +366,7 @@ export async function initNodeTypes() {
outputs: ['main'],
properties: [],
},
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
return this.prepareOutputData(items);
@@ -571,7 +569,7 @@ export async function initNodeTypes() {
},
],
},
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
if (items.length === 0) {
@@ -585,13 +583,13 @@ export async function initNodeTypes() {
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
keepOnlySet = this.getNodeParameter('keepOnlySet', itemIndex, false) as boolean;
item = items[itemIndex];
const options = this.getNodeParameter('options', itemIndex, {}) as IDataObject;
const options = this.getNodeParameter('options', itemIndex, {});
const newItem: INodeExecutionData = {
json: {},
};
if (keepOnlySet !== true) {
if (!keepOnlySet) {
if (item.binary !== undefined) {
// Create a shallow copy of the binary data so that the old
// data references which do not get changed still stay behind
@@ -600,7 +598,7 @@ export async function initNodeTypes() {
Object.assign(newItem.binary, item.binary);
}
newItem.json = JSON.parse(JSON.stringify(item.json));
newItem.json = deepCopy(item.json);
}
// Add boolean values
@@ -708,7 +706,7 @@ export function createAuthAgent(app: express.Application) {
* Example: http://127.0.0.1:62100/me/password → http://127.0.0.1:62100/rest/me/password
*/
export function prefix(pathSegment: string) {
return function (request: superagent.SuperAgentRequest) {
return async function (request: superagent.SuperAgentRequest) {
const url = new URL(request.url);
// enforce consistency at call sites

View File

@@ -514,7 +514,7 @@ describe('UserManagementMailer expect NodeMailer.verifyConnection', () => {
test('not be called when SMTP not set up', async () => {
const userManagementMailer = new UserManagementMailer();
// NodeMailer.verifyConnection gets called only explicitly
expect(async () => await userManagementMailer.verifyConnection()).rejects.toThrow();
expect(async () => userManagementMailer.verifyConnection()).rejects.toThrow();
expect(NodeMailer.prototype.verifyConnection).toHaveBeenCalledTimes(0);
});
@@ -526,6 +526,6 @@ describe('UserManagementMailer expect NodeMailer.verifyConnection', () => {
const userManagementMailer = new UserManagementMailer();
// NodeMailer.verifyConnection gets called only explicitly
expect(async () => await userManagementMailer.verifyConnection()).not.toThrow();
expect(async () => userManagementMailer.verifyConnection()).not.toThrow();
});
});

View File

@@ -5,7 +5,6 @@ import * as testDb from './shared/testDb';
import * as utils from './shared/utils';
import type { AuthAgent } from './shared/types';
import type { ClassLike, MockedClass } from 'jest-mock';
import { License } from '@/License';
// mock that credentialsSharing is not enabled
@@ -14,7 +13,7 @@ let ownerUser: User;
let memberUser: User;
let authAgent: AuthAgent;
let variablesSpy: jest.SpyInstance<boolean>;
let licenseLike = {
const licenseLike = {
isVariablesEnabled: jest.fn().mockReturnValue(true),
getVariablesLimit: jest.fn().mockReturnValue(-1),
};

View File

@@ -1,4 +1,4 @@
import { SuperAgentTest } from 'supertest';
import type { SuperAgentTest } from 'supertest';
import type { IPinData } from 'n8n-workflow';
import type { User } from '@db/entities/User';

View File

@@ -12,14 +12,14 @@ export default async () => {
const query =
dbType === 'postgres' ? 'SELECT datname as "Database" FROM pg_database' : 'SHOW DATABASES';
const results: { Database: string }[] = await connection.query(query);
const results: Array<{ Database: string }> = await connection.query(query);
const databases = results
.filter(
({ Database: dbName }) => dbName.startsWith(`${dbType}_`) && dbName.endsWith('_n8n_test'),
)
.map(({ Database: dbName }) => dbName);
const promises = databases.map((dbName) => connection.query(`DROP DATABASE ${dbName};`));
const promises = databases.map(async (dbName) => connection.query(`DROP DATABASE ${dbName};`));
await Promise.all(promises);
await connection.destroy();
};

View File

@@ -3,13 +3,9 @@ import { ActiveExecutions } from '@/ActiveExecutions';
import { mocked } from 'jest-mock';
import PCancelable from 'p-cancelable';
import { v4 as uuid } from 'uuid';
import {
createDeferredPromise,
IDeferredPromise,
IExecuteResponsePromiseData,
IRun,
} from 'n8n-workflow';
import { IWorkflowExecutionDataProcess } from '@/Interfaces';
import type { IDeferredPromise, IExecuteResponsePromiseData, IRun } from 'n8n-workflow';
import { createDeferredPromise } from 'n8n-workflow';
import type { IWorkflowExecutionDataProcess } from '@/Interfaces';
const FAKE_EXECUTION_ID = '15';
const FAKE_SECOND_EXECUTION_ID = '20';
@@ -160,12 +156,12 @@ function mockFullRunData(): IRun {
};
}
function mockCancelablePromise(): PCancelable<IRun> {
async function mockCancelablePromise(): PCancelable<IRun> {
return new PCancelable(async (resolve) => {
resolve();
});
}
function mockDeferredPromise(): Promise<IDeferredPromise<IExecuteResponsePromiseData>> {
async function mockDeferredPromise(): Promise<IDeferredPromise<IExecuteResponsePromiseData>> {
return createDeferredPromise<IExecuteResponsePromiseData>();
}

View File

@@ -1,13 +1,8 @@
import { v4 as uuid } from 'uuid';
import { mocked } from 'jest-mock';
import {
ICredentialTypes,
INodesAndCredentials,
LoggerProxy,
NodeOperationError,
Workflow,
} from 'n8n-workflow';
import type { ICredentialTypes, INodesAndCredentials } from 'n8n-workflow';
import { LoggerProxy, NodeOperationError, Workflow } from 'n8n-workflow';
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
import * as Db from '@/Db';
@@ -22,7 +17,7 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'
import { WorkflowRunner } from '@/WorkflowRunner';
import { mock } from 'jest-mock-extended';
import { ExternalHooks } from '@/ExternalHooks';
import type { ExternalHooks } from '@/ExternalHooks';
import { Container } from 'typedi';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { mockInstance } from '../integration/shared/utils';

View File

@@ -145,7 +145,7 @@ describe('executeCommand', () => {
);
});
await expect(async () => await executeCommand('ls')).rejects.toThrow(
await expect(async () => executeCommand('ls')).rejects.toThrow(
RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND,
);

View File

@@ -1,4 +1,4 @@
import {
import type {
IAuthenticateGeneric,
ICredentialDataDecryptedObject,
ICredentialType,
@@ -7,8 +7,9 @@ import {
INode,
INodeProperties,
INodesAndCredentials,
Workflow,
} from 'n8n-workflow';
import { deepCopy } from 'n8n-workflow';
import { Workflow } from 'n8n-workflow';
import { CredentialsHelper } from '@/CredentialsHelper';
import { CredentialTypes } from '@/CredentialTypes';
import { Container } from 'typedi';
@@ -82,7 +83,9 @@ describe('CredentialsHelper', () => {
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'User',
@@ -124,7 +127,9 @@ describe('CredentialsHelper', () => {
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'Access Token',
@@ -154,7 +159,9 @@ describe('CredentialsHelper', () => {
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'Access Token',
@@ -184,7 +191,9 @@ describe('CredentialsHelper', () => {
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'Access Token',
@@ -215,7 +224,9 @@ describe('CredentialsHelper', () => {
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'My Token',
@@ -229,8 +240,8 @@ describe('CredentialsHelper', () => {
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
requestOptions.headers!['Authorization'] = `Bearer ${credentials.accessToken}`;
requestOptions.qs!['user'] = credentials.user;
requestOptions.headers!.Authorization = `Bearer ${credentials.accessToken}`;
requestOptions.qs!.user = credentials.user;
return requestOptions;
}
})(),
@@ -287,7 +298,7 @@ describe('CredentialsHelper', () => {
const result = await credentialsHelper.authenticate(
testData.input.credentials,
testData.input.credentialType.name,
JSON.parse(JSON.stringify(incomingRequestOptions)),
deepCopy(incomingRequestOptions),
workflow,
node,
timezone,

View File

@@ -17,7 +17,8 @@ describe('CurlConverterHelper', () => {
});
test('Should parse JSON content type correctly', () => {
const curl = `curl -X POST https://reqbin.com/echo/post/json -H 'Content-Type: application/json' -d '{"login":"my_login","password":"my_password"}'`;
const curl =
'curl -X POST https://reqbin.com/echo/post/json -H \'Content-Type: application/json\' -d \'{"login":"my_login","password":"my_password"}\'';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
expect(parameters.sendBody).toBe(true);
@@ -31,7 +32,8 @@ describe('CurlConverterHelper', () => {
});
test('Should parse multipart-form-data content type correctly', () => {
const curl = `curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename`;
const curl =
'curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
expect(parameters.sendBody).toBe(true);
@@ -46,7 +48,8 @@ describe('CurlConverterHelper', () => {
});
test('Should parse binary request correctly', () => {
const curl = `curl --location --request POST 'https://www.website.com' --header 'Content-Type: image/png' --data-binary '@/Users/image.png`;
const curl =
"curl --location --request POST 'https://www.website.com' --header 'Content-Type: image/png' --data-binary '@/Users/image.png";
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://www.website.com');
expect(parameters.method).toBe('POST');
@@ -74,7 +77,8 @@ describe('CurlConverterHelper', () => {
});
test('Should parse header properties and keep the original case', () => {
const curl = `curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename -H "ACCEPT: text/javascript" -H "content-type: multipart/form-data"`;
const curl =
'curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename -H "ACCEPT: text/javascript" -H "content-type: multipart/form-data"';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
expect(parameters.sendBody).toBe(true);
@@ -91,7 +95,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse querystring properties', () => {
const curl = `curl -G -d 'q=kitties' -d 'count=20' https://google.com/search`;
const curl = "curl -G -d 'q=kitties' -d 'count=20' https://google.com/search";
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://google.com/search');
expect(parameters.sendBody).toBe(false);
@@ -105,7 +109,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse basic authentication property and keep the original case', () => {
const curl = `curl https://reqbin.com/echo -u "login:password"`;
const curl = 'curl https://reqbin.com/echo -u "login:password"';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -119,7 +123,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse location flag with --location', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" --location`;
const curl = 'curl https://reqbin.com/echo -u "login:password" --location';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -134,7 +138,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse location flag with --L', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" -L`;
const curl = 'curl https://reqbin.com/echo -u "login:password" -L';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -149,7 +153,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse location and max redirects flags with --location and --max-redirs 10', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" --location --max-redirs 10`;
const curl = 'curl https://reqbin.com/echo -u "login:password" --location --max-redirs 10';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -165,7 +169,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse proxy flag -x', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" -x https://google.com`;
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -180,7 +184,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse proxy flag --proxy', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" -x https://google.com`;
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -195,7 +199,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse include headers on output flag --include', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" --include -x https://google.com`;
const curl = 'curl https://reqbin.com/echo -u "login:password" --include -x https://google.com';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -210,7 +214,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse include headers on output flag -i', () => {
const curl = `curl https://reqbin.com/echo -u "login:password" -x https://google.com -i`;
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com -i';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.sendBody).toBe(false);
@@ -225,7 +229,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse include request flag -X', () => {
const curl = `curl -X POST https://reqbin.com/echo -u "login:password" -x https://google.com`;
const curl = 'curl -X POST https://reqbin.com/echo -u "login:password" -x https://google.com';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');
@@ -233,7 +237,8 @@ describe('CurlConverterHelper', () => {
});
test('Should parse include request flag --request', () => {
const curl = `curl --request POST https://reqbin.com/echo -u "login:password" -x https://google.com`;
const curl =
'curl --request POST https://reqbin.com/echo -u "login:password" -x https://google.com';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');
@@ -241,7 +246,8 @@ describe('CurlConverterHelper', () => {
});
test('Should parse include timeout flag --connect-timeout', () => {
const curl = `curl --request POST https://reqbin.com/echo -u "login:password" --connect-timeout 20`;
const curl =
'curl --request POST https://reqbin.com/echo -u "login:password" --connect-timeout 20';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');
@@ -250,7 +256,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse download file flag -O', () => {
const curl = `curl --request POST https://reqbin.com/echo -u "login:password" -O`;
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -O';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');
@@ -260,7 +266,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse download file flag -o', () => {
const curl = `curl --request POST https://reqbin.com/echo -u "login:password" -o`;
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -o';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');
@@ -270,7 +276,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse ignore SSL flag -k', () => {
const curl = `curl --request POST https://reqbin.com/echo -u "login:password" -k`;
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -k';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');
@@ -279,7 +285,7 @@ describe('CurlConverterHelper', () => {
});
test('Should parse ignore SSL flag --insecure', () => {
const curl = `curl --request POST https://reqbin.com/echo -u "login:password" --insecure`;
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" --insecure';
const parameters = toHttpNodeParameters(curl);
expect(parameters.url).toBe('https://reqbin.com/echo');
expect(parameters.method).toBe('POST');

View File

@@ -1,12 +1,13 @@
import { IRun, LoggerProxy, WorkflowExecuteMode } from 'n8n-workflow';
import type { IRun, WorkflowExecuteMode } from 'n8n-workflow';
import { LoggerProxy } from 'n8n-workflow';
import { QueryFailedError } from 'typeorm';
import { mock } from 'jest-mock-extended';
import config from '@/config';
import * as Db from '@/Db';
import { User } from '@db/entities/User';
import { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
import { WorkflowStatisticsRepository } from '@db/repositories';
import type { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
import type { WorkflowStatisticsRepository } from '@db/repositories';
import { nodeFetchedData, workflowExecutionCompleted } from '@/events/WorkflowStatistics';
import * as UserManagementHelper from '@/UserManagement/UserManagementHelper';
import { getLogger } from '@/Logger';

View File

@@ -1,4 +1,4 @@
import { INodeTypeData } from 'n8n-workflow';
import type { INodeTypeData } from 'n8n-workflow';
/**
* Ensure all pending promises settle. The promise's `resolve` is placed in
@@ -29,7 +29,7 @@ export function mockNodeTypesData(
outputs: [],
properties: [],
},
trigger: options?.addTrigger ? () => Promise.resolve(undefined) : undefined,
trigger: options?.addTrigger ? async () => undefined : undefined,
},
}),
acc

View File

@@ -1,6 +1,7 @@
import { v4 as uuid } from 'uuid';
import { Container } from 'typedi';
import { ICredentialTypes, INodeTypes, SubworkflowOperationError, Workflow } from 'n8n-workflow';
import type { ICredentialTypes, INodeTypes } from 'n8n-workflow';
import { SubworkflowOperationError, Workflow } from 'n8n-workflow';
import config from '@/config';
import * as Db from '@/Db';
@@ -79,7 +80,7 @@ describe('PermissionChecker.check()', () => {
],
});
expect(() => PermissionChecker.check(workflow, userId)).not.toThrow();
expect(async () => PermissionChecker.check(workflow, userId)).not.toThrow();
});
test('should allow if requesting user is instance owner', async () => {
@@ -109,7 +110,7 @@ describe('PermissionChecker.check()', () => {
],
});
expect(async () => await PermissionChecker.check(workflow, owner.id)).not.toThrow();
expect(async () => PermissionChecker.check(workflow, owner.id)).not.toThrow();
});
test('should allow if workflow creds are valid subset', async () => {
@@ -156,7 +157,7 @@ describe('PermissionChecker.check()', () => {
],
});
expect(async () => await PermissionChecker.check(workflow, owner.id)).not.toThrow();
expect(async () => PermissionChecker.check(workflow, owner.id)).not.toThrow();
});
test('should deny if workflow creds are not valid subset', async () => {

View File

@@ -24,7 +24,7 @@ describe('PostHog', () => {
const ph = new PostHogClient();
await ph.init(instanceId);
expect(PostHog.prototype.constructor).toHaveBeenCalledWith(apiKey, {host: apiHost});
expect(PostHog.prototype.constructor).toHaveBeenCalledWith(apiKey, { host: apiHost });
});
it('does not initialize or track if diagnostics are not enabled', async () => {
@@ -78,13 +78,10 @@ describe('PostHog', () => {
createdAt,
});
expect(PostHog.prototype.getAllFlags).toHaveBeenCalledWith(
`${instanceId}#${userId}`,
{
personProperties: {
created_at_timestamp: createdAt.getTime().toString(),
},
}
);
expect(PostHog.prototype.getAllFlags).toHaveBeenCalledWith(`${instanceId}#${userId}`, {
personProperties: {
created_at_timestamp: createdAt.getTime().toString(),
},
});
});
});
});

View File

@@ -12,16 +12,16 @@ async function mockFind({
type: string;
}): Promise<IWorkflowCredentials | null> {
// Simple statement that maps a return value based on the `id` parameter
if (id === notFoundNode.credentials!!.test.id) {
if (id === notFoundNode.credentials!.test.id) {
return null;
}
// Otherwise just build some kind of credential object and return it
return {
[type]: {
[id]: {
id: id,
id,
name: type,
type: type,
type,
nodesAccess: [],
data: '',
},
@@ -49,7 +49,7 @@ describe('WorkflowCredentials', () => {
});
test('Should return an error if any node has no credential ID', () => {
const credentials = noIdNode.credentials!!.test;
const credentials = noIdNode.credentials!.test;
const expectedError = new Error(
`Credentials with name "${credentials.name}" for type "test" miss an ID.`,
);
@@ -58,7 +58,7 @@ describe('WorkflowCredentials', () => {
});
test('Should return an error if credentials cannot be found in the DB', () => {
const credentials = notFoundNode.credentials!!.test;
const credentials = notFoundNode.credentials!.test;
const expectedError = new Error(
`Could not find credentials for type "test" with ID "${credentials.id}".`,
);

View File

@@ -1,4 +1,5 @@
import { INode, LoggerProxy } from 'n8n-workflow';
import type { INode } from 'n8n-workflow';
import { LoggerProxy } from 'n8n-workflow';
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
import { getNodesWithInaccessibleCreds, validateWorkflowCredentialUsage } from '@/WorkflowHelpers';

View File

@@ -1,11 +1,10 @@
import { CookieOptions, Response } from 'express';
import type { Repository } from 'typeorm';
import type { CookieOptions, Response } from 'express';
import jwt from 'jsonwebtoken';
import { mock, anyObject, captor } from 'jest-mock-extended';
import type { ILogger } from 'n8n-workflow';
import type { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
import type { User } from '@db/entities/User';
import { UserRepository } from '@db/repositories';
import type { UserRepository } from '@db/repositories';
import { MeController } from '@/controllers';
import { AUTH_COOKIE_NAME } from '@/constants';
import { BadRequestError } from '@/ResponseHelper';

View File

@@ -1,9 +1,9 @@
import { mock } from 'jest-mock-extended';
import type { ICredentialTypes } from 'n8n-workflow';
import type { Config } from '@/config';
import type { TranslationRequest } from '@/controllers/translation.controller';
import {
TranslationController,
TranslationRequest,
CREDENTIAL_TRANSLATIONS_DIR,
} from '@/controllers/translation.controller';
import { BadRequestError } from '@/ResponseHelper';

View File

@@ -1,7 +1,8 @@
import { Container } from 'typedi';
import { DataSource, EntityManager } from 'typeorm';
import { mock } from 'jest-mock-extended';
import { Role, RoleNames, RoleScopes } from '@db/entities/Role';
import type { RoleNames, RoleScopes } from '@db/entities/Role';
import { Role } from '@db/entities/Role';
import { RoleRepository } from '@db/repositories/role.repository';
import { mockInstance } from '../../integration/shared/utils';
import { randomInteger } from '../../integration/shared/random';
@@ -38,7 +39,7 @@ describe('RoleRepository', () => {
test('should throw otherwise', async () => {
entityManager.findOneOrFail.mockRejectedValueOnce(new Error());
expect(() => roleRepository.findRoleOrFail('global', 'owner')).rejects.toThrow();
expect(async () => roleRepository.findRoleOrFail('global', 'owner')).rejects.toThrow();
});
});