diff --git a/cypress/e2e/11-inline-expression-editor.cy.ts b/cypress/e2e/11-inline-expression-editor.cy.ts index de5594a4f4..88fea311d9 100644 --- a/cypress/e2e/11-inline-expression-editor.cy.ts +++ b/cypress/e2e/11-inline-expression-editor.cy.ts @@ -69,6 +69,6 @@ describe('Inline expression editor', () => { WorkflowPage.getters.inlineExpressionEditorInput().clear(); WorkflowPage.getters.inlineExpressionEditorInput().type('{{'); WorkflowPage.getters.inlineExpressionEditorInput().type('$parameter["operation"]'); - WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^getAll$/); + WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^get$/); }); }); diff --git a/cypress/e2e/13-pinning.cy.ts b/cypress/e2e/13-pinning.cy.ts index 6f1c328fd9..c278231017 100644 --- a/cypress/e2e/13-pinning.cy.ts +++ b/cypress/e2e/13-pinning.cy.ts @@ -1,6 +1,6 @@ import { HTTP_REQUEST_NODE_NAME, - MANUAL_TRIGGER_NODE_DISPLAY_NAME, + MANUAL_TRIGGER_NODE_NAME, PIPEDRIVE_NODE_NAME, SET_NODE_NAME, } from '../constants'; @@ -75,7 +75,7 @@ describe('Data pinning', () => { }); it('Should be able to reference paired items in a node located before pinned data', () => { - workflowPage.actions.addInitialNodeToCanvas(MANUAL_TRIGGER_NODE_DISPLAY_NAME); + workflowPage.actions.addInitialNodeToCanvas(MANUAL_TRIGGER_NODE_NAME); workflowPage.actions.addNodeToCanvas(HTTP_REQUEST_NODE_NAME, true, true); ndv.actions.setPinnedData([{ http: 123 }]); ndv.actions.close(); diff --git a/cypress/e2e/4-node-creator.cy.ts b/cypress/e2e/4-node-creator.cy.ts index 0057afd93c..0ad0306cb6 100644 --- a/cypress/e2e/4-node-creator.cy.ts +++ b/cypress/e2e/4-node-creator.cy.ts @@ -58,8 +58,8 @@ describe('Node Creator', () => { nodeCreatorFeature.getters.getCreatorItem('On app event').click(); nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image'); - nodeCreatorFeature.getters.getCreatorItem('Results in other categories (1)').should('exist'); - nodeCreatorFeature.getters.creatorItem().should('have.length', 2); + nodeCreatorFeature.getters.getCategoryItem('Results in other categories').should('exist'); + nodeCreatorFeature.getters.creatorItem().should('have.length', 1); nodeCreatorFeature.getters.getCreatorItem('Edit Image').should('exist'); nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image123123'); nodeCreatorFeature.getters.creatorItem().should('have.length', 0); @@ -101,7 +101,7 @@ describe('Node Creator', () => { nodeCreatorFeature.getters.activeSubcategory().should('have.text', 'FTP'); nodeCreatorFeature.getters.searchBar().find('input').clear().type('file'); // Navigate to rename action which should be the 4th item - nodeCreatorFeature.getters.searchBar().find('input').type('{downarrow} {downarrow} {downarrow} {rightarrow}'); + nodeCreatorFeature.getters.searchBar().find('input').type('{uparrow}{uparrow}{rightarrow}'); NDVModal.getters.parameterInput('operation').should('contain.text', 'Rename'); }) @@ -127,9 +127,107 @@ describe('Node Creator', () => { }) nodeCreatorFeature.getters.searchBar().find('input').clear().type(doubleActionNode); nodeCreatorFeature.getters.getCreatorItem(doubleActionNode).click(); - nodeCreatorFeature.getters.creatorItem().should('have.length', 2); + nodeCreatorFeature.getters.creatorItem().should('have.length', 4); }) + it('should have "Actions" section collapsed when opening actions view from Trigger root view', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('ActiveCampaign'); + nodeCreatorFeature.getters.getCreatorItem('ActiveCampaign').click(); + nodeCreatorFeature.getters.getCategoryItem('Actions').should('exist'); + nodeCreatorFeature.getters.getCategoryItem('Triggers').should('exist'); + + nodeCreatorFeature.getters.getCategoryItem('Triggers').parent().should('not.have.attr', 'data-category-collapsed'); + nodeCreatorFeature.getters.getCategoryItem('Actions').parent().should('have.attr', 'data-category-collapsed', 'true'); + nodeCreatorFeature.getters.getCategoryItem('Actions').click() + nodeCreatorFeature.getters.getCategoryItem('Actions').parent().should('not.have.attr', 'data-category-collapsed'); + }); + + it('should have "Triggers" section collapsed when opening actions view from Regular root view', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.getCreatorItem('Manually').click(); + + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n'); + nodeCreatorFeature.getters.getCreatorItem('n8n').click(); + + nodeCreatorFeature.getters.getCategoryItem('Actions').parent().should('not.have.attr', 'data-category-collapsed'); + nodeCreatorFeature.getters.getCategoryItem('Actions').click() + nodeCreatorFeature.getters.getCategoryItem('Actions').parent().should('have.attr', 'data-category-collapsed'); + nodeCreatorFeature.getters.getCategoryItem('Triggers').parent().should('have.attr', 'data-category-collapsed'); + nodeCreatorFeature.getters.getCategoryItem('Triggers').click() + nodeCreatorFeature.getters.getCategoryItem('Triggers').parent().should('not.have.attr', 'data-category-collapsed'); + }); + + it('should show callout and two suggested nodes if node has no trigger actions', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('Customer Datastore (n8n training)'); + nodeCreatorFeature.getters.getCreatorItem('Customer Datastore (n8n training)').click(); + + cy.getByTestId('actions-panel-no-triggers-callout').should('be.visible'); + nodeCreatorFeature.getters.getCreatorItem('On a Schedule').should('be.visible'); + nodeCreatorFeature.getters.getCreatorItem('On a Webhook call').should('be.visible'); + }); + + it('should show intro callout if user has not made a production execution', () => { + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('Customer Datastore (n8n training)'); + nodeCreatorFeature.getters.getCreatorItem('Customer Datastore (n8n training)').click(); + + cy.getByTestId('actions-panel-activation-callout').should('be.visible'); + nodeCreatorFeature.getters.activeSubcategory().find('button').click(); + nodeCreatorFeature.getters.searchBar().find('input').clear() + + nodeCreatorFeature.getters.getCreatorItem('On a schedule').click(); + + // Setup 1s interval execution + cy.getByTestId('parameter-input-field').click(); + cy.getByTestId('parameter-input-field') + .find('.el-select-dropdown') + .find('.option-headline') + .contains('Seconds') + .click(); + cy.getByTestId('parameter-input-secondsInterval').clear().type('1'); + + NDVModal.actions.close(); + + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('Customer Datastore (n8n training)'); + nodeCreatorFeature.getters.getCreatorItem('Customer Datastore (n8n training)').click(); + nodeCreatorFeature.getters.getCreatorItem('Get All People').click(); + NDVModal.actions.close(); + + WorkflowPage.actions.saveWorkflowOnButtonClick(); + WorkflowPage.actions.activateWorkflow(); + WorkflowPage.getters.activatorSwitch().should('have.class', 'is-checked'); + + // Wait for schedule 1s execution to mark user as having made a production execution + cy.wait(1500); + cy.reload() + + // Action callout should not be visible after user has made a production execution + nodeCreatorFeature.actions.openNodeCreator(); + nodeCreatorFeature.getters.searchBar().find('input').clear().type('Customer Datastore (n8n training)'); + nodeCreatorFeature.getters.getCreatorItem('Customer Datastore (n8n training)').click(); + + cy.getByTestId('actions-panel-activation-callout').should('not.exist'); + }); + + it('should show Trigger and Actions sections during search', () => { + nodeCreatorFeature.actions.openNodeCreator(); + + nodeCreatorFeature.getters.searchBar().find('input').clear().type('Customer Datastore (n8n training)'); + nodeCreatorFeature.getters.getCreatorItem('Customer Datastore (n8n training)').click(); + + nodeCreatorFeature.getters.searchBar().find('input').clear().type('Non existent action name'); + + nodeCreatorFeature.getters.getCategoryItem('Triggers').should('be.visible'); + nodeCreatorFeature.getters.getCategoryItem('Actions').should('be.visible'); + cy.getByTestId('actions-panel-no-triggers-callout').should('be.visible'); + nodeCreatorFeature.getters.getCreatorItem('On a Schedule').should('be.visible'); + nodeCreatorFeature.getters.getCreatorItem('On a Webhook call').should('be.visible'); + }); + describe('should correctly append manual trigger for regular actions', () => { // For these sources, manual node should be added const sourcesWithAppend = [ @@ -152,6 +250,7 @@ describe('Node Creator', () => { source.handler() nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n'); nodeCreatorFeature.getters.getCreatorItem('n8n').click(); + nodeCreatorFeature.getters.getCategoryItem('Actions').click(); nodeCreatorFeature.getters.getCreatorItem('Create a credential').click(); NDVModal.actions.close(); WorkflowPage.getters.canvasNodes().should('have.length', 2); @@ -162,12 +261,14 @@ describe('Node Creator', () => { nodeCreatorFeature.getters.canvasAddButton().click(); nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n'); nodeCreatorFeature.getters.getCreatorItem('n8n').click(); + nodeCreatorFeature.getters.getCategoryItem('Actions').click(); nodeCreatorFeature.getters.getCreatorItem('Create a credential').click(); NDVModal.actions.close(); WorkflowPage.actions.deleteNode('When clicking "Execute Workflow"') WorkflowPage.getters.canvasNodePlusEndpointByName('n8n').click() nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n'); nodeCreatorFeature.getters.getCreatorItem('n8n').click(); + nodeCreatorFeature.getters.getCategoryItem('Actions').click(); nodeCreatorFeature.getters.getCreatorItem('Create a credential').click(); NDVModal.actions.close(); WorkflowPage.getters.canvasNodes().should('have.length', 2); diff --git a/cypress/e2e/9-expression-editor-modal.cy.ts b/cypress/e2e/9-expression-editor-modal.cy.ts index 957c0505f5..dd4e01128b 100644 --- a/cypress/e2e/9-expression-editor-modal.cy.ts +++ b/cypress/e2e/9-expression-editor-modal.cy.ts @@ -60,6 +60,6 @@ describe('Expression editor modal', () => { it('should resolve $parameter[]', () => { WorkflowPage.getters.expressionModalInput().clear(); WorkflowPage.getters.expressionModalInput().type('{{ $parameter["operation"]'); - WorkflowPage.getters.expressionModalOutput().contains(/^getAll$/); + WorkflowPage.getters.expressionModalOutput().contains(/^get$/); }); }); diff --git a/cypress/pages/features/node-creator.ts b/cypress/pages/features/node-creator.ts index 8ebe6db702..6686de25ff 100644 --- a/cypress/pages/features/node-creator.ts +++ b/cypress/pages/features/node-creator.ts @@ -7,6 +7,7 @@ export class NodeCreator extends BasePage { plusButton: () => cy.getByTestId('node-creator-plus-button'), canvasAddButton: () => cy.getByTestId('canvas-add-button'), searchBar: () => cy.getByTestId('search-bar'), + getCategoryItem: (label: string) => cy.get(`[data-keyboard-nav-id="${label}"]`), getCreatorItem: (label: string) => this.getters.creatorItem().contains(label).parents('[data-test-id="item-iterator-item"]'), getNthCreatorItem: (n: number) => this.getters.creatorItem().eq(n), @@ -15,10 +16,11 @@ export class NodeCreator extends BasePage { selectedTab: () => this.getters.nodeCreatorTabs().find('.is-active'), categorizedItems: () => cy.getByTestId('categorized-items'), creatorItem: () => cy.getByTestId('item-iterator-item'), + categoryItem: () => cy.getByTestId('node-creator-category-item'), communityNodeTooltip: () => cy.getByTestId('node-item-community-tooltip'), - noResults: () => cy.getByTestId('categorized-no-results'), + noResults: () => cy.getByTestId('node-creator-no-results'), nodeItemName: () => cy.getByTestId('node-creator-item-name'), - activeSubcategory: () => cy.getByTestId('categorized-items-subcategory'), + activeSubcategory: () => cy.getByTestId('nodes-list-header'), expandedCategories: () => this.getters.creatorItem().find('>div').filter('.active').invoke('text'), }; diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index d42b2850c4..8b6d195105 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -140,7 +140,8 @@ export class WorkflowPage extends BasePage { if(action) { cy.contains(action).click() } else { - cy.getByTestId('item-iterator-item').eq(1).click() + // Select the first action + cy.get('[data-keyboard-nav-type="action"]').eq(0).click() } } }) diff --git a/packages/design-system/src/components/N8nCallout/Callout.vue b/packages/design-system/src/components/N8nCallout/Callout.vue index 97c15296e0..604cec6a25 100644 --- a/packages/design-system/src/components/N8nCallout/Callout.vue +++ b/packages/design-system/src/components/N8nCallout/Callout.vue @@ -1,7 +1,7 @@