mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-23 10:32:17 -08:00
test(editor): Add e2e tests for executions preview (#5458)
* ✅ Added initial tests for executions preview * 🔥 Removing unneeded actions * 👌 Renaming test suite, moving mock executions logic to util function
This commit is contained in:
parent
856238721a
commit
3b9eec77ec
40
cypress/e2e/20-workflow-executions.cy.ts
Normal file
40
cypress/e2e/20-workflow-executions.cy.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { WorkflowPage } from "../pages";
|
||||
import { WorkflowExecutionsTab } from "../pages/workflow-executions-tab";
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
const executionsTab = new WorkflowExecutionsTab();
|
||||
|
||||
// Test suite for executions tab
|
||||
describe('Current Workflow Executions', () => {
|
||||
before(() => {
|
||||
cy.resetAll();
|
||||
cy.skipSetup();
|
||||
workflowPage.actions.visit();
|
||||
cy.waitForLoad();
|
||||
cy.createFixtureWorkflow('Test_workflow_4_executions_view.json', `My test workflow`);
|
||||
createMockExecutions();
|
||||
});
|
||||
|
||||
it('should render executions tab correctly', () => {
|
||||
cy.waitForLoad();
|
||||
executionsTab.getters.executionListItems().should('have.length', 11);
|
||||
executionsTab.getters.successfulExecutionListItems().should('have.length', 9);
|
||||
executionsTab.getters.failedExecutionListItems().should('have.length', 2);
|
||||
executionsTab.getters.executionListItems().first().invoke('attr','class').should('match', /_active_/);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
const createMockExecutions = () => {
|
||||
workflowPage.actions.turnOnManualExecutionSaving();
|
||||
executionsTab.actions.createManualExecutions(5);
|
||||
// Make some failed executions by enabling Code node with syntax error
|
||||
executionsTab.actions.toggleNodeEnabled('Error');
|
||||
executionsTab.actions.createManualExecutions(2);
|
||||
// Then add some more successful ones
|
||||
executionsTab.actions.toggleNodeEnabled('Error');
|
||||
executionsTab.actions.createManualExecutions(4);
|
||||
executionsTab.actions.switchToExecutionsTab();
|
||||
cy.waitForLoad();
|
||||
}
|
69
cypress/fixtures/Test_workflow_4_executions_view.json
Normal file
69
cypress/fixtures/Test_workflow_4_executions_view.json
Normal file
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"meta": {
|
||||
"instanceId": "6b85439d79c07750ea49eced4bc2a12b283cfcba0ab2917cd4f3fee36080e869"
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Loop over input items and add a new field\n// called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n error\n}\n\nreturn $input.all();"
|
||||
},
|
||||
"id": "d0ab7e12-0e1b-4c08-8081-83107794f37d",
|
||||
"name": "Error",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
680,
|
||||
460
|
||||
],
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"id": "f5026145-66c1-463c-8ac8-46a1309a6632",
|
||||
"name": "On clicking 'execute'",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
460,
|
||||
460
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Loop over input items and add a new field\n// called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n}\n\nreturn $input.all();"
|
||||
},
|
||||
"id": "9926f884-348a-4af0-872e-dd7c8b3da811",
|
||||
"name": "Code",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
900,
|
||||
460
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Error": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Code",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"On clicking 'execute'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Error",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
40
cypress/pages/workflow-executions-tab.ts
Normal file
40
cypress/pages/workflow-executions-tab.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { BasePage } from "./base";
|
||||
import { WorkflowPage } from "./workflow";
|
||||
|
||||
const workflowPage = new WorkflowPage();
|
||||
|
||||
export class WorkflowExecutionsTab extends BasePage {
|
||||
getters = {
|
||||
executionsTabButton: () => cy.getByTestId('radio-button-executions'),
|
||||
executionsSidebar: () => cy.getByTestId('executions-sidebar'),
|
||||
autoRefreshCheckBox: () => cy.getByTestId('auto-refresh-checkbox'),
|
||||
executionsList: () => cy.getByTestId('current-executions-list'),
|
||||
executionListItems: () => this.getters.executionsList().find('div.execution-card'),
|
||||
successfulExecutionListItems: () => cy.get('[data-test-execution-status="success"]'),
|
||||
failedExecutionListItems: () => cy.get('[data-test-execution-status="error"]'),
|
||||
executionCard: (executionId: string) => cy.getByTestId(`execution-details-${executionId}`),
|
||||
executionPreviewDetails: () => cy.get('[data-test-id^="execution-preview-details-"]'),
|
||||
executionPreviewDetailsById: (executionId: string) => cy.getByTestId(`execution-preview-details-${executionId}`),
|
||||
executionPreviewTime: () => this.getters.executionPreviewDetails().find('[data-test-id="execution-time"]'),
|
||||
executionPreviewStatus: () => this.getters.executionPreviewDetails().find('[data-test-id="execution-preview-label"]'),
|
||||
executionPreviewId: () => this.getters.executionPreviewDetails().find('[data-test-id="execution-preview-id"]'),
|
||||
};
|
||||
actions = {
|
||||
toggleNodeEnabled: (nodeName: string) => {
|
||||
workflowPage.getters.canvasNodeByName(nodeName).click();
|
||||
cy.get('body').type('d', { force: true });
|
||||
},
|
||||
createManualExecutions: (count: number) => {
|
||||
for (let i=0; i<count; i++) {
|
||||
workflowPage.actions.executeWorkflow();
|
||||
cy.wait(300);
|
||||
}
|
||||
},
|
||||
switchToExecutionsTab: () => {
|
||||
this.getters.executionsTabButton().click();
|
||||
},
|
||||
switchToEditorTab: () => {
|
||||
workflowPage.getters.editorTabButton().click();
|
||||
}
|
||||
};
|
||||
};
|
|
@ -103,6 +103,7 @@ export class WorkflowPage extends BasePage {
|
|||
cy.get(
|
||||
`.connection-actions[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`,
|
||||
),
|
||||
editorTabButton: () => cy.getByTestId('radio-button-workflow'),
|
||||
};
|
||||
actions = {
|
||||
visit: () => {
|
||||
|
@ -230,5 +231,15 @@ export class WorkflowPage extends BasePage {
|
|||
.first()
|
||||
.click({ force: true });
|
||||
},
|
||||
turnOnManualExecutionSaving: () => {
|
||||
this.getters.workflowMenu().click();
|
||||
this.getters.workflowMenuItemSettings().click();
|
||||
this.getters
|
||||
.workflowSettingsSaveManualExecutionsSelect()
|
||||
.find('li:contains("Yes")')
|
||||
.click({ force: true });
|
||||
this.getters.workflowSettingsSaveButton().click();
|
||||
this.getters.successToast().should('exist');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[$style[size]]: true,
|
||||
[$style.disabled]: disabled,
|
||||
}"
|
||||
:data-test-id="`radio-button-${value}`"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
{{ label }}
|
||||
|
|
|
@ -14,11 +14,12 @@
|
|||
name: VIEWS.EXECUTION_PREVIEW,
|
||||
params: { workflowId: currentWorkflow, executionId: execution.id },
|
||||
}"
|
||||
:data-test-execution-status="executionUIDetails.name"
|
||||
>
|
||||
<div :class="$style.description">
|
||||
<n8n-text color="text-dark" :bold="true" size="medium">{{
|
||||
executionUIDetails.startTime
|
||||
}}</n8n-text>
|
||||
<n8n-text color="text-dark" :bold="true" size="medium" data-test-id="execution-time">
|
||||
{{ executionUIDetails.startTime }}
|
||||
</n8n-text>
|
||||
<div :class="$style.executionStatus">
|
||||
<n8n-spinner
|
||||
v-if="executionUIDetails.name === 'running'"
|
||||
|
@ -62,6 +63,7 @@
|
|||
:class="[$style.icon, $style.retry]"
|
||||
:items="retryExecutionActions"
|
||||
activatorIcon="redo"
|
||||
data-test-id="retry-execution-button"
|
||||
@select="onRetryMenuItemSelect"
|
||||
/>
|
||||
<n8n-tooltip v-if="execution.mode === 'manual'" placement="top">
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
<div
|
||||
:class="{ [$style.executionDetails]: true, [$style.sidebarCollapsed]: sidebarCollapsed }"
|
||||
v-if="activeExecution"
|
||||
:data-test-id="`execution-preview-details-${executionId}`"
|
||||
>
|
||||
<div>
|
||||
<n8n-text size="large" color="text-base" :bold="true">{{
|
||||
<n8n-text size="large" color="text-base" :bold="true" data-test-id="execution-time">{{
|
||||
executionUIDetails.startTime
|
||||
}}</n8n-text
|
||||
><br />
|
||||
|
@ -28,9 +29,13 @@
|
|||
size="small"
|
||||
:class="[$style.spinner, 'mr-4xs']"
|
||||
/>
|
||||
<n8n-text size="medium" :class="[$style.status, $style[executionUIDetails.name]]">{{
|
||||
executionUIDetails.label
|
||||
}}</n8n-text>
|
||||
<n8n-text
|
||||
size="medium"
|
||||
:class="[$style.status, $style[executionUIDetails.name]]"
|
||||
data-test-id="execution-preview-label"
|
||||
>
|
||||
{{ executionUIDetails.label }}
|
||||
</n8n-text>
|
||||
<n8n-text v-if="executionUIDetails.name === 'running'" color="text-base" size="medium">
|
||||
{{
|
||||
$locale.baseText('executionDetails.runningTimeRunning', {
|
||||
|
@ -39,7 +44,12 @@
|
|||
}}
|
||||
| ID#{{ activeExecution.id }}
|
||||
</n8n-text>
|
||||
<n8n-text v-else-if="executionUIDetails.name !== 'waiting'" color="text-base" size="medium">
|
||||
<n8n-text
|
||||
v-else-if="executionUIDetails.name !== 'waiting'"
|
||||
color="text-base"
|
||||
size="medium"
|
||||
data-test-id="execution-preview-id"
|
||||
>
|
||||
{{
|
||||
$locale.baseText('executionDetails.runningTimeFinished', {
|
||||
interpolate: { time: executionUIDetails.runningTime },
|
||||
|
@ -80,6 +90,7 @@
|
|||
type="tertiary"
|
||||
:title="$locale.baseText('executionsList.retryExecution')"
|
||||
icon="redo"
|
||||
data-test-id="execution-preview-retry-button"
|
||||
@blur="onRetryButtonBlur"
|
||||
/>
|
||||
</span>
|
||||
|
@ -99,6 +110,7 @@
|
|||
icon="trash"
|
||||
size="large"
|
||||
type="tertiary"
|
||||
data-test-id="execution-preview-delete-button"
|
||||
@click="onDeleteExecution"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,32 @@
|
|||
<template>
|
||||
<div :class="['executions-sidebar', $style.container]" ref="container">
|
||||
<div
|
||||
:class="['executions-sidebar', $style.container]"
|
||||
ref="container"
|
||||
data-test-id="executions-sidebar"
|
||||
>
|
||||
<div :class="$style.heading">
|
||||
<n8n-heading tag="h2" size="medium" color="text-dark">
|
||||
{{ $locale.baseText('generic.executions') }}
|
||||
</n8n-heading>
|
||||
</div>
|
||||
<div :class="$style.controls">
|
||||
<el-checkbox v-model="autoRefresh" @change="onAutoRefreshToggle">{{
|
||||
$locale.baseText('executionsList.autoRefresh')
|
||||
}}</el-checkbox>
|
||||
<el-checkbox
|
||||
v-model="autoRefresh"
|
||||
@change="onAutoRefreshToggle"
|
||||
data-test-id="auto-refresh-checkbox"
|
||||
>
|
||||
{{ $locale.baseText('executionsList.autoRefresh') }}
|
||||
</el-checkbox>
|
||||
<n8n-popover trigger="click">
|
||||
<template #reference>
|
||||
<div :class="$style.filterButton">
|
||||
<n8n-button icon="filter" type="tertiary" size="medium" :active="statusFilterApplied">
|
||||
<n8n-button
|
||||
icon="filter"
|
||||
type="tertiary"
|
||||
size="medium"
|
||||
:active="statusFilterApplied"
|
||||
data-test-id="executions-filter-button"
|
||||
>
|
||||
<n8n-badge v-if="statusFilterApplied" theme="primary" class="mr-4xs">1</n8n-badge>
|
||||
{{ $locale.baseText('executionsList.filters') }}
|
||||
</n8n-button>
|
||||
|
@ -33,6 +47,7 @@
|
|||
ref="typeInput"
|
||||
:class="$style['type-input']"
|
||||
:placeholder="$locale.baseText('generic.any')"
|
||||
data-test-id="execution-status-select"
|
||||
@change="onFilterChange"
|
||||
>
|
||||
<n8n-option
|
||||
|
@ -40,6 +55,7 @@
|
|||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:data-test-id="`execution-status-${item.id}`"
|
||||
>
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
|
@ -60,7 +76,12 @@
|
|||
</n8n-link>
|
||||
</n8n-info-tip>
|
||||
</div>
|
||||
<div :class="$style.executionList" ref="executionList" @scroll="loadMore(20)">
|
||||
<div
|
||||
:class="$style.executionList"
|
||||
ref="executionList"
|
||||
data-test-id="current-executions-list"
|
||||
@scroll="loadMore(20)"
|
||||
>
|
||||
<div v-if="loading" class="mr-m">
|
||||
<n8n-loading :class="$style.loader" variant="p" :rows="1" />
|
||||
<n8n-loading :class="$style.loader" variant="p" :rows="1" />
|
||||
|
@ -77,6 +98,7 @@
|
|||
:key="execution.id"
|
||||
:execution="execution"
|
||||
:ref="`execution-${execution.id}`"
|
||||
:data-test-id="`execution-details-${execution.id}`"
|
||||
@refresh="onRefresh"
|
||||
@retryExecution="onRetryExecution"
|
||||
/>
|
||||
|
|
Loading…
Reference in a new issue