Skip to content

Commit

Permalink
chore: merge in master
Browse files Browse the repository at this point in the history
  • Loading branch information
mutdmour committed Feb 10, 2023
2 parents 7bae279 + 136b74d commit 64bcb84
Show file tree
Hide file tree
Showing 144 changed files with 9,121 additions and 2,031 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:

- uses: pnpm/[email protected]
with:
version: 7.18.1
version: 7.27.0

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
## [0.214.3](https://github.com/n8n-io/n8n/compare/[email protected]@0.214.3) (2023-02-09)

* **editor:** Prevent creation of input connections for nodes without input slot ([#5425](https://github.com/n8n-io/n8n/issues/5425)) ([b57ec1d](https://github.com/n8n-io/n8n/commit/b57ec1d6abbae9e23ae5f473d70674aa14701bce))


## [0.214.2](https://github.com/n8n-io/n8n/compare/[email protected]@0.214.2) (2023-02-06)


### Bug Fixes


* **editor:** Correctly show OAuth reconnect button ([#5384](https://github.com/n8n-io/n8n/issues/5384)) ([6482688](https://github.com/n8n-io/n8n/commit/6482688ee04621744451c67f6d6e3292e925bb8d))
* **editor:** Fix resolvable highlighting for HTML editor ([#5379](https://github.com/n8n-io/n8n/issues/5379)) ([31130d5](https://github.com/n8n-io/n8n/commit/31130d5257f253d9be21fe62d668231e27ecbd52))



## [0.214.1](https://github.com/n8n-io/n8n/compare/[email protected]@0.214.1) (2023-02-06)


Expand Down
4 changes: 4 additions & 0 deletions cypress/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ export const DEFAULT_USER_EMAIL = '[email protected]';
export const DEFAULT_USER_PASSWORD = 'CypressTest123';

export const MANUAL_TRIGGER_NODE_NAME = 'Manual Trigger';
export const MANUAL_TRIGGER_NODE_DISPLAY_NAME = 'When clicking "Execute Workflow"';
export const SCHEDULE_TRIGGER_NODE_NAME = 'Schedule Trigger';
export const CODE_NODE_NAME = 'Code';
export const SET_NODE_NAME = 'Set';
export const IF_NODE_NAME = 'IF';
export const MERGE_NODE_NAME = 'Merge';
export const SWITCH_NODE_NAME = 'Switch';
export const GMAIL_NODE_NAME = 'Gmail';
export const TRELLO_NODE_NAME = 'Trello';
export const NOTION_NODE_NAME = 'Notion';
Expand Down
119 changes: 118 additions & 1 deletion cypress/e2e/12-canvas.cy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import {
MANUAL_TRIGGER_NODE_NAME,
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
CODE_NODE_NAME,
SCHEDULE_TRIGGER_NODE_NAME,
SET_NODE_NAME,
SWITCH_NODE_NAME,
IF_NODE_NAME,
MERGE_NODE_NAME,
HTTP_REQUEST_NODE_NAME,
} from './../constants';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
Expand Down Expand Up @@ -33,12 +37,125 @@ describe('Canvas Actions', () => {
WorkflowPage.getters.executeWorkflowButton().should('be.visible');
});

it('should connect and disconnect a simple node', () => {
WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME);
WorkflowPage.getters.nodeViewBackground().click(600, 200, { force: true });
cy.get('.jtk-connector').should('have.length', 1);
WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME);

// Change connection from Set to Set1
cy.draganddrop(
WorkflowPage.getters.getEndpointSelector('input', SET_NODE_NAME),
WorkflowPage.getters.getEndpointSelector('input', `${SET_NODE_NAME}1`)
)

WorkflowPage.getters.canvasNodeInputEndpointByName(`${SET_NODE_NAME}1`).should('have.class', 'jtk-endpoint-connected');

cy.get('.jtk-connector').should('have.length', 1);
// Disconnect Set1
cy.drag(WorkflowPage.getters.getEndpointSelector('input', `${SET_NODE_NAME}1`), [-200, 100])
cy.get('.jtk-connector').should('have.length', 0);
});

it('should add first step', () => {
WorkflowPage.getters.canvasPlusButton().should('be.visible');
WorkflowPage.actions.addInitialNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
WorkflowPage.getters.canvasNodes().should('have.length', 1);
});

it('should add a node via plus endpoint drag', () => {
WorkflowPage.getters.canvasPlusButton().should('be.visible');
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME, true);

cy.drag(WorkflowPage.getters.getEndpointSelector('plus', SCHEDULE_TRIGGER_NODE_NAME), [100, 100])

WorkflowPage.getters.nodeCreatorSearchBar().should('be.visible');
WorkflowPage.actions.addNodeToCanvas(IF_NODE_NAME, false);
WorkflowPage.getters.nodeViewBackground().click({ force: true });
});

it('should add switch node and test connections', () => {
WorkflowPage.actions.addNodeToCanvas(SWITCH_NODE_NAME, true);

// Switch has 4 output endpoints
for (let i = 0; i < 4; i++) {
WorkflowPage.getters.canvasNodePlusEndpointByName(SWITCH_NODE_NAME, i).click({ force: true })
WorkflowPage.getters.nodeCreatorSearchBar().should('be.visible');
WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME, false);
WorkflowPage.actions.zoomToFit();
}
WorkflowPage.actions.saveWorkflowOnButtonClick();
cy.reload()
cy.waitForLoad();
// Make sure all connections are there after reload
for (let i = 0; i < 4; i++) {
const setName = `${SET_NODE_NAME}${i > 0 ? i : ''}`;
WorkflowPage.getters.canvasNodeInputEndpointByName(setName).should('have.class', 'jtk-endpoint-connected');
}
});

it('should add merge node and test connections', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
for (let i = 0; i < 2; i++) {
WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME, true);
WorkflowPage.getters.nodeViewBackground().click(600 + i * 100, 200, { force: true });
}
WorkflowPage.actions.zoomToFit();

WorkflowPage.actions.addNodeToCanvas(MERGE_NODE_NAME);
WorkflowPage.actions.zoomToFit();

// Connect manual to Set1
cy.draganddrop(
WorkflowPage.getters.getEndpointSelector('output', MANUAL_TRIGGER_NODE_DISPLAY_NAME),
WorkflowPage.getters.getEndpointSelector('input', `${SET_NODE_NAME}1`)
)

cy.get('.rect-input-endpoint.jtk-endpoint-connected').should('have.length', 2);

// Connect Set1 and Set2 to merge
cy.draganddrop(
WorkflowPage.getters.getEndpointSelector('plus', SET_NODE_NAME),
WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 0)
)
cy.draganddrop(
WorkflowPage.getters.getEndpointSelector('plus', `${SET_NODE_NAME}1`),
WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 1)
)

