1
1
mirror of https://github.com/n8n-io/n8n.git synced 2024-09-11 21:17:50 +03: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:
Milorad FIlipović 2023-02-14 11:39:19 +01:00 committed by GitHub
parent 856238721a
commit 3b9eec77ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 211 additions and 14 deletions

View 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();
}

View 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
}
]
]
}
}
}

View 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();
}
};
};

View File

@ -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');
},
};
}

View File

@ -17,6 +17,7 @@
[$style[size]]: true,
[$style.disabled]: disabled,
}"
:data-test-id="`radio-button-${value}`"
@click="$emit('click')"
>
{{ label }}

View File

@ -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">

View File

@ -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>

View File

@ -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"
/>