diff --git a/cypress/e2e/30-editor-after-route-changes.cy.ts b/cypress/e2e/30-editor-after-route-changes.cy.ts new file mode 100644 index 0000000000..3f20879dab --- /dev/null +++ b/cypress/e2e/30-editor-after-route-changes.cy.ts @@ -0,0 +1,151 @@ +import { + CODE_NODE_NAME, + EDIT_FIELDS_SET_NODE_NAME, + IF_NODE_NAME, + INSTANCE_OWNER, + SCHEDULE_TRIGGER_NODE_NAME, +} from '../constants'; +import { + WorkflowExecutionsTab, + WorkflowPage as WorkflowPageClass, + WorkflowHistoryPage, +} from '../pages'; + +const workflowPage = new WorkflowPageClass(); +const executionsTab = new WorkflowExecutionsTab(); +const workflowHistoryPage = new WorkflowHistoryPage(); + +const createNewWorkflowAndActivate = () => { + workflowPage.actions.visit(); + workflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME); + workflowPage.actions.saveWorkflowOnButtonClick(); + workflowPage.actions.activateWorkflow(); + cy.get('.el-notification .el-notification--error').should('not.exist'); +}; + +const editWorkflowAndDeactivate = () => { + workflowPage.getters.canvasNodePlusEndpointByName(SCHEDULE_TRIGGER_NODE_NAME).click(); + workflowPage.getters.nodeCreatorSearchBar().should('be.visible'); + workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME, false); + cy.get('.jtk-connector').should('have.length', 1); + workflowPage.actions.saveWorkflowOnButtonClick(); + workflowPage.getters.activatorSwitch().click(); + workflowPage.actions.zoomToFit(); + cy.get('.el-notification .el-notification--error').should('not.exist'); +}; + +const editWorkflowMoreAndActivate = () => { + cy.drag(workflowPage.getters.getEndpointSelector('plus', EDIT_FIELDS_SET_NODE_NAME), [200, 200], { + realMouse: true, + }); + workflowPage.getters.nodeCreatorSearchBar().should('be.visible'); + + workflowPage.actions.addNodeToCanvas(CODE_NODE_NAME, false); + workflowPage.getters.nodeViewBackground().click(600, 200, { force: true }); + cy.get('.jtk-connector').should('have.length', 2); + workflowPage.actions.zoomToFit(); + workflowPage.actions.saveWorkflowOnButtonClick(); + + workflowPage.actions.addNodeToCanvas(IF_NODE_NAME); + workflowPage.getters.nodeViewBackground().click(600, 200, { force: true }); + cy.get('.jtk-connector').should('have.length', 2); + + const position = { + top: 0, + left: 0, + }; + workflowPage.getters + .canvasNodeByName(IF_NODE_NAME) + .click() + .then(($element) => { + position.top = $element.position().top; + position.left = $element.position().left; + }); + + cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 200], { clickToFinish: true }); + workflowPage.getters + .canvasNodes() + .last() + .then(($element) => { + const finalPosition = { + top: $element.position().top, + left: $element.position().left, + }; + + expect(finalPosition.top).to.be.greaterThan(position.top); + expect(finalPosition.left).to.be.greaterThan(position.left); + }); + + cy.draganddrop( + workflowPage.getters.getEndpointSelector('output', CODE_NODE_NAME), + workflowPage.getters.getEndpointSelector('input', IF_NODE_NAME), + ); + cy.get('.jtk-connector').should('have.length', 3); + + workflowPage.actions.saveWorkflowOnButtonClick(); + workflowPage.getters.activatorSwitch().click(); + cy.get('.el-notification .el-notification--error').should('not.exist'); +}; + +describe('Editor actions should work', () => { + beforeEach(() => { + cy.enableFeature('debugInEditor'); + cy.enableFeature('workflowHistory'); + cy.signin({ email: INSTANCE_OWNER.email, password: INSTANCE_OWNER.password }); + createNewWorkflowAndActivate(); + }); + + it('after saving a new workflow', () => { + editWorkflowAndDeactivate(); + editWorkflowMoreAndActivate(); + }); + + it('after switching between Editor and Executions', () => { + cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions'); + cy.intercept('GET', '/rest/executions-current?filter=*').as('getCurrentExecutions'); + + executionsTab.actions.switchToExecutionsTab(); + cy.wait(['@getExecutions', '@getCurrentExecutions']); + cy.wait(500); + executionsTab.actions.switchToEditorTab(); + editWorkflowAndDeactivate(); + editWorkflowMoreAndActivate(); + }); + + it('after switching between Editor and Debug', () => { + cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions'); + cy.intercept('GET', '/rest/executions/*').as('getExecution'); + cy.intercept('GET', '/rest/executions-current?filter=*').as('getCurrentExecutions'); + cy.intercept('POST', '/rest/workflows/run').as('postWorkflowRun'); + + editWorkflowAndDeactivate(); + workflowPage.actions.executeWorkflow(); + cy.wait(['@postWorkflowRun']); + + executionsTab.actions.switchToExecutionsTab(); + cy.wait(['@getExecutions', '@getCurrentExecutions']); + + executionsTab.getters.executionListItems().should('have.length', 1).first().click(); + cy.wait(['@getExecution']); + + executionsTab.getters.executionDebugButton().should('have.text', 'Copy to editor').click(); + editWorkflowMoreAndActivate(); + }); + + it('after switching between Editor and Workflow history', () => { + cy.intercept('GET', '/rest/workflow-history/workflow/*/version/*').as('getVersion'); + cy.intercept('GET', '/rest/workflow-history/workflow/*').as('getHistory'); + + editWorkflowAndDeactivate(); + workflowPage.getters.workflowHistoryButton().click(); + cy.wait(['@getHistory']); + cy.wait(['@getVersion']); + + cy.intercept('GET', '/rest/workflows/*').as('workflowGet'); + workflowHistoryPage.getters.workflowHistoryCloseButton().click(); + cy.wait(['@workflowGet']); + cy.wait(1000); + + editWorkflowMoreAndActivate(); + }); +}); diff --git a/cypress/pages/index.ts b/cypress/pages/index.ts index 18e3649e1a..ebdb0a3ac7 100644 --- a/cypress/pages/index.ts +++ b/cypress/pages/index.ts @@ -10,3 +10,4 @@ export * from './ndv'; export * from './bannerStack'; export * from './workflow-executions-tab'; export * from './signin'; +export * from './workflow-history'; diff --git a/cypress/pages/workflow-history.ts b/cypress/pages/workflow-history.ts new file mode 100644 index 0000000000..18cd6ed999 --- /dev/null +++ b/cypress/pages/workflow-history.ts @@ -0,0 +1,7 @@ +import { BasePage } from "./base"; + +export class WorkflowHistoryPage extends BasePage { + getters = { + workflowHistoryCloseButton: () => cy.getByTestId('workflow-history-close-button'), + } +} diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index 4bcccc7418..09691e163b 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -124,6 +124,7 @@ export class WorkflowPage extends BasePage { addStickyButton: () => cy.getByTestId('add-sticky-button'), stickies: () => cy.getByTestId('sticky'), editorTabButton: () => cy.getByTestId('radio-button-workflow'), + workflowHistoryButton: () => cy.getByTestId('workflow-history-button'), }; actions = { visit: (preventNodeViewUnload = true) => { diff --git a/packages/editor-ui/src/App.vue b/packages/editor-ui/src/App.vue index 35e2170513..187329ab12 100644 --- a/packages/editor-ui/src/App.vue +++ b/packages/editor-ui/src/App.vue @@ -20,9 +20,10 @@
- + +
@@ -257,7 +258,7 @@ export default defineComponent({ void this.postAuthenticate(); } }, - async $route(route) { + async $route() { await this.initSettings(); await this.redirectIfNecessary(); diff --git a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue index 7c414e2fa7..a9c2546ecd 100644 --- a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue +++ b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue @@ -108,6 +108,7 @@ > (); const emit = defineEmits<{ @@ -42,6 +43,12 @@ const workflowVersionPreview = computed(() => { }; }); +const actions = computed(() => + props.isFirstItemShown + ? props.actions.filter((action) => action.value !== 'restore') + : props.actions, +); + const onAction = ({ action, id, @@ -67,11 +74,10 @@ const onAction = ({