Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update e2e tests to run on new canvas (no-changelog) #12784

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .github/workflows/e2e-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ on:
description: 'PR number to run tests for.'
required: false
type: number
node_view_version:
description: 'Node View version to run tests with.'
required: false
default: '1'
type: string
secrets:
CYPRESS_RECORD_KEY:
description: 'Cypress record key.'
Expand Down Expand Up @@ -165,7 +160,7 @@ jobs:
spec: '${{ inputs.spec }}'
env:
NODE_OPTIONS: --dns-result-order=ipv4first
CYPRESS_NODE_VIEW_VERSION: ${{ inputs.node_view_version }}
CYPRESS_NODE_VIEW_VERSION: 2
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
E2E_TESTS: true
Expand Down
81 changes: 81 additions & 0 deletions cypress/composables/webhooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { BACKEND_BASE_URL } from '../constants';
import { NDV, WorkflowPage } from '../pages';
import { getVisibleSelect } from '../utils';

export const waitForWebhook = 500;

export interface SimpleWebhookCallOptions {
method: string;
webhookPath: string;
responseCode?: number;
respondWith?: string;
executeNow?: boolean;
responseData?: string;
authentication?: string;
}

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

export const simpleWebhookCall = (options: SimpleWebhookCallOptions) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted out of webhooks tests. The tests were running multiple times due to importing.

const {
authentication,
method,
webhookPath,
responseCode,
respondWith,
responseData,
executeNow = true,
} = options;

workflowPage.actions.addInitialNodeToCanvas('Webhook');
workflowPage.actions.openNode('Webhook');

cy.getByTestId('parameter-input-httpMethod').click();
getVisibleSelect().find('.option-headline').contains(method).click();
cy.getByTestId('parameter-input-path')
.find('.parameter-input')
.find('input')
.clear()
.type(webhookPath);

if (authentication) {
cy.getByTestId('parameter-input-authentication').click();
getVisibleSelect().find('.option-headline').contains(authentication).click();
}

if (responseCode) {
cy.get('.param-options').click();
getVisibleSelect().contains('Response Code').click();
cy.get('.parameter-item-wrapper > .parameter-input-list-wrapper').children().click();
getVisibleSelect().contains('201').click();
}

if (respondWith) {
cy.getByTestId('parameter-input-responseMode').click();
getVisibleSelect().find('.option-headline').contains(respondWith).click();
}

if (responseData) {
cy.getByTestId('parameter-input-responseData').click();
getVisibleSelect().find('.option-headline').contains(responseData).click();
}

const callEndpoint = (fn: (response: Cypress.Response<unknown>) => void) => {
cy.request(method, `${BACKEND_BASE_URL}/webhook-test/${webhookPath}`).then(fn);
};

if (executeNow) {
ndv.actions.execute();
cy.wait(waitForWebhook);

callEndpoint((response) => {
expect(response.status).to.eq(200);
ndv.getters.outputPanel().contains('headers');
});
}

return {
callEndpoint,
};
};
173 changes: 1 addition & 172 deletions cypress/e2e/10-undo-redo.cy.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import {
SCHEDULE_TRIGGER_NODE_NAME,
CODE_NODE_NAME,
SET_NODE_NAME,
EDIT_FIELDS_SET_NODE_NAME,
} from '../constants';
import { SCHEDULE_TRIGGER_NODE_NAME, CODE_NODE_NAME, SET_NODE_NAME } from '../constants';
import { MessageBox as MessageBoxClass } from '../pages/modals/message-box';
import { NDV } from '../pages/ndv';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';

// Suite-specific constants
const CODE_NODE_NEW_NAME = 'Something else';

const WorkflowPage = new WorkflowPageClass();
const messageBox = new MessageBoxClass();
const ndv = new NDV();
Expand All @@ -20,40 +12,6 @@ describe('Undo/Redo', () => {
WorkflowPage.actions.visit();
});

// FIXME: Canvas V2: Fix redo connections
it('should undo/redo adding node in the middle', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.actions.addNodeBetweenNodes(
SCHEDULE_TRIGGER_NODE_NAME,
CODE_NODE_NAME,
SET_NODE_NAME,
);
WorkflowPage.actions.zoomToFit();
WorkflowPage.getters.canvasNodeByName('Code').then(($codeNode) => {
const cssLeft = parseInt($codeNode.css('left'));
const cssTop = parseInt($codeNode.css('top'));

WorkflowPage.actions.hitUndo();
WorkflowPage.getters.canvasNodes().should('have.have.length', 2);
WorkflowPage.getters.nodeConnections().should('have.length', 1);
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.canvasNodes().should('have.have.length', 1);
WorkflowPage.getters.nodeConnections().should('have.length', 0);
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodes().should('have.have.length', 2);
WorkflowPage.getters.nodeConnections().should('have.length', 1);
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodes().should('have.have.length', 3);
WorkflowPage.getters.nodeConnections().should('have.length', 2);
// Last node should be added back to original position
WorkflowPage.getters
.canvasNodeByName('Code')
.should('have.css', 'left', cssLeft + 'px')
.should('have.css', 'top', cssTop + 'px');
});
});

