From cb3bfc32f79ab4eba385fd3eb8bbb9a2f6e3a442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milorad=20FIlipovi=C4=87?= Date: Fri, 25 Nov 2022 15:32:09 +0100 Subject: [PATCH] test: Setup e2e tests for workflow actions (#4724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✅ Adding first batch of workflow actions tests * ✅ Adding loading handling logic and new workflow actions tests * ✅ Added workflow activation and rename tests * 👌 Addressing review feedback * 🔥 Removing leftover commented code --- cypress/e2e/5-workflow-actions.cy.ts | 70 +++++++++++++++++++ cypress/pages/workflow.ts | 35 ++++++++-- .../N8nActionToggle/ActionToggle.vue | 6 +- .../components/MainHeader/WorkflowDetails.vue | 5 +- .../editor-ui/src/components/ShortenName.vue | 4 +- .../src/components/WorkflowActivator.vue | 6 +- packages/editor-ui/src/views/LoadingView.vue | 2 +- packages/editor-ui/src/views/NodeView.vue | 1 + 8 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 cypress/e2e/5-workflow-actions.cy.ts diff --git a/cypress/e2e/5-workflow-actions.cy.ts b/cypress/e2e/5-workflow-actions.cy.ts new file mode 100644 index 0000000000..7976756c3e --- /dev/null +++ b/cypress/e2e/5-workflow-actions.cy.ts @@ -0,0 +1,70 @@ +import { randFirstName, randLastName } from "@ngneat/falso"; +import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from "../constants"; +import { WorkflowPage as WorkflowPageClass } from '../pages/workflow'; + +const NEW_WORKFLOW_NAME = 'Something else'; +const MANUAL_TRIGGER_NODE_NAME = 'Manual Trigger'; +const SCHEDULE_TRIGGER_NODE_NAME = 'Schedule Trigger'; + +const username = DEFAULT_USER_EMAIL; +const password = DEFAULT_USER_PASSWORD; +const firstName = randFirstName(); +const lastName = randLastName(); +const WorkflowPage = new WorkflowPageClass(); + +describe('Workflow Actions', () => { + beforeEach(() => { + cy.signup(username, firstName, lastName, password); + cy.on('uncaught:exception', (err, runnable) => { + expect(err.message).to.include('Not logged in'); + + return false; + }) + + cy.signin(username, password); + + WorkflowPage.actions.visit(); + }); + + it('should be able to save on button slick', () => { + WorkflowPage.actions.saveWorkflowOnButtonClick(); + // In Element UI, disabled button turn into spans 🤷‍♂️ + WorkflowPage.getters.saveButton().should('match', 'span'); + }); + + it('should save workflow on keyboard shortcut', () => { + WorkflowPage.actions.saveWorkflowUsingKeyboardShortcut(); + WorkflowPage.getters.saveButton().should('match', 'span'); + }); + + it('should not be able to activate unsaved workflow', () => { + WorkflowPage.getters.activatorSwitch().find('input').first().should('be.disabled'); + }); + + it('should not be able to activate workflow without trigger node', () => { + // Manual trigger is not enough to activate the workflow + WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME); + WorkflowPage.actions.saveWorkflowOnButtonClick(); + WorkflowPage.getters.activatorSwitch().find('input').first().should('be.disabled'); + }); + + it('should be able to activate workflow', () => { + WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME); + WorkflowPage.actions.saveWorkflowOnButtonClick(); + WorkflowPage.actions.activateWorkflow(); + WorkflowPage.getters.activatorSwitch().should('have.class', 'is-checked'); + }); + + it('should save new workflow after renaming', () => { + WorkflowPage.actions.renameWorkflow(NEW_WORKFLOW_NAME); + WorkflowPage.getters.saveButton().should('match', 'span'); + }); + + it('should rename workflow', () => { + WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME); + WorkflowPage.actions.saveWorkflowOnButtonClick(); + WorkflowPage.actions.renameWorkflow(NEW_WORKFLOW_NAME); + WorkflowPage.getters.saveButton().should('match', 'span'); + WorkflowPage.getters.workflowNameInput().invoke('attr', 'title').should('eq', NEW_WORKFLOW_NAME); + }); +}); diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index f6326f837e..27308267be 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -3,13 +3,10 @@ import { BasePage } from './base'; export class WorkflowPage extends BasePage { url = '/workflow/new'; getters = { - workflowNameInput: () => - cy - .getByTestId('workflow-name-input', { timeout: 5000 }) - .then(($el) => cy.wrap($el.find('input'))), + workflowNameInput: () => cy.getByTestId('workflow-name-input'), workflowImportInput: () => cy.getByTestId('workflow-import-input'), workflowTags: () => cy.getByTestId('workflow-tags'), - saveButton: () => cy.getByTestId('save-button'), + saveButton: () => cy.getByTestId('workflow-save-button'), nodeCreatorSearchBar: () => cy.getByTestId('node-creator-search-bar'), nodeCreatorPlusButton: () => cy.getByTestId('node-creator-plus-button'), @@ -24,6 +21,9 @@ export class WorkflowPage extends BasePage { ndvParameterInput: (parameterName: string) => cy.getByTestId(`parameter-input-${parameterName}`), ndvOutputPanel: () => cy.getByTestId('output-panel'), + activatorSwitch: () => cy.getByTestId('workflow-activate-switch'), + workflowMenu: () => cy.getByTestId('workflow-menu'), + firstStepButton: () => cy.getByTestId('canvas-add-button'), }; actions = { @@ -46,5 +46,30 @@ export class WorkflowPage extends BasePage { executeNodeFromNdv: () => { cy.contains('Execute node').click(); }, + visit: () => { + cy.visit(this.url); + cy.getByTestId('node-view-loader', { timeout: 5000 }).should('not.exist'); + cy.get('.el-loading-mask', { timeout: 5000 }).should('not.exist'); + }, + openWorkflowMenu: () => { + this.getters.workflowMenu().click(); + }, + saveWorkflowOnButtonClick: () => { + this.getters.saveButton().click(); + }, + saveWorkflowUsingKeyboardShortcut: () => { + cy.get('body').type('{meta}', { release: false }).type('s'); + }, + activateWorkflow: () => { + this.getters.activatorSwitch().find('input').first().should('be.enabled'); + this.getters.activatorSwitch().click(); + cy.get('body').type('{esc}'); + }, + renameWorkflow: (newName: string) => { + this.getters.workflowNameInput().click(); + cy.get('body').type('{selectall}'); + cy.get('body').type(newName); + cy.get('body').type('{enter}'); + }, }; } diff --git a/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue b/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue index 1b71a5b3eb..5168128438 100644 --- a/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue +++ b/packages/design-system/src/components/N8nActionToggle/ActionToggle.vue @@ -13,7 +13,7 @@ diff --git a/packages/editor-ui/src/components/ShortenName.vue b/packages/editor-ui/src/components/ShortenName.vue index c09a22398f..b629f22374 100644 --- a/packages/editor-ui/src/components/ShortenName.vue +++ b/packages/editor-ui/src/components/ShortenName.vue @@ -1,5 +1,5 @@ @@ -13,7 +13,7 @@ const WORKFLOW_NAME_END_COUNT_TO_KEEP = 4; export default Vue.extend({ name: "ShortenName", - props: ["name", "limit"], + props: ["name", "limit", "testId"], computed: { shortenedName(): string { return shorten(this.name, this.limit || DEFAULT_WORKFLOW_NAME_LIMIT, WORKFLOW_NAME_END_COUNT_TO_KEEP); diff --git a/packages/editor-ui/src/components/WorkflowActivator.vue b/packages/editor-ui/src/components/WorkflowActivator.vue index 452508c45f..cf4ec1583d 100644 --- a/packages/editor-ui/src/components/WorkflowActivator.vue +++ b/packages/editor-ui/src/components/WorkflowActivator.vue @@ -16,11 +16,13 @@ v-loading="updatingWorkflowActivation" :value="workflowActive" @change="activeChanged" - :title="workflowActive ? $locale.baseText('workflowActivator.deactivateWorkflow') : $locale.baseText('workflowActivator.activateWorkflow')" + :title="workflowActive ? $locale.baseText('workflowActivator.deactivateWorkflow') : $locale.baseText('workflowActivator.activateWorkflow')" :disabled="disabled || updatingWorkflowActivation" :active-color="getActiveColor" inactive-color="#8899AA" - element-loading-spinner="el-icon-loading"> + element-loading-spinner="el-icon-loading" + data-test-id="workflow-activate-switch" + > diff --git a/packages/editor-ui/src/views/LoadingView.vue b/packages/editor-ui/src/views/LoadingView.vue index 55a051b3d3..03ba2045d3 100644 --- a/packages/editor-ui/src/views/LoadingView.vue +++ b/packages/editor-ui/src/views/LoadingView.vue @@ -1,5 +1,5 @@