cy.get('.rect-input-endpoint.jtk-endpoint-connected').should('have.length', 4);

// Make sure all connections are there after save & reload
WorkflowPage.actions.saveWorkflowOnButtonClick();
cy.reload()
cy.waitForLoad();

cy.get('.rect-input-endpoint.jtk-endpoint-connected').should('have.length', 4);
WorkflowPage.actions.executeWorkflow();
// If the merged set nodes are connected and executed correctly, there should be 2 items in the output of merge node
cy.get('[data-label="2 items"]').should('be.visible');
});

it('should add nodes and check execution success', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
for (let i = 0; i < 3; i++) {
WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME, true);
}
WorkflowPage.actions.zoomToFit();
WorkflowPage.actions.executeWorkflow();

cy.get('.jtk-connector.success').should('have.length', 3);
cy.get('.data-count').should('have.length', 4);
cy.get('.plus-draggable-endpoint').should('have.class', 'ep-success');

WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME);
WorkflowPage.actions.zoomToFit();

cy.get('.plus-draggable-endpoint').filter(':visible').should('not.have.class', 'ep-success');
cy.get('.jtk-connector.success').should('have.length', 3);
cy.get('.jtk-connector').should('have.length', 4);
})

it('should add a connected node using plus endpoint', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
cy.get('.plus-endpoint').should('be.visible').click();
Expand Down Expand Up @@ -226,7 +343,7 @@ describe('Canvas Actions', () => {
it('should delete a connection by moving it away from endpoint', () => {
WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
cy.drag('.rect-input-endpoint.jtk-endpoint-connected', [0, -100]);
cy.drag(WorkflowPage.getters.getEndpointSelector('input', CODE_NODE_NAME), [0, -100]);
WorkflowPage.getters.nodeConnections().should('have.length', 0);
});

Expand Down
113 changes: 113 additions & 0 deletions cypress/e2e/14-data-transformation-expressions.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { WorkflowPage, NDV } from '../pages';

const wf = new WorkflowPage();
const ndv = new NDV();

describe('Data transformation expressions', () => {
beforeEach(() => {
cy.resetAll();
cy.skipSetup();
wf.actions.visit();
cy.waitForLoad();

cy.window()
// @ts-ignore
.then(win => win.onBeforeUnload && win.removeEventListener('beforeunload', win.onBeforeUnload));
});

it('$json + native string methods', () => {
wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true });
ndv.actions.setPinnedData([{ myStr: 'Monday' }]);
ndv.actions.close();
addSet();

const input = '{{$json.myStr.toLowerCase() + " is " + "today".toUpperCase()';
const output = 'monday is TODAY';

ndv.getters.inlineExpressionEditorInput().clear().type(input);
ndv.actions.execute();
ndv.getters.outputDataContainer().should('be.visible').contains(output);
});

it('$json + n8n string methods', () => {
wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true });
ndv.actions.setPinnedData([{ myStr: '[email protected] is an email' }]);
ndv.actions.close();
addSet();

const input = '{{$json.myStr.extractEmail() + " " + $json.myStr.isEmpty()';
const output = '[email protected] false';

ndv.getters.inlineExpressionEditorInput().clear().type(input);
ndv.actions.execute();
ndv.getters.outputDataContainer().should('be.visible').contains(output);
});

it('$json + native numeric methods', () => {
wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true });
ndv.actions.setPinnedData([{ myNum: 9.123 }]);
ndv.actions.close();
addSet();

const input = '{{$json.myNum.toPrecision(3)';
const output = '9.12';

ndv.getters.inlineExpressionEditorInput().clear().type(input);
ndv.actions.execute();
ndv.getters.outputDataContainer().should('be.visible').contains(output);
});