it('should undo/redo deleting node using context menu', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
Expand Down Expand Up @@ -115,36 +73,6 @@ describe('Undo/Redo', () => {
WorkflowPage.getters.nodeConnections().should('have.length', 0);
});

// FIXME: Canvas V2: Fix moving of nodes via e2e tests
it('should undo/redo moving nodes', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters.canvasNodeByName(CODE_NODE_NAME).then(($node) => {
const initialPosition = $node.position();
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 150], { clickToFinish: true });

WorkflowPage.getters.canvasNodeByName(CODE_NODE_NAME).then(($node) => {
const cssLeft = parseInt($node.css('left'));
const cssTop = parseInt($node.css('top'));
expect(cssLeft).to.be.greaterThan(initialPosition.left);
expect(cssTop).to.be.greaterThan(initialPosition.top);
});

WorkflowPage.actions.hitUndo();
WorkflowPage.getters
.canvasNodeByName(CODE_NODE_NAME)
.should('have.css', 'left', `${initialPosition.left}px`)
.should('have.css', 'top', `${initialPosition.top}px`);
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodeByName(CODE_NODE_NAME).then(($node) => {
const cssLeft = parseInt($node.css('left'));
const cssTop = parseInt($node.css('top'));
expect(cssLeft).to.be.greaterThan(initialPosition.left);
expect(cssTop).to.be.greaterThan(initialPosition.top);
});
});
});

it('should undo/redo deleting a connection using context menu', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
Expand All @@ -155,17 +83,6 @@ describe('Undo/Redo', () => {
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.nodeConnections().should('have.length', 0);
});
// FIXME: Canvas V2: Fix disconnecting by moving
it('should undo/redo deleting a connection by moving it away', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
cy.drag('.rect-input-endpoint.jtk-endpoint-connected', [0, -100]);
WorkflowPage.getters.nodeConnections().should('have.length', 0);
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.nodeConnections().should('have.length', 1);
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.nodeConnections().should('have.length', 0);
});

it('should undo/redo disabling a node using context menu', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
Expand Down Expand Up @@ -204,23 +121,6 @@ describe('Undo/Redo', () => {
WorkflowPage.getters.disabledNodes().should('have.length', 2);
});

// FIXME: Canvas V2: Fix undo renaming node
it('should undo/redo renaming node using keyboard shortcut', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters.canvasNodes().last().click();
cy.get('body').trigger('keydown', { key: 'F2' });
cy.get('.rename-prompt').should('be.visible');
cy.get('body').type(CODE_NODE_NEW_NAME);
cy.get('body').type('{enter}');
WorkflowPage.actions.hitUndo();
cy.get('body').type('{esc}');
WorkflowPage.getters.canvasNodeByName(CODE_NODE_NAME).should('exist');
WorkflowPage.actions.hitRedo();
cy.get('body').type('{esc}');
WorkflowPage.getters.canvasNodeByName(CODE_NODE_NEW_NAME).should('exist');
});

it('should undo/redo duplicating a node', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
Expand All @@ -243,77 +143,6 @@ describe('Undo/Redo', () => {
});
});

// FIXME: Canvas V2: Figure out why moving doesn't work from e2e
it('should undo/redo multiple steps', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
// WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.actions.zoomToFit();

// Disable last node
WorkflowPage.getters.canvasNodes().last().click();
WorkflowPage.actions.hitDisableNodeShortcut();

// Move first one
WorkflowPage.actions
.getNodePosition(WorkflowPage.getters.canvasNodes().first())
.then((initialPosition) => {
WorkflowPage.getters.canvasNodes().first().click();
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 150], {
clickToFinish: true,
});
WorkflowPage.getters
.canvasNodes()
.first()
.then(($node) => {
const cssLeft = parseInt($node.css('left'));
const cssTop = parseInt($node.css('top'));
expect(cssLeft).to.be.greaterThan(initialPosition.left);
expect(cssTop).to.be.greaterThan(initialPosition.top);
});

// Delete the set node
WorkflowPage.getters.canvasNodeByName(EDIT_FIELDS_SET_NODE_NAME).click().click();
cy.get('body').type('{backspace}');

// First undo: Should return deleted node
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.canvasNodes().should('have.length', 4);
WorkflowPage.getters.nodeConnections().should('have.length', 3);
// Second undo: Should move first node to it's original position
WorkflowPage.actions.hitUndo();
WorkflowPage.getters
.canvasNodes()
.first()
.should('have.css', 'left', `${initialPosition.left}px`)
.should('have.css', 'top', `${initialPosition.top}px`);
// Third undo: Should enable last node
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.disabledNodes().should('have.length', 0);

// First redo: Should disable last node
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.disabledNodes().should('have.length', 1);
// Second redo: Should move the first node
WorkflowPage.actions.hitRedo();
WorkflowPage.getters
.canvasNodes()
.first()
.then(($node) => {
const cssLeft = parseInt($node.css('left'));
const cssTop = parseInt($node.css('top'));
expect(cssLeft).to.be.greaterThan(initialPosition.left);
expect(cssTop).to.be.greaterThan(initialPosition.top);
});
// Third redo: Should delete the Set node
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodes().should('have.length', 3);
WorkflowPage.getters.nodeConnections().should('have.length', 2);
});
});

it('should be able to copy and paste pinned data nodes in workflows with dynamic Switch node', () => {
cy.fixture('Test_workflow_form_switch.json').then((data) => {
cy.get('body').paste(JSON.stringify(data));
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/11-inline-expression-editor.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ describe('Inline expression editor', () => {

// Run workflow
ndv.actions.close();
WorkflowPage.actions.executeNode('No Operation', { anchor: 'topLeft' });
WorkflowPage.actions.executeNode('No Operation, do nothing', { anchor: 'topLeft' });
WorkflowPage.actions.openNode('Hacker News');
WorkflowPage.actions.openInlineExpressionEditor();

Expand Down
Loading
Loading