mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-27 23:07:12 +02:00
fix(editor): Reflect Wait node's execution status correctly in log view (#19898)
This commit is contained in:
parent
7f2aaa7a7a
commit
a6793593b9
|
|
@ -65,7 +65,7 @@ export type NodeExecuteAfter = {
|
|||
/**
|
||||
* The data field for task data in `NodeExecuteAfter` is always trimmed (undefined).
|
||||
*/
|
||||
data: ITaskData;
|
||||
data: Omit<ITaskData, 'data'>;
|
||||
/**
|
||||
* The number of items per output connection type. This is needed so that the frontend
|
||||
* can know how many items to expect when receiving the `NodeExecuteAfterData` message.
|
||||
|
|
|
|||
|
|
@ -37,14 +37,14 @@ describe('nodeExecuteAfter', () => {
|
|||
|
||||
await nodeExecuteAfter(event);
|
||||
|
||||
expect(workflowsStore.updateNodeExecutionData).toHaveBeenCalledTimes(1);
|
||||
expect(workflowsStore.updateNodeExecutionStatus).toHaveBeenCalledTimes(1);
|
||||
expect(workflowsStore.removeExecutingNode).toHaveBeenCalledTimes(1);
|
||||
expect(workflowsStore.removeExecutingNode).toHaveBeenCalledWith('Test Node');
|
||||
expect(assistantStore.onNodeExecution).toHaveBeenCalledTimes(1);
|
||||
expect(assistantStore.onNodeExecution).toHaveBeenCalledWith(event.data);
|
||||
|
||||
// Verify the placeholder data structure
|
||||
const updateCall = workflowsStore.updateNodeExecutionData.mock.calls[0][0];
|
||||
const updateCall = workflowsStore.updateNodeExecutionStatus.mock.calls[0][0];
|
||||
expect(updateCall.data.data).toEqual({
|
||||
main: [
|
||||
Array.from({ length: 2 }).fill({ json: { [TRIMMED_TASK_DATA_CONNECTIONS_KEY]: true } }),
|
||||
|
|
@ -77,7 +77,7 @@ describe('nodeExecuteAfter', () => {
|
|||
|
||||
await nodeExecuteAfter(event);
|
||||
|
||||
const updateCall = workflowsStore.updateNodeExecutionData.mock.calls[0][0];
|
||||
const updateCall = workflowsStore.updateNodeExecutionStatus.mock.calls[0][0];
|
||||
expect(updateCall.data.data).toEqual({
|
||||
main: [
|
||||
Array.from({ length: 3 }).fill({ json: { [TRIMMED_TASK_DATA_CONNECTIONS_KEY]: true } }),
|
||||
|
|
@ -112,7 +112,7 @@ describe('nodeExecuteAfter', () => {
|
|||
|
||||
await nodeExecuteAfter(event);
|
||||
|
||||
const updateCall = workflowsStore.updateNodeExecutionData.mock.calls[0][0];
|
||||
const updateCall = workflowsStore.updateNodeExecutionStatus.mock.calls[0][0];
|
||||
expect(updateCall.data.data).toEqual({
|
||||
main: [],
|
||||
});
|
||||
|
|
@ -138,7 +138,7 @@ describe('nodeExecuteAfter', () => {
|
|||
|
||||
await nodeExecuteAfter(event);
|
||||
|
||||
const updateCall = workflowsStore.updateNodeExecutionData.mock.calls[0][0];
|
||||
const updateCall = workflowsStore.updateNodeExecutionStatus.mock.calls[0][0];
|
||||
expect(updateCall.executionId).toBe('exec-1');
|
||||
expect(updateCall.nodeName).toBe('Test Node');
|
||||
expect(updateCall.data.executionTime).toBe(100);
|
||||
|
|
@ -178,7 +178,7 @@ describe('nodeExecuteAfter', () => {
|
|||
|
||||
await nodeExecuteAfter(event);
|
||||
|
||||
const updateCall = workflowsStore.updateNodeExecutionData.mock.calls[0][0];
|
||||
const updateCall = workflowsStore.updateNodeExecutionStatus.mock.calls[0][0];
|
||||
// Should only contain main connection, invalid_connection should be filtered out
|
||||
expect(updateCall.data.data).toEqual({
|
||||
main: [
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export async function nodeExecuteAfter({ data: pushData }: NodeExecuteAfter) {
|
|||
},
|
||||
};
|
||||
|
||||
workflowsStore.updateNodeExecutionData(pushDataWithPlaceholderOutputData);
|
||||
workflowsStore.updateNodeExecutionStatus(pushDataWithPlaceholderOutputData);
|
||||
workflowsStore.removeExecutingNode(pushData.nodeName);
|
||||
|
||||
void assistantStore.onNodeExecution(pushData);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ describe('nodeExecuteAfterData', () => {
|
|||
|
||||
await nodeExecuteAfterData(event);
|
||||
|
||||
expect(workflowsStore.updateNodeExecutionData).toHaveBeenCalledTimes(1);
|
||||
expect(workflowsStore.updateNodeExecutionData).toHaveBeenCalledWith(event.data);
|
||||
expect(workflowsStore.updateNodeExecutionRunData).toHaveBeenCalledTimes(1);
|
||||
expect(workflowsStore.updateNodeExecutionRunData).toHaveBeenCalledWith(event.data);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export async function nodeExecuteAfterData({ data: pushData }: NodeExecuteAfterD
|
|||
const workflowsStore = useWorkflowsStore();
|
||||
const schemaPreviewStore = useSchemaPreviewStore();
|
||||
|
||||
workflowsStore.updateNodeExecutionData(pushData);
|
||||
workflowsStore.updateNodeExecutionRunData(pushData);
|
||||
|
||||
void schemaPreviewStore.trackSchemaPreviewExecution(pushData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type {
|
||||
IExecutionPushResponse,
|
||||
IExecutionResponse,
|
||||
IExecutionsStopData,
|
||||
IStartRunData,
|
||||
IWorkflowDb,
|
||||
} from '@/Interface';
|
||||
|
|
@ -476,12 +477,14 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
|||
|
||||
async function stopCurrentExecution() {
|
||||
const executionId = workflowsStore.activeExecutionId;
|
||||
let stopData: IExecutionsStopData | undefined;
|
||||
|
||||
if (!executionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await executionsStore.stopCurrentExecution(executionId);
|
||||
stopData = await executionsStore.stopCurrentExecution(executionId);
|
||||
} catch (error) {
|
||||
// Execution stop might fail when the execution has already finished. Let's treat this here.
|
||||
const execution = await workflowsStore.getExecution(executionId);
|
||||
|
|
@ -518,7 +521,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
|||
async () => {
|
||||
const execution = await workflowsStore.getExecution(executionId);
|
||||
if (!['running', 'waiting'].includes(execution?.status as string)) {
|
||||
workflowsStore.markExecutionAsStopped();
|
||||
workflowsStore.markExecutionAsStopped(stopData);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -529,7 +532,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
|||
);
|
||||
|
||||
if (!markedAsStopped) {
|
||||
workflowsStore.markExecutionAsStopped();
|
||||
workflowsStore.markExecutionAsStopped(stopData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ describe('LogsPanel', () => {
|
|||
expect(lastTreeItem.getByText('AI Agent')).toBeInTheDocument();
|
||||
expect(lastTreeItem.getByText(/Running/)).toBeInTheDocument();
|
||||
|
||||
workflowsStore.updateNodeExecutionData({
|
||||
workflowsStore.updateNodeExecutionStatus({
|
||||
nodeName: 'AI Agent',
|
||||
executionId: '567',
|
||||
itemCountByConnectionType: { ai_agent: [1] },
|
||||
|
|
|
|||
|
|
@ -31,7 +31,13 @@ import * as apiUtils from '@n8n/rest-api-client';
|
|||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useLocalStorage } from '@vueuse/core';
|
||||
import { ref } from 'vue';
|
||||
import { createTestNode, createTestWorkflow, mockNodeTypeDescription } from '@/__tests__/mocks';
|
||||
import {
|
||||
createTestNode,
|
||||
createTestTaskData,
|
||||
createTestWorkflow,
|
||||
createTestWorkflowExecutionResponse,
|
||||
mockNodeTypeDescription,
|
||||
} from '@/__tests__/mocks';
|
||||
import { waitFor } from '@testing-library/vue';
|
||||
|
||||
vi.mock('@/stores/ndv.store', () => ({
|
||||
|
|
@ -657,7 +663,90 @@ describe('useWorkflowsStore', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('updateNodeExecutionData', () => {
|
||||
describe('updateNodeExecutionRunData', () => {
|
||||
beforeEach(() => {
|
||||
workflowsStore.workflowExecutionData = createTestWorkflowExecutionResponse({
|
||||
id: 'test-execution',
|
||||
data: {
|
||||
resultData: {
|
||||
runData: {
|
||||
n0: [
|
||||
createTestTaskData({
|
||||
executionIndex: 0,
|
||||
executionStatus: 'success',
|
||||
executionTime: 33,
|
||||
}),
|
||||
createTestTaskData({
|
||||
executionIndex: 1,
|
||||
executionStatus: 'success',
|
||||
executionTime: 44,
|
||||
}),
|
||||
createTestTaskData({
|
||||
executionIndex: 2,
|
||||
executionStatus: 'running',
|
||||
executionTime: undefined,
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should replace run data at the matched index in the execution data', () => {
|
||||
workflowsStore.updateNodeExecutionRunData({
|
||||
executionId: 'test-execution',
|
||||
nodeName: 'n0',
|
||||
data: createTestTaskData({
|
||||
executionIndex: 2,
|
||||
executionStatus: 'success',
|
||||
executionTime: 100,
|
||||
}),
|
||||
itemCountByConnectionType: { main: [1] },
|
||||
});
|
||||
|
||||
const runData = workflowsStore.workflowExecutionData?.data?.resultData?.runData.n0;
|
||||
|
||||
expect(runData).toHaveLength(3);
|
||||
expect(runData?.[0].executionIndex).toBe(0);
|
||||
expect(runData?.[0].executionStatus).toBe('success');
|
||||
expect(runData?.[0].executionTime).toBe(33);
|
||||
expect(runData?.[1].executionIndex).toBe(1);
|
||||
expect(runData?.[1].executionStatus).toBe('success');
|
||||
expect(runData?.[1].executionTime).toBe(44);
|
||||
expect(runData?.[2].executionIndex).toBe(2);
|
||||
expect(runData?.[2].executionStatus).toBe('success');
|
||||
expect(runData?.[2].executionTime).toBe(100);
|
||||
});
|
||||
|
||||
it('should not modify execution data if there is no matched index in execution data', () => {
|
||||
workflowsStore.updateNodeExecutionRunData({
|
||||
executionId: 'test-execution',
|
||||
nodeName: 'n0',
|
||||
data: createTestTaskData({
|
||||
executionIndex: 3,
|
||||
executionStatus: 'success',
|
||||
executionTime: 100,
|
||||
}),
|
||||
itemCountByConnectionType: { main: [1] },
|
||||
});
|
||||
|
||||
const runData = workflowsStore.workflowExecutionData?.data?.resultData?.runData.n0;
|
||||
|
||||
expect(runData).toHaveLength(3);
|
||||
expect(runData?.[0].executionIndex).toBe(0);
|
||||
expect(runData?.[0].executionStatus).toBe('success');
|
||||
expect(runData?.[0].executionTime).toBe(33);
|
||||
expect(runData?.[1].executionIndex).toBe(1);
|
||||
expect(runData?.[1].executionStatus).toBe('success');
|
||||
expect(runData?.[1].executionTime).toBe(44);
|
||||
expect(runData?.[2].executionIndex).toBe(2);
|
||||
expect(runData?.[2].executionStatus).toBe('running');
|
||||
expect(runData?.[2].executionTime).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateNodeExecutionStatus', () => {
|
||||
let successEvent: ReturnType<typeof generateMockExecutionEvents>['successEvent'];
|
||||
let errorEvent: ReturnType<typeof generateMockExecutionEvents>['errorEvent'];
|
||||
let executionResponse: ReturnType<typeof generateMockExecutionEvents>['executionResponse'];
|
||||
|
|
@ -670,7 +759,7 @@ describe('useWorkflowsStore', () => {
|
|||
});
|
||||
|
||||
it('should throw error if not initialized', () => {
|
||||
expect(() => workflowsStore.updateNodeExecutionData(successEvent)).toThrowError();
|
||||
expect(() => workflowsStore.updateNodeExecutionStatus(successEvent)).toThrowError();
|
||||
});
|
||||
|
||||
it('should add node success run data', () => {
|
||||
|
|
@ -681,7 +770,7 @@ describe('useWorkflowsStore', () => {
|
|||
});
|
||||
|
||||
// ACT
|
||||
workflowsStore.updateNodeExecutionData(successEvent);
|
||||
workflowsStore.updateNodeExecutionStatus(successEvent);
|
||||
|
||||
expect(workflowsStore.workflowExecutionData).toEqual({
|
||||
...executionResponse,
|
||||
|
|
@ -710,7 +799,7 @@ describe('useWorkflowsStore', () => {
|
|||
getNodeType.mockReturnValue(getMockEditFieldsNode());
|
||||
|
||||
// ACT
|
||||
workflowsStore.updateNodeExecutionData(errorEvent);
|
||||
workflowsStore.updateNodeExecutionStatus(errorEvent);
|
||||
await flushPromises();
|
||||
|
||||
expect(workflowsStore.workflowExecutionData).toEqual({
|
||||
|
|
@ -793,7 +882,7 @@ describe('useWorkflowsStore', () => {
|
|||
});
|
||||
|
||||
// ACT
|
||||
workflowsStore.updateNodeExecutionData(successEvent);
|
||||
workflowsStore.updateNodeExecutionStatus(successEvent);
|
||||
|
||||
expect(workflowsStore.workflowExecutionData).toEqual({
|
||||
...runWithExistingRunData,
|
||||
|
|
@ -806,6 +895,7 @@ describe('useWorkflowsStore', () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should replace existing placeholder task data in new log view', () => {
|
||||
const successEventWithExecutionIndex = deepCopy(successEvent);
|
||||
successEventWithExecutionIndex.data.executionIndex = 1;
|
||||
|
|
@ -846,7 +936,7 @@ describe('useWorkflowsStore', () => {
|
|||
});
|
||||
|
||||
// ACT
|
||||
workflowsStore.updateNodeExecutionData(successEventWithExecutionIndex);
|
||||
workflowsStore.updateNodeExecutionStatus(successEventWithExecutionIndex);
|
||||
|
||||
expect(workflowsStore.workflowExecutionData).toEqual({
|
||||
...executionResponse,
|
||||
|
|
@ -1497,6 +1587,68 @@ describe('useWorkflowsStore', () => {
|
|||
await waitFor(() => expect(workflowsStore.selectedTriggerNodeName).toBe(undefined));
|
||||
});
|
||||
});
|
||||
|
||||
describe('markExecutionAsStopped', () => {
|
||||
beforeEach(() => {
|
||||
workflowsStore.workflowExecutionData = createTestWorkflowExecutionResponse({
|
||||
status: 'running',
|
||||
startedAt: new Date('2023-01-01T09:00:00Z'),
|
||||
stoppedAt: undefined,
|
||||
data: {
|
||||
resultData: {
|
||||
runData: {
|
||||
node1: [
|
||||
createTestTaskData({ executionStatus: 'success' }),
|
||||
createTestTaskData({ executionStatus: 'error' }),
|
||||
createTestTaskData({ executionStatus: 'running' }),
|
||||
],
|
||||
node2: [
|
||||
createTestTaskData({ executionStatus: 'success' }),
|
||||
createTestTaskData({ executionStatus: 'waiting' }),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove non successful node runs', () => {
|
||||
workflowsStore.markExecutionAsStopped();
|
||||
|
||||
const runData = workflowsStore.workflowExecutionData?.data?.resultData?.runData;
|
||||
expect(runData?.node1).toHaveLength(1);
|
||||
expect(runData?.node1[0].executionStatus).toBe('success');
|
||||
expect(runData?.node2).toHaveLength(1);
|
||||
expect(runData?.node2[0].executionStatus).toBe('success');
|
||||
});
|
||||
|
||||
it('should update execution status, startedAt and stoppedAt when data is provided', () => {
|
||||
workflowsStore.markExecutionAsStopped({
|
||||
status: 'canceled',
|
||||
startedAt: new Date('2023-01-01T10:00:00Z'),
|
||||
stoppedAt: new Date('2023-01-01T10:05:00Z'),
|
||||
mode: 'manual',
|
||||
});
|
||||
|
||||
expect(workflowsStore.workflowExecutionData?.status).toBe('canceled');
|
||||
expect(workflowsStore.workflowExecutionData?.startedAt).toEqual(
|
||||
new Date('2023-01-01T10:00:00Z'),
|
||||
);
|
||||
expect(workflowsStore.workflowExecutionData?.stoppedAt).toEqual(
|
||||
new Date('2023-01-01T10:05:00Z'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not update execution data when stopData is not provided', () => {
|
||||
workflowsStore.markExecutionAsStopped();
|
||||
|
||||
expect(workflowsStore.workflowExecutionData?.status).toBe('running');
|
||||
expect(workflowsStore.workflowExecutionData?.startedAt).toEqual(
|
||||
new Date('2023-01-01T09:00:00Z'),
|
||||
);
|
||||
expect(workflowsStore.workflowExecutionData?.stoppedAt).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getMockEditFieldsNode(): Partial<INodeTypeDescription> {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import type {
|
|||
NodeMetadataMap,
|
||||
IExecutionFlattedResponse,
|
||||
WorkflowListResource,
|
||||
IExecutionsStopData,
|
||||
} from '@/Interface';
|
||||
import type { IWorkflowTemplateNode } from '@n8n/rest-api-client/api/templates';
|
||||
import type {
|
||||
|
|
@ -1556,7 +1557,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
|||
];
|
||||
}
|
||||
|
||||
function updateNodeExecutionData(pushData: PushPayload<'nodeExecuteAfterData'>): void {
|
||||
function updateNodeExecutionStatus(pushData: PushPayload<'nodeExecuteAfterData'>): void {
|
||||
if (!workflowExecutionData.value?.data) {
|
||||
throw new Error('The "workflowExecutionData" is not initialized!');
|
||||
}
|
||||
|
|
@ -1583,7 +1584,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
|||
openFormPopupWindow(testUrl);
|
||||
}
|
||||
} else {
|
||||
// If we process items in paralell on subnodes we get several placeholder taskData items.
|
||||
// If we process items in parallel on subnodes we get several placeholder taskData items.
|
||||
// We need to find and replace the item with the matching executionIndex and only append if we don't find anything matching.
|
||||
const existingRunIndex = tasksData.findIndex(
|
||||
(item) => item.executionIndex === data.executionIndex,
|
||||
|
|
@ -1607,6 +1608,17 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
|||
}
|
||||
}
|
||||
|
||||
function updateNodeExecutionRunData(pushData: PushPayload<'nodeExecuteAfterData'>): void {
|
||||
const tasksData = workflowExecutionData.value?.data?.resultData.runData[pushData.nodeName];
|
||||
const existingRunIndex =
|
||||
tasksData?.findIndex((item) => item.executionIndex === pushData.data.executionIndex) ?? -1;
|
||||
|
||||
if (tasksData?.[existingRunIndex]) {
|
||||
tasksData.splice(existingRunIndex, 1, pushData.data);
|
||||
workflowExecutionResultDataLastUpdate.value = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
function clearNodeExecutionData(nodeName: string): void {
|
||||
if (!workflowExecutionData.value?.data) {
|
||||
return;
|
||||
|
|
@ -1897,20 +1909,32 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
|||
// End Canvas V2 Functions
|
||||
//
|
||||
|
||||
function markExecutionAsStopped() {
|
||||
function markExecutionAsStopped(stopData?: IExecutionsStopData) {
|
||||
setActiveExecutionId(undefined);
|
||||
clearNodeExecutionQueue();
|
||||
executionWaitingForWebhook.value = false;
|
||||
workflowHelpers.setDocumentTitle(workflowName.value, 'IDLE');
|
||||
workflowExecutionStartedData.value = undefined;
|
||||
|
||||
clearPopupWindowState();
|
||||
|
||||
const runData = workflowExecutionData.value?.data?.resultData.runData ?? {};
|
||||
if (!workflowExecutionData.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const runData = workflowExecutionData.value.data?.resultData.runData ?? {};
|
||||
|
||||
for (const nodeName in runData) {
|
||||
runData[nodeName] = runData[nodeName].filter(
|
||||
({ executionStatus }) => executionStatus === 'success',
|
||||
);
|
||||
}
|
||||
|
||||
if (stopData) {
|
||||
workflowExecutionData.value.status = stopData.status;
|
||||
workflowExecutionData.value.startedAt = stopData.startedAt;
|
||||
workflowExecutionData.value.stoppedAt = stopData.stoppedAt;
|
||||
}
|
||||
}
|
||||
|
||||
function setSelectedTriggerNodeName(value: string) {
|
||||
|
|
@ -2077,7 +2101,8 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
|||
setNodeValue,
|
||||
setNodeParameters,
|
||||
setLastNodeParameters,
|
||||
updateNodeExecutionData,
|
||||
updateNodeExecutionRunData,
|
||||
updateNodeExecutionStatus,
|
||||
clearNodeExecutionData,
|
||||
pinDataByNodeName,
|
||||
activeNode,
|
||||
|
|
|
|||
|
|
@ -446,6 +446,10 @@ export class CanvasPage extends BasePage {
|
|||
return this.page.getByTestId('toggle-focus-panel-button');
|
||||
}
|
||||
|
||||
stopExecutionButton(): Locator {
|
||||
return this.page.getByTestId('stop-execution-button');
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
async addInitialNodeToCanvas(nodeName: string): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -250,6 +250,9 @@ test.describe('Logs', () => {
|
|||
.getAttribute('href');
|
||||
await n8n.ndv.clickBackToCanvasButton();
|
||||
|
||||
// [CAT-1454] Assert that no duplicate logs added at this point
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries()).toHaveCount(2);
|
||||
|
||||
// Trigger the webhook
|
||||
const response = await n8n.page.request.get(webhookUrl!);
|
||||
expect(response.status()).toBe(200);
|
||||
|
|
@ -263,4 +266,27 @@ test.describe('Logs', () => {
|
|||
await expect(n8n.canvas.logsPanel.getLogEntries().nth(1)).toContainText(NODES.WAIT_NODE);
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries().nth(1)).toContainText('Success');
|
||||
});
|
||||
|
||||
test('should allow to cancel a workflow with a node that waits for webhook', async ({ n8n }) => {
|
||||
await n8n.start.fromImportedWorkflow('Workflow_wait_for_webhook.json');
|
||||
await n8n.canvas.deselectAll();
|
||||
await n8n.canvas.logsPanel.open();
|
||||
|
||||
await n8n.canvas.clickExecuteWorkflowButton();
|
||||
|
||||
await expect(n8n.canvas.getWaitingNodes()).toContainText(NODES.WAIT_NODE);
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries()).toHaveCount(2);
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries().nth(0)).toContainText(
|
||||
'When clicking ‘Test workflow’',
|
||||
);
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries().nth(1)).toContainText(NODES.WAIT_NODE);
|
||||
|
||||
await n8n.canvas.stopExecutionButton().click();
|
||||
await expect(n8n.canvas.stopExecutionButton()).toBeHidden();
|
||||
await expect(n8n.canvas.logsPanel.getOverviewStatus()).toContainText('Canceled in');
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries()).toHaveCount(1);
|
||||
await expect(n8n.canvas.logsPanel.getLogEntries().nth(0)).toContainText(
|
||||
'When clicking ‘Test workflow’',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user