mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +00:00
fix(editor): Show error toast for failed executions (#15388)
This commit is contained in:
committed by
GitHub
parent
954b66218f
commit
e68149bbc7
@@ -1,9 +1,16 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { displayForm, executionFilterToQueryFilter, waitingNodeTooltip } from './executionUtils';
|
||||
import type { INode, IRunData, IPinData } from 'n8n-workflow';
|
||||
import {
|
||||
displayForm,
|
||||
executionFilterToQueryFilter,
|
||||
waitingNodeTooltip,
|
||||
getExecutionErrorMessage,
|
||||
getExecutionErrorToastConfiguration,
|
||||
} from './executionUtils';
|
||||
import type { INode, IRunData, IPinData, ExecutionError } from 'n8n-workflow';
|
||||
import { type INodeUi } from '../Interface';
|
||||
import { CHAT_TRIGGER_NODE_TYPE, FORM_TRIGGER_NODE_TYPE, GITHUB_NODE_TYPE } from '@/constants';
|
||||
import { createTestNode } from '@/__tests__/mocks';
|
||||
import type { VNode } from 'vue';
|
||||
|
||||
const WAIT_NODE_TYPE = 'waitNode';
|
||||
|
||||
@@ -24,13 +31,15 @@ vi.mock('@/stores/workflows.store', () => ({
|
||||
|
||||
vi.mock('@/plugins/i18n', () => ({
|
||||
i18n: {
|
||||
baseText: (key: string) => {
|
||||
baseText: (key: string, options?: { interpolate?: { error?: string; details?: string } }) => {
|
||||
const texts: { [key: string]: string } = {
|
||||
'ndv.output.waitNodeWaiting': 'Waiting for execution to resume...',
|
||||
'ndv.output.waitNodeWaitingForFormSubmission': 'Waiting for form submission: ',
|
||||
'ndv.output.waitNodeWaitingForWebhook': 'Waiting for webhook call: ',
|
||||
'ndv.output.githubNodeWaitingForWebhook': 'Waiting for webhook call: ',
|
||||
'ndv.output.sendAndWaitWaitingApproval': 'Waiting for approval...',
|
||||
'pushConnection.executionError': `Execution error${options?.interpolate?.error}`,
|
||||
'pushConnection.executionError.details': `Details: ${options?.interpolate?.details}`,
|
||||
};
|
||||
return texts[key] || key;
|
||||
},
|
||||
@@ -323,3 +332,123 @@ describe('waitingNodeTooltip', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const executionErrorFactory = (error: Record<string, unknown>) =>
|
||||
error as unknown as ExecutionError;
|
||||
|
||||
describe('getExecutionErrorMessage', () => {
|
||||
it('returns error.message when lastNodeExecuted and error are present', () => {
|
||||
const result = getExecutionErrorMessage({
|
||||
error: executionErrorFactory({ message: 'Node failed' }),
|
||||
lastNodeExecuted: 'Node1',
|
||||
});
|
||||
expect(result).toBe('Node failed');
|
||||
});
|
||||
|
||||
it('uses fallback translation when only error.message is provided', () => {
|
||||
const result = getExecutionErrorMessage({
|
||||
error: executionErrorFactory({ message: 'Something went wrong' }),
|
||||
});
|
||||
expect(result).toBe('Execution error.Details: Something went wrong');
|
||||
});
|
||||
|
||||
it('includes node name if error.node is a string', () => {
|
||||
const result = getExecutionErrorMessage({
|
||||
error: executionErrorFactory({ message: 'Failed', node: 'MyNode' }),
|
||||
});
|
||||
expect(result).toBe('Execution error.Details: MyNode: Failed');
|
||||
});
|
||||
|
||||
it('includes node.name if error.node is an object', () => {
|
||||
const result = getExecutionErrorMessage({
|
||||
error: executionErrorFactory({ message: 'Crashed', node: { name: 'Step1' } }),
|
||||
});
|
||||
expect(result).toBe('Execution error.Details: Step1: Crashed');
|
||||
});
|
||||
|
||||
it('uses default fallback when no error or lastNodeExecuted', () => {
|
||||
const result = getExecutionErrorMessage({});
|
||||
expect(result).toBe('Execution error!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getExecutionErrorToastConfiguration', () => {
|
||||
it('returns config for SubworkflowOperationError', () => {
|
||||
const result = getExecutionErrorToastConfiguration({
|
||||
error: executionErrorFactory({
|
||||
name: 'SubworkflowOperationError',
|
||||
message: 'Subworkflow failed',
|
||||
description: 'Workflow XYZ failed',
|
||||
}),
|
||||
lastNodeExecuted: 'NodeA',
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
title: 'Subworkflow failed',
|
||||
message: 'Workflow XYZ failed',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config for configuration-node error with node name', () => {
|
||||
const result = getExecutionErrorToastConfiguration({
|
||||
error: executionErrorFactory({
|
||||
name: 'NodeOperationError',
|
||||
message: 'Node failed',
|
||||
description: 'Bad configuration',
|
||||
functionality: 'configuration-node',
|
||||
node: { name: 'TestNode' },
|
||||
}),
|
||||
});
|
||||
expect(result.title).toBe('Error in sub-node ‘TestNode‘');
|
||||
expect((result.message as VNode).props).toEqual({
|
||||
errorMessage: 'Bad configuration',
|
||||
nodeName: 'TestNode',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns config for configuration-node error without node name', () => {
|
||||
const result = getExecutionErrorToastConfiguration({
|
||||
error: executionErrorFactory({
|
||||
name: 'NodeApiError',
|
||||
message: 'API failed',
|
||||
description: 'Missing credentials',
|
||||
functionality: 'configuration-node',
|
||||
node: {},
|
||||
}),
|
||||
});
|
||||
|
||||
expect(result.title).toBe('Problem executing workflow');
|
||||
expect((result.message as VNode).props).toEqual({
|
||||
errorMessage: 'Missing credentials',
|
||||
nodeName: '',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns generic config when error type is not special', () => {
|
||||
const result = getExecutionErrorToastConfiguration({
|
||||
error: executionErrorFactory({
|
||||
name: 'UnknownError',
|
||||
message: 'Something broke',
|
||||
}),
|
||||
lastNodeExecuted: 'NodeX',
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
title: 'Problem in node ‘NodeX‘',
|
||||
message: 'Something broke',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns generic config without lastNodeExecuted', () => {
|
||||
const result = getExecutionErrorToastConfiguration({
|
||||
error: executionErrorFactory({
|
||||
name: 'UnknownError',
|
||||
message: 'Something broke',
|
||||
}),
|
||||
});
|
||||
expect(result).toEqual({
|
||||
title: 'Problem executing workflow',
|
||||
message: 'Execution error.Details: Something broke',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user