mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-12 16:10:30 +02:00
fix(core): Add ESLint rule to prevent error instances in toThrow assertions (#29889)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
73dae68663
commit
75ed71c001
|
|
@ -414,6 +414,7 @@ export const baseConfig = tseslint.config(
|
|||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'n8n-local-rules/no-skipped-tests': process.env.NODE_ENV === 'development' ? 'warn' : 'error',
|
||||
'n8n-local-rules/no-error-instance-in-to-throw': 'error',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { NoArgumentSpreadRule } from './no-argument-spread.js';
|
|||
import { NoInternalPackageImportRule } from './no-internal-package-import.js';
|
||||
import { NoImportEnterpriseEditionRule } from './no-import-enterprise-edition.js';
|
||||
import { NoTypeOnlyImportInDiRule } from './no-type-only-import-in-di.js';
|
||||
import { NoErrorInstanceInToThrowRule } from './no-error-instance-in-to-throw.js';
|
||||
|
||||
export const rules = {
|
||||
'no-uncaught-json-parse': NoUncaughtJsonParseRule,
|
||||
|
|
@ -37,4 +38,5 @@ export const rules = {
|
|||
'no-internal-package-import': NoInternalPackageImportRule,
|
||||
'no-import-enterprise-edition': NoImportEnterpriseEditionRule,
|
||||
'no-type-only-import-in-di': NoTypeOnlyImportInDiRule,
|
||||
'no-error-instance-in-to-throw': NoErrorInstanceInToThrowRule,
|
||||
} satisfies Record<string, AnyRuleModule>;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { RuleTester } from '@typescript-eslint/rule-tester';
|
||||
import { NoErrorInstanceInToThrowRule } from './no-error-instance-in-to-throw.js';
|
||||
|
||||
const ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run('no-error-instance-in-to-throw', NoErrorInstanceInToThrowRule, {
|
||||
valid: [
|
||||
// Passing a class reference is fine
|
||||
{ code: 'expect(() => foo()).toThrow(NodeOperationError)' },
|
||||
// Passing a string is fine
|
||||
{ code: "expect(() => foo()).toThrow('expected message')" },
|
||||
// Passing a regex is fine
|
||||
{ code: 'expect(() => foo()).toThrow(/expected/)' },
|
||||
// No argument is fine
|
||||
{ code: 'expect(() => foo()).toThrow()' },
|
||||
// Async with class reference is fine
|
||||
{ code: 'await expect(foo()).rejects.toThrow(NodeOperationError)' },
|
||||
// Async with string is fine
|
||||
{ code: "await expect(foo()).rejects.toThrow('expected message')" },
|
||||
// NewExpression not inside toThrow is fine
|
||||
{ code: 'const err = new Error("test")' },
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: "expect(() => foo()).toThrow(new Error('bad'))",
|
||||
errors: [{ messageId: 'noErrorInstance', data: { className: 'Error' } }],
|
||||
},
|
||||
{
|
||||
code: "expect(() => foo()).toThrow(new NodeOperationError(node, 'bad'))",
|
||||
errors: [{ messageId: 'noErrorInstance', data: { className: 'NodeOperationError' } }],
|
||||
},
|
||||
{
|
||||
code: "await expect(foo()).rejects.toThrow(new Error('bad'))",
|
||||
errors: [{ messageId: 'noErrorInstance', data: { className: 'Error' } }],
|
||||
},
|
||||
{
|
||||
code: "await expect(foo()).rejects.toThrow(new NodeOperationError(node, 'message'))",
|
||||
errors: [{ messageId: 'noErrorInstance', data: { className: 'NodeOperationError' } }],
|
||||
},
|
||||
{
|
||||
code: 'expect(() => foo()).toThrow(new TypeError())',
|
||||
errors: [{ messageId: 'noErrorInstance', data: { className: 'TypeError' } }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoErrorInstanceInToThrowRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Disallow passing error instances to `.toThrow()`. Jest compares by reference, not message, making assertions flaky. Pass the error class and message string separately instead.',
|
||||
},
|
||||
messages: {
|
||||
noErrorInstance:
|
||||
"Do not pass an error instance to `.toThrow()`. Use `.toThrow({{className}})` for type checking and `.toThrow('message')` for message matching.",
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
// Match: expect(...).toThrow(new Foo(...))
|
||||
// Match: expect(...).rejects.toThrow(new Foo(...))
|
||||
if (
|
||||
node.callee.type !== TSESTree.AST_NODE_TYPES.MemberExpression ||
|
||||
node.callee.property.type !== TSESTree.AST_NODE_TYPES.Identifier ||
|
||||
node.callee.property.name !== 'toThrow'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Must have exactly one argument that is a NewExpression
|
||||
if (
|
||||
node.arguments.length !== 1 ||
|
||||
node.arguments[0].type !== TSESTree.AST_NODE_TYPES.NewExpression
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newExpr = node.arguments[0];
|
||||
const className =
|
||||
newExpr.callee.type === TSESTree.AST_NODE_TYPES.Identifier
|
||||
? newExpr.callee.name
|
||||
: 'ErrorClass';
|
||||
|
||||
context.report({
|
||||
messageId: 'noErrorInstance',
|
||||
node: node.arguments[0],
|
||||
data: { className },
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -2128,11 +2128,9 @@ describe('GoogleGemini Node', () => {
|
|||
});
|
||||
executeFunctionsMock.getNode.mockReturnValue({ name: 'Google Gemini' } as INode);
|
||||
|
||||
await expect(video.generate.execute.call(executeFunctionsMock, 0)).rejects.toThrow(
|
||||
new NodeOperationError(executeFunctionsMock.getNode(), 'Failed to generate video', {
|
||||
description: 'Error generating video',
|
||||
}),
|
||||
);
|
||||
const promise = video.generate.execute.call(executeFunctionsMock, 0);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Failed to generate video');
|
||||
});
|
||||
|
||||
it('should throw error for non-Veo model', async () => {
|
||||
|
|
@ -2149,14 +2147,10 @@ describe('GoogleGemini Node', () => {
|
|||
|
||||
executeFunctionsMock.getNode.mockReturnValue({ name: 'Google Gemini' } as INode);
|
||||
|
||||
await expect(video.generate.execute.call(executeFunctionsMock, 0)).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
executeFunctionsMock.getNode(),
|
||||
'Model models/gemini-2.0-flash is not supported for video generation. Please use a Veo model',
|
||||
{
|
||||
description: 'Video generation is only supported by Veo models',
|
||||
},
|
||||
),
|
||||
const promise = video.generate.execute.call(executeFunctionsMock, 0);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Model models/gemini-2.0-flash is not supported for video generation. Please use a Veo model',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -282,11 +282,9 @@ describe('GoogleGemini -> utils', () => {
|
|||
|
||||
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Google Gemini' } as any);
|
||||
|
||||
await expect(uploadFile.call(mockExecuteFunctions, fileContent, mimeType)).rejects.toThrow(
|
||||
new NodeOperationError(mockExecuteFunctions.getNode(), 'Upload failed', {
|
||||
description: 'Error uploading file',
|
||||
}),
|
||||
);
|
||||
const promise = uploadFile.call(mockExecuteFunctions, fileContent, mimeType);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Upload failed');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -463,17 +461,14 @@ describe('GoogleGemini -> utils', () => {
|
|||
mockExecuteFunctions.getNodeParameter.mockReturnValue('');
|
||||
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Google Gemini' } as any);
|
||||
|
||||
await expect(
|
||||
transferFile.call(mockExecuteFunctions, 0, undefined, 'application/octet-stream'),
|
||||
).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockExecuteFunctions.getNode(),
|
||||
'Binary property name or download URL is required',
|
||||
{
|
||||
description: 'Error uploading file',
|
||||
},
|
||||
),
|
||||
const promise = transferFile.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
undefined,
|
||||
'application/octet-stream',
|
||||
);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Binary property name or download URL is required');
|
||||
});
|
||||
|
||||
it('should throw error when upload URL is not received', async () => {
|
||||
|
|
@ -495,16 +490,14 @@ describe('GoogleGemini -> utils', () => {
|
|||
|
||||
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Google Gemini' } as any);
|
||||
|
||||
await expect(
|
||||
transferFile.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
'https://example.com/file.pdf',
|
||||
'application/octet-stream',
|
||||
),
|
||||
).rejects.toThrow(
|
||||
new NodeOperationError(mockExecuteFunctions.getNode(), 'Failed to get upload URL'),
|
||||
const promise = transferFile.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
'https://example.com/file.pdf',
|
||||
'application/octet-stream',
|
||||
);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Failed to get upload URL');
|
||||
});
|
||||
|
||||
it('should poll until file is active and throw error on failure', async () => {
|
||||
|
|
@ -552,18 +545,14 @@ describe('GoogleGemini -> utils', () => {
|
|||
|
||||
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Google Gemini' } as any);
|
||||
|
||||
await expect(
|
||||
transferFile.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
'https://example.com/file.pdf',
|
||||
'application/octet-stream',
|
||||
),
|
||||
).rejects.toThrow(
|
||||
new NodeOperationError(mockExecuteFunctions.getNode(), 'Processing failed', {
|
||||
description: 'Error uploading file',
|
||||
}),
|
||||
const promise = transferFile.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
'https://example.com/file.pdf',
|
||||
'application/octet-stream',
|
||||
);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Processing failed');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -881,19 +870,15 @@ describe('GoogleGemini -> utils', () => {
|
|||
|
||||
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Google Gemini' } as any);
|
||||
|
||||
await expect(
|
||||
uploadToFileSearchStore.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
fileSearchStoreName,
|
||||
displayName,
|
||||
'https://example.com/file.pdf',
|
||||
),
|
||||
).rejects.toThrow(
|
||||
new NodeOperationError(mockExecuteFunctions.getNode(), 'Upload failed', {
|
||||
description: 'Error uploading file to File Search store',
|
||||
}),
|
||||
const promise = uploadToFileSearchStore.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
fileSearchStoreName,
|
||||
displayName,
|
||||
'https://example.com/file.pdf',
|
||||
);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Upload failed');
|
||||
});
|
||||
|
||||
it('should throw error when binary property name is missing', async () => {
|
||||
|
|
@ -903,17 +888,14 @@ describe('GoogleGemini -> utils', () => {
|
|||
mockExecuteFunctions.getNodeParameter.mockReturnValue('');
|
||||
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Google Gemini' } as any);
|
||||
|
||||
await expect(
|
||||
uploadToFileSearchStore.call(mockExecuteFunctions, 0, fileSearchStoreName, displayName),
|
||||
).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockExecuteFunctions.getNode(),
|
||||
'Binary property name or download URL is required',
|
||||
{
|
||||
description: 'Error uploading file',
|
||||
},
|
||||
),
|
||||
const promise = uploadToFileSearchStore.call(
|
||||
mockExecuteFunctions,
|
||||
0,
|
||||
fileSearchStoreName,
|
||||
displayName,
|
||||
);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Binary property name or download URL is required');
|
||||
});
|
||||
|
||||
it('should return undefined when response is missing', async () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { ExecutionError } from '@/js-task-runner/errors/execution-error';
|
||||
|
||||
import { DisallowedModuleError } from '../errors/disallowed-module.error';
|
||||
import { createRequireResolver, type RequireResolverOpts } from '../require-resolver';
|
||||
|
||||
describe('require resolver', () => {
|
||||
|
|
@ -45,9 +44,8 @@ describe('require resolver', () => {
|
|||
|
||||
it('should throw when requiring non-allowlisted external modules', () => {
|
||||
const resolver = createRequireResolver(defaultOpts);
|
||||
expect(() => resolver('express')).toThrow(
|
||||
new ExecutionError(new DisallowedModuleError('express')),
|
||||
);
|
||||
expect(() => resolver('express')).toThrow(ExecutionError);
|
||||
expect(() => resolver('express')).toThrow('express');
|
||||
});
|
||||
|
||||
it('should allow all external modules when allowedExternalModules is "*"', () => {
|
||||
|
|
|
|||
|
|
@ -114,8 +114,10 @@ describe('EmailAuthHandler', () => {
|
|||
userRepository.findOne.mockResolvedValue(user);
|
||||
globalConfig.sso.ldap.loginEnabled = false;
|
||||
|
||||
await expect(handler.handleLogin(email, password)).rejects.toThrow(
|
||||
new AuthError('Reset your password to gain access to the instance.'),
|
||||
const promise = handler.handleLogin(email, password);
|
||||
await expect(promise).rejects.toThrow(AuthError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Reset your password to gain access to the instance.',
|
||||
);
|
||||
|
||||
expect(eventService.emit).toHaveBeenCalledWith('login-failed-due-to-ldap-disabled', {
|
||||
|
|
|
|||
|
|
@ -256,10 +256,10 @@ describe('AuthController', () => {
|
|||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError(
|
||||
'Invite links are not supported on this system, please use single sign on instead.',
|
||||
),
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Invite links are not supported on this system, please use single sign on instead.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -295,9 +295,9 @@ describe('AuthController', () => {
|
|||
});
|
||||
jest.spyOn(license, 'isWithinUsersLimit').mockReturnValue(false);
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new ForbiddenError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED),
|
||||
);
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
||||
});
|
||||
|
||||
it('throws a BadRequestError if the users are not found', async () => {
|
||||
|
|
@ -333,9 +333,9 @@ describe('AuthController', () => {
|
|||
jest.spyOn(license, 'isWithinUsersLimit').mockReturnValue(true);
|
||||
jest.spyOn(userRepository, 'findManyByIds').mockResolvedValue([]);
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('Invalid invite URL'),
|
||||
);
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid invite URL');
|
||||
});
|
||||
|
||||
it('throws a BadRequestError if the invitee already has a password', async () => {
|
||||
|
|
@ -380,8 +380,10 @@ describe('AuthController', () => {
|
|||
}),
|
||||
]);
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('The invitation was likely either deleted or already claimed'),
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'The invitation was likely either deleted or already claimed',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -429,9 +431,9 @@ describe('AuthController', () => {
|
|||
}),
|
||||
]);
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('Invalid request'),
|
||||
);
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid request');
|
||||
});
|
||||
|
||||
it('returns the inviter if the invitation is valid', async () => {
|
||||
|
|
@ -578,9 +580,9 @@ describe('AuthController', () => {
|
|||
.spyOn(userService, 'getInvitationIdsFromPayload')
|
||||
.mockRejectedValue(new BadRequestError('Invalid invite URL'));
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('Invalid invite URL'),
|
||||
);
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid invite URL');
|
||||
});
|
||||
|
||||
it('throws BadRequestError if JWT token payload is missing inviterId or inviteeId', async () => {
|
||||
|
|
@ -612,9 +614,9 @@ describe('AuthController', () => {
|
|||
.spyOn(userService, 'getInvitationIdsFromPayload')
|
||||
.mockRejectedValue(new BadRequestError('Invalid invite URL'));
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('Invalid invite URL'),
|
||||
);
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid invite URL');
|
||||
});
|
||||
|
||||
it('throws BadRequestError if token is missing', async () => {
|
||||
|
|
@ -642,9 +644,9 @@ describe('AuthController', () => {
|
|||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(authController.resolveSignupToken(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('Token is required'),
|
||||
);
|
||||
const promise = authController.resolveSignupToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Token is required');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ describe('InvitationController', () => {
|
|||
const req = mock<AuthenticatedRequest>({ user });
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(invitationController.inviteUser(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError(
|
||||
'SSO is enabled, so users are managed by the Identity Provider and cannot be added through invites',
|
||||
),
|
||||
const promise = invitationController.inviteUser(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'SSO is enabled, so users are managed by the Identity Provider and cannot be added through invites',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -103,9 +103,9 @@ describe('InvitationController', () => {
|
|||
const req = mock<AuthenticatedRequest>({ user });
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(invitationController.inviteUser(req, res, payload)).rejects.toThrow(
|
||||
new ForbiddenError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED),
|
||||
);
|
||||
const promise = invitationController.inviteUser(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
||||
});
|
||||
|
||||
it('throws a BadRequestError if the owner account is not set up', async () => {
|
||||
|
|
@ -129,8 +129,10 @@ describe('InvitationController', () => {
|
|||
const req = mock<AuthenticatedRequest>({ user });
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(invitationController.inviteUser(req, res, payload)).rejects.toThrow(
|
||||
new BadRequestError('You must set up your own account before inviting others'),
|
||||
const promise = invitationController.inviteUser(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'You must set up your own account before inviting others',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -163,10 +165,10 @@ describe('InvitationController', () => {
|
|||
const req = mock<AuthenticatedRequest>({ user });
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(invitationController.inviteUser(req, res, payload)).rejects.toThrow(
|
||||
new ForbiddenError(
|
||||
'Cannot invite admin user without advanced permissions. Please upgrade to a license that includes this feature.',
|
||||
),
|
||||
const promise = invitationController.inviteUser(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Cannot invite admin user without advanced permissions. Please upgrade to a license that includes this feature.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -244,12 +246,10 @@ describe('InvitationController', () => {
|
|||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(
|
||||
invitationController.acceptInvitationWithToken(req, res, payload),
|
||||
).rejects.toThrow(
|
||||
new BadRequestError(
|
||||
'Invite links are not supported on this system, please use single sign on instead.',
|
||||
),
|
||||
const promise = invitationController.acceptInvitationWithToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Invite links are not supported on this system, please use single sign on instead.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -269,9 +269,9 @@ describe('InvitationController', () => {
|
|||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(
|
||||
invitationController.acceptInvitationWithToken(req, res, payload),
|
||||
).rejects.toThrow(new BadRequestError('Token is required'));
|
||||
const promise = invitationController.acceptInvitationWithToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Token is required');
|
||||
});
|
||||
|
||||
it('accepts the invitation successfully with JWT token', async () => {
|
||||
|
|
@ -365,9 +365,9 @@ describe('InvitationController', () => {
|
|||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(
|
||||
invitationController.acceptInvitationWithToken(req, res, payload),
|
||||
).rejects.toThrow(new BadRequestError('Invalid payload or URL'));
|
||||
const promise = invitationController.acceptInvitationWithToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid payload or URL');
|
||||
});
|
||||
|
||||
it('throws a BadRequestError if invitee already has a password', async () => {
|
||||
|
|
@ -408,9 +408,9 @@ describe('InvitationController', () => {
|
|||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
await expect(
|
||||
invitationController.acceptInvitationWithToken(req, res, payload),
|
||||
).rejects.toThrow(new BadRequestError('This invite has been accepted already'));
|
||||
const promise = invitationController.acceptInvitationWithToken(req, res, payload);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('This invite has been accepted already');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -80,8 +80,10 @@ describe('TelegramIntegration.onBeforeConnect', () => {
|
|||
makeAgent('agent-other', 'Agent Other', [{ type: 'telegram', credentialId: 'cred-1' }]),
|
||||
]);
|
||||
|
||||
await expect(integration.onBeforeConnect(makeContext())).rejects.toThrow(
|
||||
new ConflictError('Telegram credential is already connected to agent "Agent Other"'),
|
||||
const promise = integration.onBeforeConnect(makeContext());
|
||||
await expect(promise).rejects.toThrow(ConflictError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Telegram credential is already connected to agent "Agent Other"',
|
||||
);
|
||||
// Telegram API must not be called once the DB already indicates a conflict.
|
||||
expect(fetchSpy).not.toHaveBeenCalled();
|
||||
|
|
@ -119,8 +121,10 @@ describe('TelegramIntegration.onBeforeConnect', () => {
|
|||
makeAgent('agent-b', 'Beta', [{ type: 'telegram', credentialId: 'cred-1' }]),
|
||||
]);
|
||||
|
||||
await expect(integration.onBeforeConnect(makeContext())).rejects.toThrow(
|
||||
new ConflictError('Telegram credential is already connected to agent "Alpha"'),
|
||||
const promise = integration.onBeforeConnect(makeContext());
|
||||
await expect(promise).rejects.toThrow(ConflictError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Telegram credential is already connected to agent "Alpha"',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ describe('ChatHubCredentialsService', () => {
|
|||
it('should throw ForbiddenError when user does not have access to the credential', async () => {
|
||||
credentialsFinderService.findCredentialForUser.mockResolvedValue(null);
|
||||
|
||||
await expect(service.ensureCredentialAccess(mockUser, CREDENTIAL_ID)).rejects.toThrow(
|
||||
new ForbiddenError("You don't have access to the provided credentials"),
|
||||
);
|
||||
const promise = service.ensureCredentialAccess(mockUser, CREDENTIAL_ID);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow("You don't have access to the provided credentials");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -90,9 +90,9 @@ describe('ChatHubCredentialsService', () => {
|
|||
it('should throw ForbiddenError when no personal project is found', async () => {
|
||||
projectRepository.getPersonalProjectForUser.mockResolvedValue(null);
|
||||
|
||||
await expect(service.findPersonalProject(mockUser, mockTrx)).rejects.toThrow(
|
||||
new ForbiddenError('Missing personal project'),
|
||||
);
|
||||
const promise = service.findPersonalProject(mockUser, mockTrx);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow('Missing personal project');
|
||||
|
||||
expect(projectRepository.getPersonalProjectForUser).toHaveBeenCalledWith(
|
||||
mockUser.id,
|
||||
|
|
@ -138,10 +138,14 @@ describe('ChatHubCredentialsService', () => {
|
|||
openAiApi: { id: CREDENTIAL_ID, name: 'OpenAI Credentials' },
|
||||
};
|
||||
|
||||
await expect(
|
||||
service.findWorkflowCredentialAndProject('anthropic', mockCredentials, 'workflow-123'),
|
||||
).rejects.toThrow(
|
||||
new BadRequestError('No credentials provided for the selected model provider'),
|
||||
const promise = service.findWorkflowCredentialAndProject(
|
||||
'anthropic',
|
||||
mockCredentials,
|
||||
'workflow-123',
|
||||
);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'No credentials provided for the selected model provider',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -160,9 +164,13 @@ describe('ChatHubCredentialsService', () => {
|
|||
credentialsService.findAllCredentialIdsForWorkflow.mockResolvedValue([]);
|
||||
credentialsService.findAllGlobalCredentialIds.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
service.findWorkflowCredentialAndProject('openai', mockCredentials, 'workflow-123'),
|
||||
).rejects.toThrow(new ForbiddenError("You don't have access to the provided credentials"));
|
||||
const promise = service.findWorkflowCredentialAndProject(
|
||||
'openai',
|
||||
mockCredentials,
|
||||
'workflow-123',
|
||||
);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow("You don't have access to the provided credentials");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -492,14 +492,12 @@ describe('CommunityPackagesService', () => {
|
|||
license.isCustomNpmRegistryEnabled.mockReturnValue(false);
|
||||
|
||||
// ACT & ASSERT
|
||||
await expect(
|
||||
communityPackagesService.updatePackage(
|
||||
installedPackageForUpdateTest.packageName,
|
||||
installedPackageForUpdateTest,
|
||||
),
|
||||
).rejects.toThrow(
|
||||
new FeatureNotLicensedError(LICENSE_FEATURES.COMMUNITY_NODES_CUSTOM_REGISTRY),
|
||||
const promise = communityPackagesService.updatePackage(
|
||||
installedPackageForUpdateTest.packageName,
|
||||
installedPackageForUpdateTest,
|
||||
);
|
||||
await expect(promise).rejects.toThrow(FeatureNotLicensedError);
|
||||
await expect(promise).rejects.toThrow(LICENSE_FEATURES.COMMUNITY_NODES_CUSTOM_REGISTRY);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -137,9 +137,9 @@ describe('executeNpmCommand', () => {
|
|||
new Error('npm ERR! 404 Not Found - GET https://registry.npmjs.org/nonexistent-package'),
|
||||
);
|
||||
|
||||
await expect(executeNpmCommand(['install', 'nonexistent-package'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'nonexistent-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for package not found (E404)', async () => {
|
||||
|
|
@ -149,25 +149,25 @@ describe('executeNpmCommand', () => {
|
|||
),
|
||||
);
|
||||
|
||||
await expect(executeNpmCommand(['view', 'nonexistent-package'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND),
|
||||
);
|
||||
const promise = executeNpmCommand(['view', 'nonexistent-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for package not found (404 Not Found)', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('404 Not Found - package does not exist'));
|
||||
|
||||
await expect(executeNpmCommand(['install', 'nonexistent-package'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'nonexistent-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for no version available', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('No valid versions available for package'));
|
||||
|
||||
await expect(executeNpmCommand(['install', 'some-package'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'some-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for package version not found', async () => {
|
||||
|
|
@ -175,9 +175,9 @@ describe('executeNpmCommand', () => {
|
|||
new Error(`${NPM_COMMAND_TOKENS.NPM_PACKAGE_VERSION_NOT_FOUND_ERROR} package@1.2.3`),
|
||||
);
|
||||
|
||||
await expect(executeNpmCommand(['install', 'package@1.2.3'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_VERSION_NOT_FOUND),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'package@1.2.3']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_VERSION_NOT_FOUND);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for disk full (ENOSPC)', async () => {
|
||||
|
|
@ -185,36 +185,36 @@ describe('executeNpmCommand', () => {
|
|||
new Error(`${NPM_COMMAND_TOKENS.NPM_DISK_NO_SPACE}: no space left on device`),
|
||||
);
|
||||
|
||||
await expect(executeNpmCommand(['install', 'some-package'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.DISK_IS_FULL),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'some-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.DISK_IS_FULL);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for insufficient disk space', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('Error: insufficient space on device'));
|
||||
|
||||
await expect(executeNpmCommand(['install', 'large-package'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.DISK_IS_FULL),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'large-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.DISK_IS_FULL);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for DNS getaddrinfo errors', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('getaddrinfo ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(executeNpmCommand(['install', 'some-package'])).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Network error: Unable to reach npm registry. Please check your internet connection.',
|
||||
),
|
||||
const promise = executeNpmCommand(['install', 'some-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Network error: Unable to reach npm registry. Please check your internet connection.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for DNS ENOTFOUND errors', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(executeNpmCommand(['install', 'some-package'])).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Network error: Unable to reach npm registry. Please check your internet connection.',
|
||||
),
|
||||
const promise = executeNpmCommand(['install', 'some-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Network error: Unable to reach npm registry. Please check your internet connection.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -266,17 +266,17 @@ describe('executeNpmCommand', () => {
|
|||
it('should handle errors normally when doNotHandleError is false', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('npm ERR! 404 Not Found'));
|
||||
|
||||
await expect(
|
||||
executeNpmCommand(['install', 'nonexistent'], { doNotHandleError: false }),
|
||||
).rejects.toThrow(new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND));
|
||||
const promise = executeNpmCommand(['install', 'nonexistent'], { doNotHandleError: false });
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND);
|
||||
});
|
||||
|
||||
it('should handle errors normally when doNotHandleError is undefined (default)', async () => {
|
||||
mockAsyncExec.mockRejectedValue(new Error('npm ERR! 404 Not Found'));
|
||||
|
||||
await expect(executeNpmCommand(['install', 'nonexistent'])).rejects.toThrow(
|
||||
new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'nonexistent']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -417,9 +417,9 @@ describe('executeNpmCommand', () => {
|
|||
it('should handle non-Error objects being thrown', async () => {
|
||||
mockAsyncExec.mockRejectedValue('string error');
|
||||
|
||||
await expect(executeNpmCommand(['install', 'some-package'])).rejects.toThrow(
|
||||
new UnexpectedError('Failed to execute npm command'),
|
||||
);
|
||||
const promise = executeNpmCommand(['install', 'some-package']);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Failed to execute npm command');
|
||||
});
|
||||
|
||||
it('should handle errors with no message', async () => {
|
||||
|
|
@ -645,10 +645,10 @@ describe('verifyIntegrity', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('CLI command failed'));
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Try restarting n8n and attempting the installation again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Try restarting n8n and attempting the installation again.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -659,10 +659,10 @@ describe('verifyIntegrity', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('getaddrinfo ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -673,10 +673,10 @@ describe('verifyIntegrity', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -721,10 +721,10 @@ describe('verifyIntegrity', () => {
|
|||
stderr: '',
|
||||
});
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Try restarting n8n and attempting the installation again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Try restarting n8n and attempting the installation again.',
|
||||
);
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -766,10 +766,10 @@ describe('verifyIntegrity', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('getaddrinfo ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
);
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -784,10 +784,10 @@ describe('verifyIntegrity', () => {
|
|||
new Error('npm ERR! 404 Not Found - GET https://registry.npmjs.org/nonexistent-package'),
|
||||
);
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Please check your network connection and try again.',
|
||||
);
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -800,10 +800,10 @@ describe('verifyIntegrity', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('Some other error'));
|
||||
|
||||
await expect(verifyIntegrity(packageName, version, registryUrl, integrity)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'Checksum verification failed. Try restarting n8n and attempting the installation again.',
|
||||
),
|
||||
const promise = verifyIntegrity(packageName, version, registryUrl, integrity);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'Checksum verification failed. Try restarting n8n and attempting the installation again.',
|
||||
);
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -845,9 +845,9 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('E404 Not Found'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError('Package version does not exist'),
|
||||
);
|
||||
const promise1 = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise1).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise1).rejects.toThrow('Package version does not exist');
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError with proper message on 404 when CLI fallback fails', async () => {
|
||||
|
|
@ -857,9 +857,9 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('Some error'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError('Failed to check package version existence'),
|
||||
);
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Failed to check package version existence');
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for network failures when CLI fallback fails', async () => {
|
||||
|
|
@ -869,9 +869,9 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('CLI network failure'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError('Failed to check package version existence'),
|
||||
);
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Failed to check package version existence');
|
||||
});
|
||||
|
||||
it('should throw UnexpectedError for server errors (500) when CLI fallback fails', async () => {
|
||||
|
|
@ -893,10 +893,10 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('getaddrinfo ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
),
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -907,10 +907,10 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
),
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -959,9 +959,9 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockResolvedValue({ stdout: 'null', stderr: '' });
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError('Failed to check package version existence'),
|
||||
);
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Failed to check package version existence');
|
||||
});
|
||||
|
||||
it('should reject CLI output that is not valid semver', async () => {
|
||||
|
|
@ -991,9 +991,9 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
new Error('E404 Not Found - GET https://registry.npmjs.org/nonexistent-package'),
|
||||
);
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError('Package version does not exist'),
|
||||
);
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Package version does not exist');
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
|
@ -1005,10 +1005,10 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('getaddrinfo ENOTFOUND registry.npmjs.org'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
),
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
);
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -1021,10 +1021,10 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('npm ERR! 500 Internal Server Error'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
),
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow(
|
||||
'The community nodes service is temporarily unreachable. Please try again later.',
|
||||
);
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
|
|
@ -1037,9 +1037,9 @@ describe('checkIfVersionExistsOrThrow', () => {
|
|||
|
||||
mockAsyncExec.mockRejectedValue(new Error('Some other error'));
|
||||
|
||||
await expect(checkIfVersionExistsOrThrow(packageName, version, registryUrl)).rejects.toThrow(
|
||||
new UnexpectedError('Failed to check package version existence'),
|
||||
);
|
||||
const promise = checkIfVersionExistsOrThrow(packageName, version, registryUrl);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Failed to check package version existence');
|
||||
|
||||
expect(mockAsyncExec).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -577,10 +577,9 @@ describe('dataTable filters', () => {
|
|||
});
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError(
|
||||
`${condition.toUpperCase()} filter value cannot be null or undefined`,
|
||||
),
|
||||
`${condition.toUpperCase()} filter value cannot be null or undefined`,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -610,10 +609,9 @@ describe('dataTable filters', () => {
|
|||
});
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError(
|
||||
`${condition.toUpperCase()} filter value must be a string`,
|
||||
),
|
||||
`${condition.toUpperCase()} filter value must be a string`,
|
||||
);
|
||||
});
|
||||
},
|
||||
|
|
@ -1364,10 +1362,9 @@ describe('dataTable filters', () => {
|
|||
});
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError(
|
||||
`${condition.toUpperCase()} filter value cannot be null or undefined`,
|
||||
),
|
||||
`${condition.toUpperCase()} filter value cannot be null or undefined`,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1292,9 +1292,8 @@ describe('dataTable', () => {
|
|||
);
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError("unknown column name 'cWrong'"),
|
||||
);
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow("unknown column name 'cWrong'");
|
||||
});
|
||||
|
||||
it('inserts rows with partial data (some columns missing)', async () => {
|
||||
|
|
@ -1380,9 +1379,8 @@ describe('dataTable', () => {
|
|||
);
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError("unknown column name 'cWrong'"),
|
||||
);
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow("unknown column name 'cWrong'");
|
||||
});
|
||||
|
||||
it('rejects an invalid date string to date column', async () => {
|
||||
|
|
@ -2372,10 +2370,9 @@ describe('dataTable', () => {
|
|||
filter: undefined as any,
|
||||
});
|
||||
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError(
|
||||
'Filter is required for delete operations to prevent accidental deletion of all data',
|
||||
),
|
||||
'Filter is required for delete operations to prevent accidental deletion of all data',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -2398,10 +2395,9 @@ describe('dataTable', () => {
|
|||
filter: { type: 'and', filters: [] },
|
||||
});
|
||||
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError(
|
||||
'Filter is required for delete operations to prevent accidental deletion of all data',
|
||||
),
|
||||
'Filter is required for delete operations to prevent accidental deletion of all data',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -2950,9 +2946,8 @@ describe('dataTable', () => {
|
|||
});
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError('Filter must not be empty'),
|
||||
);
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow('Filter must not be empty');
|
||||
|
||||
const { data } = await dataTableService.getManyRowsAndCount(dataTableId, project1.id, {});
|
||||
expect(data).toEqual([
|
||||
|
|
@ -2982,9 +2977,8 @@ describe('dataTable', () => {
|
|||
});
|
||||
|
||||
// ASSERT
|
||||
await expect(result).rejects.toThrow(
|
||||
new DataTableValidationError('Data columns must not be empty'),
|
||||
);
|
||||
await expect(result).rejects.toThrow(DataTableValidationError);
|
||||
await expect(result).rejects.toThrow('Data columns must not be empty');
|
||||
|
||||
const { data } = await dataTableService.getManyRowsAndCount(dataTableId, project1.id, {});
|
||||
expect(data).toEqual([
|
||||
|
|
|
|||
|
|
@ -356,9 +356,9 @@ describe('OidcService', () => {
|
|||
const storedState = oidcService.generateState().signed;
|
||||
const storedNonce = oidcService.generateNonce().signed;
|
||||
|
||||
await expect(oidcService.loginUser(callbackUrl, storedState, storedNonce)).rejects.toThrow(
|
||||
new BadRequestError('Invalid authorization code'),
|
||||
);
|
||||
const promise = oidcService.loginUser(callbackUrl, storedState, storedNonce);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid authorization code');
|
||||
});
|
||||
|
||||
it('throws an error if claims() throws an error', async () => {
|
||||
|
|
@ -377,9 +377,9 @@ describe('OidcService', () => {
|
|||
const storedState = oidcService.generateState().signed;
|
||||
const storedNonce = oidcService.generateNonce().signed;
|
||||
|
||||
await expect(oidcService.loginUser(callbackUrl, storedState, storedNonce)).rejects.toThrow(
|
||||
new BadRequestError('Invalid token'),
|
||||
);
|
||||
const promise = oidcService.loginUser(callbackUrl, storedState, storedNonce);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid token');
|
||||
});
|
||||
|
||||
it('should throw an error if there are no claims', async () => {
|
||||
|
|
@ -398,9 +398,9 @@ describe('OidcService', () => {
|
|||
const storedState = oidcService.generateState().signed;
|
||||
const storedNonce = oidcService.generateNonce().signed;
|
||||
|
||||
await expect(oidcService.loginUser(callbackUrl, storedState, storedNonce)).rejects.toThrow(
|
||||
new ForbiddenError('No claims found in the OIDC token'),
|
||||
);
|
||||
const promise = oidcService.loginUser(callbackUrl, storedState, storedNonce);
|
||||
await expect(promise).rejects.toThrow(ForbiddenError);
|
||||
await expect(promise).rejects.toThrow('No claims found in the OIDC token');
|
||||
});
|
||||
|
||||
it('throws an error if fetchUserInfo throws an error', async () => {
|
||||
|
|
@ -420,9 +420,9 @@ describe('OidcService', () => {
|
|||
const storedState = oidcService.generateState().signed;
|
||||
const storedNonce = oidcService.generateNonce().signed;
|
||||
|
||||
await expect(oidcService.loginUser(callbackUrl, storedState, storedNonce)).rejects.toThrow(
|
||||
new BadRequestError('Invalid token'),
|
||||
);
|
||||
const promise = oidcService.loginUser(callbackUrl, storedState, storedNonce);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid token');
|
||||
});
|
||||
|
||||
it('throws an error if there is no email', async () => {
|
||||
|
|
@ -442,9 +442,9 @@ describe('OidcService', () => {
|
|||
const storedState = oidcService.generateState().signed;
|
||||
const storedNonce = oidcService.generateNonce().signed;
|
||||
|
||||
await expect(oidcService.loginUser(callbackUrl, storedState, storedNonce)).rejects.toThrow(
|
||||
new BadRequestError('An email is required'),
|
||||
);
|
||||
const promise = oidcService.loginUser(callbackUrl, storedState, storedNonce);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('An email is required');
|
||||
});
|
||||
|
||||
it('throws an error if the email is invalid', async () => {
|
||||
|
|
@ -466,9 +466,9 @@ describe('OidcService', () => {
|
|||
const storedState = oidcService.generateState().signed;
|
||||
const storedNonce = oidcService.generateNonce().signed;
|
||||
|
||||
await expect(oidcService.loginUser(callbackUrl, storedState, storedNonce)).rejects.toThrow(
|
||||
new BadRequestError('Invalid email format'),
|
||||
);
|
||||
const promise = oidcService.loginUser(callbackUrl, storedState, storedNonce);
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid email format');
|
||||
});
|
||||
|
||||
it('should return the user if the auth identity already exists', async () => {
|
||||
|
|
|
|||
|
|
@ -178,9 +178,8 @@ describe('Push', () => {
|
|||
req.headers['x-forwarded-host'] = xForwardedHost;
|
||||
|
||||
if (backendName === 'sse') {
|
||||
expect(() => push.handleRequest(req, res)).toThrow(
|
||||
new BadRequestError('Invalid origin!'),
|
||||
);
|
||||
expect(() => push.handleRequest(req, res)).toThrow(BadRequestError);
|
||||
expect(() => push.handleRequest(req, res)).toThrow('Invalid origin!');
|
||||
} else {
|
||||
push.handleRequest(req, res);
|
||||
expect(ws.send).toHaveBeenCalledWith('Invalid origin!');
|
||||
|
|
@ -274,9 +273,8 @@ describe('Push', () => {
|
|||
} else {
|
||||
// Expected behavior: connection should be rejected
|
||||
if (backendName === 'sse') {
|
||||
expect(() => push.handleRequest(req, res)).toThrow(
|
||||
new BadRequestError('Invalid origin!'),
|
||||
);
|
||||
expect(() => push.handleRequest(req, res)).toThrow(BadRequestError);
|
||||
expect(() => push.handleRequest(req, res)).toThrow('Invalid origin!');
|
||||
} else {
|
||||
push.handleRequest(req, res);
|
||||
expect(ws.send).toHaveBeenCalledWith('Invalid origin!');
|
||||
|
|
@ -291,8 +289,9 @@ describe('Push', () => {
|
|||
req.query = { pushRef: '' };
|
||||
|
||||
if (backendName === 'sse') {
|
||||
expect(() => push.handleRequest(req, res)).toThrow(BadRequestError);
|
||||
expect(() => push.handleRequest(req, res)).toThrow(
|
||||
new BadRequestError('The query parameter "pushRef" is missing!'),
|
||||
'The query parameter "pushRef" is missing!',
|
||||
);
|
||||
} else {
|
||||
push.handleRequest(req, mock());
|
||||
|
|
|
|||
|
|
@ -776,9 +776,9 @@ describe('SAML email validation', () => {
|
|||
|
||||
const mockRequest = {} as express.Request;
|
||||
|
||||
await expect(samlService.handleSamlLogin(mockRequest, 'post')).rejects.toThrow(
|
||||
new BadRequestError('Invalid email format'),
|
||||
);
|
||||
const promise = samlService.handleSamlLogin(mockRequest, 'post');
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid email format');
|
||||
});
|
||||
|
||||
test.each([['not-an-email'], ['@missinglocal.com'], ['missing@.com'], ['spaces in@email.com']])(
|
||||
|
|
@ -797,9 +797,9 @@ describe('SAML email validation', () => {
|
|||
|
||||
const mockRequest = {} as express.Request;
|
||||
|
||||
await expect(samlService.handleSamlLogin(mockRequest, 'post')).rejects.toThrow(
|
||||
new BadRequestError('Invalid email format'),
|
||||
);
|
||||
const promise = samlService.handleSamlLogin(mockRequest, 'post');
|
||||
await expect(promise).rejects.toThrow(BadRequestError);
|
||||
await expect(promise).rejects.toThrow('Invalid email format');
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ describe('Migration Test Helpers', () => {
|
|||
|
||||
describe('initDbUpToMigration', () => {
|
||||
it('should throw error if migration not found', async () => {
|
||||
await expect(initDbUpToMigration('NonExistentMigration')).rejects.toThrow(
|
||||
new UnexpectedError('Migration "NonExistentMigration" not found'),
|
||||
);
|
||||
const promise = initDbUpToMigration('NonExistentMigration');
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Migration "NonExistentMigration" not found');
|
||||
});
|
||||
|
||||
it('should stop before specified migration', async () => {
|
||||
|
|
@ -72,9 +72,9 @@ describe('Migration Test Helpers', () => {
|
|||
|
||||
describe('runSingleMigration', () => {
|
||||
it('should throw error if migration not found', async () => {
|
||||
await expect(runSingleMigration('NonExistentMigration')).rejects.toThrow(
|
||||
new UnexpectedError('Migration "NonExistentMigration" not found'),
|
||||
);
|
||||
const promise = runSingleMigration('NonExistentMigration');
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Migration "NonExistentMigration" not found');
|
||||
});
|
||||
|
||||
it('should run specific migration', async () => {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ describe('BinaryData/utils', () => {
|
|||
it('should throw on invalid compressed Readable streams', async () => {
|
||||
const gunzip = createGunzip();
|
||||
const body = Readable.from(Buffer.from('0001f8b080000000000000000', 'hex')).pipe(gunzip);
|
||||
await expect(binaryToBuffer(body)).rejects.toThrow(
|
||||
new UnexpectedError('Failed to decompress response'),
|
||||
);
|
||||
const promise = binaryToBuffer(body);
|
||||
await expect(promise).rejects.toThrow(UnexpectedError);
|
||||
await expect(promise).rejects.toThrow('Failed to decompress response');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ describe('normalizeItems', () => {
|
|||
},
|
||||
];
|
||||
test.each(errorTests)('$description', ({ input }) => {
|
||||
expect(() => normalizeItems(input)).toThrow(new ApplicationError('Inconsistent item format'));
|
||||
expect(() => normalizeItems(input)).toThrow(ApplicationError);
|
||||
expect(() => normalizeItems(input)).toThrow('Inconsistent item format');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -458,7 +458,10 @@ describe('validateValueAgainstSchema', () => {
|
|||
|
||||
expect(() =>
|
||||
validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0),
|
||||
).toThrow(new ExpressionError("Invalid input for 'count' [item 0]"));
|
||||
).toThrow(ExpressionError);
|
||||
expect(() =>
|
||||
validateValueAgainstSchema(node, nodeType, value, parameterName, 0, 0),
|
||||
).toThrow("Invalid input for 'count' [item 0]");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ describe('AMQP Node', () => {
|
|||
it('should throw error when sink is empty', async () => {
|
||||
executeFunctions.getNodeParameter.calledWith('sink', 0).mockReturnValue('');
|
||||
|
||||
await expect(new Amqp().execute.call(executeFunctions)).rejects.toThrow(
|
||||
new NodeOperationError(executeFunctions.getNode(), 'Queue or Topic required!'),
|
||||
);
|
||||
const promise = new Amqp().execute.call(executeFunctions);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Queue or Topic required!');
|
||||
});
|
||||
|
||||
it('should send message successfully', async () => {
|
||||
|
|
|
|||
|
|
@ -34,12 +34,9 @@ describe('handleError', () => {
|
|||
Error: { Code: 'EntityAlreadyExists', Message: 'User "existingUserName" already exists' },
|
||||
} as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: 'User "existingUserName" already exists',
|
||||
description: ERROR_DESCRIPTIONS.EntityAlreadyExists.User,
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('User "existingUserName" already exists');
|
||||
});
|
||||
|
||||
test('should throw NodeApiError for NoSuchEntity with user not found', async () => {
|
||||
|
|
@ -66,12 +63,9 @@ describe('handleError', () => {
|
|||
response.statusCode = 400;
|
||||
response.body = { Error: { Code: 'BadRequest', Message: 'Invalid request' } } as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: 'BadRequest',
|
||||
description: 'Invalid request',
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('BadRequest');
|
||||
});
|
||||
|
||||
test('should throw NodeApiError for EntityAlreadyExists with group conflict', async () => {
|
||||
|
|
@ -84,12 +78,9 @@ describe('handleError', () => {
|
|||
Error: { Code: 'EntityAlreadyExists', Message: 'Group "existingGroupName" already exists' },
|
||||
} as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: 'Group "existingGroupName" already exists',
|
||||
description: ERROR_DESCRIPTIONS.EntityAlreadyExists.Group,
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('Group "existingGroupName" already exists');
|
||||
});
|
||||
|
||||
test('should throw NodeApiError for NoSuchEntity with group not found', async () => {
|
||||
|
|
@ -102,12 +93,9 @@ describe('handleError', () => {
|
|||
Error: { Code: 'NoSuchEntity', Message: 'Group "nonExistentGroup" does not exist' },
|
||||
} as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: 'Group "nonExistentGroup" does not exist',
|
||||
description: ERROR_DESCRIPTIONS.NoSuchEntity.Group,
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('Group "nonExistentGroup" does not exist');
|
||||
});
|
||||
|
||||
test('should throw NodeApiError for DeleteConflict', async () => {
|
||||
|
|
@ -120,11 +108,8 @@ describe('handleError', () => {
|
|||
Error: { Code: 'DeleteConflict', Message: 'User "userIngroup" is in a group' },
|
||||
} as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: 'User "userIngroup" is in a group',
|
||||
description: 'This entity is still in use. Remove users from the group before deleting.',
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('User "userIngroup" is in a group');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -252,12 +252,9 @@ describe('metricHandlers', () => {
|
|||
return undefined;
|
||||
});
|
||||
|
||||
await expect(metricHandlers.toolsUsed.call(mockExecuteFunctions, 0)).rejects.toThrow(
|
||||
new NodeOperationError(mockNode, 'Intermediate steps missing', {
|
||||
description:
|
||||
"Make sure to enable returning intermediate steps in your agent node's options, then map them in here",
|
||||
}),
|
||||
);
|
||||
const promise = metricHandlers.toolsUsed.call(mockExecuteFunctions, 0);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('Intermediate steps missing');
|
||||
});
|
||||
|
||||
it('should throw error for empty object intermediate steps', async () => {
|
||||
|
|
|
|||
|
|
@ -231,11 +231,9 @@ describe('Google Sheets Search Functions', () => {
|
|||
|
||||
(apiRequest.call as jest.Mock).mockResolvedValue(undefined);
|
||||
|
||||
await expect(
|
||||
sheetsSearch.call(mockLoadOptionsFunctions as ILoadOptionsFunctions),
|
||||
).rejects.toThrow(
|
||||
new NodeOperationError(mockLoadOptionsFunctions.getNode(), 'No data got returned'),
|
||||
);
|
||||
const promise = sheetsSearch.call(mockLoadOptionsFunctions as ILoadOptionsFunctions);
|
||||
await expect(promise).rejects.toThrow(NodeOperationError);
|
||||
await expect(promise).rejects.toThrow('No data got returned');
|
||||
});
|
||||
|
||||
it('should filter out non-GRID type sheets', async () => {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@ describe('handleError', () => {
|
|||
response.statusCode = 409;
|
||||
response.body = { code: 'Conflict', message: 'Container already exists' } as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: ErrorMap.Container.Conflict.getMessage('container'),
|
||||
description: ErrorMap.Container.Conflict.description,
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow(ErrorMap.Container.Conflict.getMessage('container'));
|
||||
});
|
||||
|
||||
test('should throw NodeApiError for container not found', async () => {
|
||||
|
|
@ -42,12 +39,9 @@ describe('handleError', () => {
|
|||
response.statusCode = 404;
|
||||
response.body = { code: 'NotFound', message: 'Container not found' } as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: ErrorMap.Container.NotFound.getMessage('container'),
|
||||
description: ErrorMap.Container.NotFound.description,
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow(ErrorMap.Container.NotFound.getMessage('container'));
|
||||
});
|
||||
|
||||
test('should throw NodeApiError for item not found', async () => {
|
||||
|
|
@ -56,12 +50,9 @@ describe('handleError', () => {
|
|||
response.statusCode = 404;
|
||||
response.body = { code: 'NotFound', message: 'Item not found' } as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: ErrorMap.Item.NotFound.getMessage('item'),
|
||||
description: ErrorMap.Item.NotFound.description,
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow(ErrorMap.Item.NotFound.getMessage('item'));
|
||||
});
|
||||
|
||||
test('should throw generic error if no specific mapping exists', async () => {
|
||||
|
|
@ -70,12 +61,9 @@ describe('handleError', () => {
|
|||
response.statusCode = 400;
|
||||
response.body = { code: 'BadRequest', message: 'Invalid request' } as JsonObject;
|
||||
|
||||
await expect(handleError.call(mockExecuteSingleFunctions, data, response)).rejects.toThrow(
|
||||
new NodeApiError(mockExecuteSingleFunctions.getNode(), response.body as JsonObject, {
|
||||
message: 'BadRequest',
|
||||
description: 'Invalid request',
|
||||
}),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, response);
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('BadRequest');
|
||||
});
|
||||
|
||||
test('should handle error details correctly when match is successful', async () => {
|
||||
|
|
@ -119,25 +107,13 @@ describe('handleError', () => {
|
|||
}
|
||||
|
||||
if (errorDetails && errorDetails.length > 0) {
|
||||
await expect(
|
||||
handleError.call(mockExecuteSingleFunctions, data, {
|
||||
statusCode: 500,
|
||||
body: { code: 'InternalServerError', message: errorMessage },
|
||||
headers: {},
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
new NodeApiError(
|
||||
mockExecuteSingleFunctions.getNode(),
|
||||
{
|
||||
code: 'InternalServerError',
|
||||
message: errorMessage,
|
||||
} as JsonObject,
|
||||
{
|
||||
message: 'InternalServerError',
|
||||
description: errorDetails.join('\n'),
|
||||
},
|
||||
),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, {
|
||||
statusCode: 500,
|
||||
body: { code: 'InternalServerError', message: errorMessage },
|
||||
headers: {},
|
||||
});
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('InternalServerError');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -153,25 +129,13 @@ describe('handleError', () => {
|
|||
}
|
||||
|
||||
if (errorDetails && errorDetails.length > 0) {
|
||||
await expect(
|
||||
handleError.call(mockExecuteSingleFunctions, data, {
|
||||
statusCode: 500,
|
||||
body: { code: 'InternalServerError', message: errorMessage },
|
||||
headers: {},
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
new NodeApiError(
|
||||
mockExecuteSingleFunctions.getNode(),
|
||||
{
|
||||
code: 'InternalServerError',
|
||||
message: errorMessage,
|
||||
} as JsonObject,
|
||||
{
|
||||
message: 'InternalServerError',
|
||||
description: 'Internal Server Error',
|
||||
},
|
||||
),
|
||||
);
|
||||
const promise = handleError.call(mockExecuteSingleFunctions, data, {
|
||||
statusCode: 500,
|
||||
body: { code: 'InternalServerError', message: errorMessage },
|
||||
headers: {},
|
||||
});
|
||||
await expect(promise).rejects.toThrow(NodeApiError);
|
||||
await expect(promise).rejects.toThrow('InternalServerError');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -289,8 +289,9 @@ describe('Data Transformation Functions', () => {
|
|||
);
|
||||
|
||||
vi.useFakeTimers({ now: new Date() });
|
||||
expect(() => evaluate('={{ "hi".toDateTime() }}')).toThrow(ExpressionExtensionError);
|
||||
expect(() => evaluate('={{ "hi".toDateTime() }}')).toThrow(
|
||||
new ExpressionExtensionError('cannot convert to Luxon DateTime'),
|
||||
'cannot convert to Luxon DateTime',
|
||||
);
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user