it('$json + n8n numeric methods', () => {
wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true });
ndv.actions.setPinnedData([{ myStr: '[email protected] is an email' }]);
ndv.actions.close();
addSet();

const input = '{{$json.myStr.extractEmail() + " " + $json.myStr.isEmpty()';
const output = '[email protected] false';

ndv.getters.inlineExpressionEditorInput().clear().type(input);
ndv.actions.execute();
ndv.getters.outputDataContainer().should('be.visible').contains(output);
});

it('$json + native array methods', () => {
wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true });
ndv.actions.setPinnedData([{ myArr: [1, 2, 3] }]);
ndv.actions.close();
addSet();

const input = '{{$json.myArr.includes(1) + " " + $json.myArr.at(2)';
const output = 'true 3';

ndv.getters.inlineExpressionEditorInput().clear().type(input);
ndv.actions.execute();
ndv.getters.outputDataContainer().should('be.visible').contains(output);
});

it('$json + n8n array methods', () => {
wf.actions.addInitialNodeToCanvas('Schedule Trigger', { keepNdvOpen: true });
ndv.actions.setPinnedData([{ myArr: [1, 2, 3] }]);
ndv.actions.close();
addSet();

const input = '{{$json.myArr.first() + " " + $json.myArr.last()';
const output = '1 3';

ndv.getters.inlineExpressionEditorInput().clear().type(input);
ndv.actions.execute();
ndv.getters.outputDataContainer().should('be.visible').contains(output);
});
});

// ----------------------------------
// utils
// ----------------------------------

const addSet = () => {
wf.actions.addNodeToCanvas('Set', true, true);
ndv.getters.parameterInput('keepOnlySet').find('div[role=switch]').click(); // shorten output
cy.get('input[placeholder="Add Value"]').click();
cy.get('span').contains('String').click();
ndv.getters.nthParam(3).contains('Expression').invoke('show').click(); // Values to Set > String > Value
};
Loading

0 comments on commit 64bcb84

Please sign in to comment.