From 8a0ad0f910feeada6d0c63e81c3e97a1a6e44de7 Mon Sep 17 00:00:00 2001 From: Ivan Atanasov Date: Thu, 14 Nov 2024 12:19:12 +0100 Subject: [PATCH] fix(editor): Improve formatting of expired trial error message (#11708) --- .vscode/launch.json | 4 +- .../src/composables/usePushConnection.test.ts | 111 ++++++++++++++++++ .../src/composables/usePushConnection.ts | 1 + .../src/composables/useToast.test.ts | 55 +++++++++ 4 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 packages/editor-ui/src/composables/useToast.test.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 448d745236..5501fe4439 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -47,9 +47,7 @@ "request": "launch", "skipFiles": ["/**"], "type": "node", - "env": { - // "N8N_PORT": "5679", - }, + "envFile": "${workspaceFolder}/.env", "outputCapture": "std", "killBehavior": "polite" }, diff --git a/packages/editor-ui/src/composables/usePushConnection.test.ts b/packages/editor-ui/src/composables/usePushConnection.test.ts index c21fc76702..819b9e842e 100644 --- a/packages/editor-ui/src/composables/usePushConnection.test.ts +++ b/packages/editor-ui/src/composables/usePushConnection.test.ts @@ -5,6 +5,10 @@ import type { PushMessage, PushPayload } from '@n8n/api-types'; import { usePushConnection } from '@/composables/usePushConnection'; import { usePushConnectionStore } from '@/stores/pushConnection.store'; import { useOrchestrationStore } from '@/stores/orchestration.store'; +import { useUIStore } from '@/stores/ui.store'; +import { useWorkflowsStore } from '@/stores/workflows.store'; +import { useToast } from '@/composables/useToast'; +import type { WorkflowOperationError } from 'n8n-workflow'; vi.mock('vue-router', () => { return { @@ -16,6 +20,19 @@ vi.mock('vue-router', () => { }; }); +vi.mock('@/composables/useToast', () => { + const showMessage = vi.fn(); + const showError = vi.fn(); + return { + useToast: () => { + return { + showMessage, + showError, + }; + }, + }; +}); + vi.useFakeTimers(); describe('usePushConnection()', () => { @@ -23,6 +40,9 @@ describe('usePushConnection()', () => { let pushStore: ReturnType; let orchestrationStore: ReturnType; let pushConnection: ReturnType; + let uiStore: ReturnType; + let workflowsStore: ReturnType; + let toast: ReturnType; beforeEach(() => { setActivePinia(createPinia()); @@ -30,7 +50,14 @@ describe('usePushConnection()', () => { router = vi.mocked(useRouter)(); pushStore = usePushConnectionStore(); orchestrationStore = useOrchestrationStore(); + uiStore = useUIStore(); + workflowsStore = useWorkflowsStore(); pushConnection = usePushConnection({ router }); + toast = useToast(); + }); + + afterEach(() => { + vi.restoreAllMocks(); }); describe('initialize()', () => { @@ -106,5 +133,89 @@ describe('usePushConnection()', () => { expect(result).toBeTruthy(); }); }); + + describe('executionFinished', () => { + it('should handle executionFinished event correctly', async () => { + const event: PushMessage = { + type: 'executionFinished', + data: { + executionId: '1', + data: { + data: { + resultData: { + runData: {}, + }, + }, + finished: true, + mode: 'manual', + startedAt: new Date(), + stoppedAt: new Date(), + status: 'success', + }, + }, + }; + + workflowsStore.activeExecutionId = '1'; + uiStore.isActionActive.workflowRunning = true; + + const result = await pushConnection.pushMessageReceived(event); + + expect(result).toBeTruthy(); + expect(workflowsStore.workflowExecutionData).toBeDefined(); + expect(uiStore.isActionActive['workflowRunning']).toBeTruthy(); + + expect(toast.showMessage).toHaveBeenCalledWith({ + title: 'Workflow executed successfully', + type: 'success', + }); + }); + + it('should handle isManualExecutionCancelled correctly', async () => { + const event: PushMessage = { + type: 'executionFinished', + data: { + executionId: '1', + data: { + data: { + startData: {}, + resultData: { + runData: { + 'Last Node': [], + }, + lastNodeExecuted: 'Last Node', + error: { + message: + 'Your trial has ended. Upgrade now to keep automating', + name: 'NodeApiError', + node: 'Last Node', + } as unknown as WorkflowOperationError, + }, + }, + startedAt: new Date(), + mode: 'manual', + status: 'running', + }, + }, + }; + + workflowsStore.activeExecutionId = '1'; + uiStore.isActionActive['workflowRunning'] = true; + + const result = await pushConnection.pushMessageReceived(event); + + expect(useToast().showMessage).toHaveBeenCalledWith({ + message: + 'Your trial has ended. Upgrade now to keep automating', + title: 'Problem in node ‘Last Node‘', + type: 'error', + duration: 0, + dangerouslyUseHTMLString: true, + }); + + expect(result).toBeTruthy(); + expect(workflowsStore.workflowExecutionData).toBeDefined(); + expect(uiStore.isActionActive.workflowRunning).toBeTruthy(); + }); + }); }); }); diff --git a/packages/editor-ui/src/composables/usePushConnection.ts b/packages/editor-ui/src/composables/usePushConnection.ts index ea9f79d27e..a5976d35d4 100644 --- a/packages/editor-ui/src/composables/usePushConnection.ts +++ b/packages/editor-ui/src/composables/usePushConnection.ts @@ -423,6 +423,7 @@ export function usePushConnection({ router }: { router: ReturnType { + const original = await vi.importActual('element-plus'); + return { + ...original, + ElNotification: vi.fn(), + ElTooltip: vi.fn(), + }; +}); + +describe('useToast', () => { + let toast: ReturnType; + + beforeEach(() => { + setActivePinia(createPinia()); + + toast = useToast(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should show a message', () => { + const messageData = { message: 'Test message', title: 'Test title' }; + toast.showMessage(messageData); + + expect(Notification).toHaveBeenCalledWith( + expect.objectContaining({ + message: 'Test message', + title: 'Test title', + }), + ); + }); + + it('should sanitize message and title', () => { + const messageData = { + message: '', + title: '', + }; + + toast.showMessage(messageData); + + expect(Notification).toHaveBeenCalledWith( + expect.objectContaining({ + message: 'alert("xss")', + title: 'alert("xss")', + }), + ); + }); +});