refactor: Format root-level dirs (no-changelog) (#4938)

🎨 Format root-level dirs
This commit is contained in:
Iván Ovejero
2022-12-15 16:39:59 +01:00
committed by GitHub
parent d7b3d649d6
commit 3028ad3c61
32 changed files with 612 additions and 513 deletions

View File

@@ -5,5 +5,5 @@ export const DEFAULT_USER_PASSWORD = 'CypressTest123';
export const MANUAL_TRIGGER_NODE_NAME = 'Manual Trigger';
export const SCHEDULE_TRIGGER_NODE_NAME = 'Schedule Trigger';
export const CODE_NODE_NAME = 'Code'
export const SET_NODE_NAME = 'Set'
export const CODE_NODE_NAME = 'Code';
export const SET_NODE_NAME = 'Set';

View File

@@ -1,5 +1,5 @@
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from "../constants";
import { randFirstName, randLastName } from "@ngneat/falso";
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants';
import { randFirstName, randLastName } from '@ngneat/falso';
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import { v4 as uuid } from 'uuid';
@@ -22,7 +22,7 @@ describe('Workflows', () => {
expect(err.message).to.include('Not logged in');
return false;
})
});
cy.signin({ email, password });
cy.visit(WorkflowsPage.url);
@@ -36,7 +36,7 @@ describe('Workflows', () => {
WorkflowPage.getters.workflowTags().should('contain.text', 'some-tag-1');
WorkflowPage.getters.workflowTags().should('contain.text', 'some-tag-2');
})
});
it('should create a new workflow using add workflow button', () => {
WorkflowsPage.getters.newWorkflowButtonCard().should('not.exist');
@@ -46,24 +46,28 @@ describe('Workflows', () => {
WorkflowPage.getters.workflowTags().should('contain.text', 'other-tag-1');
WorkflowPage.getters.workflowTags().should('contain.text', 'other-tag-2');
})
});
it('should search for a workflow', () => {
WorkflowsPage.getters.searchBar().type('Empty State Card Workflow');
WorkflowsPage.getters.workflowCards().should('have.length', 1);
WorkflowsPage.getters.workflowCard('Empty State Card Workflow').should('contain.text', 'Empty State Card Workflow');
WorkflowsPage.getters
.workflowCard('Empty State Card Workflow')
.should('contain.text', 'Empty State Card Workflow');
WorkflowsPage.getters.searchBar().clear().type('Add Workflow Button Workflow');
WorkflowsPage.getters.workflowCards().should('have.length', 1);
WorkflowsPage.getters.workflowCard('Add Workflow Button Workflow').should('contain.text', 'Add Workflow Button Workflow');
WorkflowsPage.getters
.workflowCard('Add Workflow Button Workflow')
.should('contain.text', 'Add Workflow Button Workflow');
WorkflowsPage.getters.searchBar().clear().type('Some non-existent workflow');
WorkflowsPage.getters.workflowCards().should('not.exist');
cy.contains('No workflows found').should('be.visible');
})
});
it('should delete all the workflows', () => {
WorkflowsPage.getters.workflowCards().should('have.length', 2);
@@ -75,15 +79,14 @@ describe('Workflows', () => {
WorkflowsPage.getters.workflowDeleteButton().click();
cy.get('button').contains('delete').click();
})
});
WorkflowsPage.getters.newWorkflowButtonCard().should('be.visible');
WorkflowsPage.getters.newWorkflowTemplateCard().should('be.visible');
})
});
it('should contain empty state cards', () => {
WorkflowsPage.getters.newWorkflowButtonCard().should('be.visible');
WorkflowsPage.getters.newWorkflowTemplateCard().should('be.visible');
});
});

View File

@@ -53,8 +53,10 @@ describe('Undo/Redo', () => {
it('should undo/redo deleting node using delete button', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters.canvasNodeByName(CODE_NODE_NAME).
find('[data-test-id=delete-node-button]').click({ force: true });
WorkflowPage.getters
.canvasNodeByName(CODE_NODE_NAME)
.find('[data-test-id=delete-node-button]')
.click({ force: true });
WorkflowPage.getters.canvasNodes().should('have.have.length', 1);
WorkflowPage.getters.nodeConnections().should('have.length', 0);
WorkflowPage.actions.hitUndo();
@@ -117,11 +119,20 @@ describe('Undo/Redo', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', 50, 150);
WorkflowPage.getters.canvasNodes().last().should('have.attr', 'style', 'left: 740px; top: 360px;');
WorkflowPage.getters
.canvasNodes()
.last()
.should('have.attr', 'style', 'left: 740px; top: 360px;');
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.canvasNodes().last().should('have.attr', 'style', 'left: 640px; top: 260px;');
WorkflowPage.getters
.canvasNodes()
.last()
.should('have.attr', 'style', 'left: 640px; top: 260px;');
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodes().last().should('have.attr', 'style', 'left: 740px; top: 360px;');
WorkflowPage.getters
.canvasNodes()
.last()
.should('have.attr', 'style', 'left: 740px; top: 360px;');
});
it('should undo/redo deleting a connection by pressing delete button', () => {
@@ -144,13 +155,17 @@ describe('Undo/Redo', () => {
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.nodeConnections().should('have.length', 1);
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.nodeConnections().should('have.length', 0)
WorkflowPage.getters.nodeConnections().should('have.length', 0);
});
it('should undo/redo disabling a node using disable button', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters.canvasNodes().last().find('[data-test-id="disable-node-button"]').click({ force: true });
WorkflowPage.getters
.canvasNodes()
.last()
.find('[data-test-id="disable-node-button"]')
.click({ force: true });
WorkflowPage.getters.disabledNodes().should('have.length', 1);
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.disabledNodes().should('have.length', 0);
@@ -207,7 +222,7 @@ describe('Undo/Redo', () => {
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('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}');
@@ -222,7 +237,11 @@ describe('Undo/Redo', () => {
it('should undo/redo duplicating a node', () => {
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters.canvasNodes().last().find('[data-test-id="duplicate-node-button"]').click({ force: true });
WorkflowPage.getters
.canvasNodes()
.last()
.find('[data-test-id="duplicate-node-button"]')
.click({ force: true });
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.canvasNodes().should('have.length', 2);
WorkflowPage.actions.hitRedo();
@@ -230,7 +249,7 @@ describe('Undo/Redo', () => {
});
it('should undo/redo pasting nodes', () => {
cy.fixture('Test_workflow-actions_paste-data.json').then(data => {
cy.fixture('Test_workflow-actions_paste-data.json').then((data) => {
cy.get('body').paste(JSON.stringify(data));
WorkflowPage.actions.zoomToFit();
WorkflowPage.getters.canvasNodes().should('have.have.length', 2);
@@ -242,42 +261,48 @@ describe('Undo/Redo', () => {
});
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(CODE_NODE_NAME);
WorkflowPage.actions.zoomToFit();
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.actions.addNodeToCanvas(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.getters.canvasNodes().first().click();
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', 50, 150);
// Delete the set node
WorkflowPage.getters.canvasNodeByName(SET_NODE_NAME).click().click();
cy.get('body').type('{backspace}');
// Disable last node
WorkflowPage.getters.canvasNodes().last().click();
WorkflowPage.actions.hitDisableNodeShortcut();
// Move first one
WorkflowPage.getters.canvasNodes().first().click();
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', 50, 150);
// Delete the set node
WorkflowPage.getters.canvasNodeByName(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.attr', 'style', 'left: 420px; top: 260px;');
// Third undo: Should enable last node
WorkflowPage.actions.hitUndo();
WorkflowPage.getters.disabledNodes().should('have.length', 0);
// 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.attr', 'style', 'left: 420px; top: 260px;');
// 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().should('have.attr', 'style', 'left: 540px; top: 400px;');
// Third redo: Should delete the Set node
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodes().should('have.length', 3);
WorkflowPage.getters.nodeConnections().should('have.length', 2);
});
// 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()
.should('have.attr', 'style', 'left: 540px; top: 400px;');
// Third redo: Should delete the Set node
WorkflowPage.actions.hitRedo();
WorkflowPage.getters.canvasNodes().should('have.length', 3);
WorkflowPage.getters.nodeConnections().should('have.length', 2);
});
});

View File

@@ -1,5 +1,5 @@
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from "../constants";
import { randFirstName, randLastName } from "@ngneat/falso";
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants';
import { randFirstName, randLastName } from '@ngneat/falso';
import { CredentialsPage, CredentialsModal } from '../pages';
const email = DEFAULT_USER_EMAIL;
@@ -20,7 +20,7 @@ describe('Credentials', () => {
expect(err.message).to.include('Not logged in');
return false;
})
});
cy.signin({ email, password });
cy.visit(credentialsPage.url);

View File

@@ -1,8 +1,16 @@
import { randFirstName, randLastName } from '@ngneat/falso';
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants';
import { SettingsUsersPage, SignupPage, WorkflowsPage, WorkflowPage, CredentialsPage, CredentialsModal, MessageBox } from '../pages';
import {
SettingsUsersPage,
SignupPage,
WorkflowsPage,
WorkflowPage,
CredentialsPage,
CredentialsModal,
MessageBox,
} from '../pages';
import { MainSidebar, SettingsSidebar } from "../pages/sidebar";
import { MainSidebar, SettingsSidebar } from '../pages/sidebar';
const mainSidebar = new MainSidebar();
const settingsSidebar = new SettingsSidebar();
@@ -29,7 +37,7 @@ describe('Default owner', () => {
});
beforeEach(() => {
cy.visit('/');
})
});
it('should skip owner setup', () => {
cy.skipSetup();
@@ -84,7 +92,7 @@ describe('Default owner', () => {
it('should be able to setup instance and migrate workflows and credentials', () => {
cy.setup({ email, firstName, lastName, password });
messageBox.getters.content().should('contain.text', '1 existing workflow and 1 credential')
messageBox.getters.content().should('contain.text', '1 existing workflow and 1 credential');
messageBox.actions.confirm();
cy.url().should('include', settingsUsersPage.url);
@@ -106,4 +114,3 @@ describe('Default owner', () => {
credentialsPage.getters.credentialCards().should('have.length', 1);
});
});

View File

@@ -1,8 +1,8 @@
import { NodeCreator } from '../pages/features/node-creator';
import { INodeTypeDescription } from '../../packages/workflow';
import CustomNodeFixture from '../fixtures/Custom_node.json';
import {DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD} from "../constants";
import {randFirstName, randLastName} from "@ngneat/falso";
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants';
import { randFirstName, randLastName } from '@ngneat/falso';
const email = DEFAULT_USER_EMAIL;
const password = DEFAULT_USER_PASSWORD;
@@ -21,15 +21,16 @@ describe('Node Creator', () => {
cy.intercept('GET', '/types/nodes.json', (req) => {
// Delete caching headers so that we can intercept the request
['etag', 'if-none-match', 'if-modified-since'].forEach(header => {delete req.headers[header]});
['etag', 'if-none-match', 'if-modified-since'].forEach((header) => {
delete req.headers[header];
});
req.continue((res) => {
const nodes = res.body as INodeTypeDescription[];
nodes.push(CustomNodeFixture as INodeTypeDescription);
res.send(nodes)
})
res.send(nodes);
});
}).as('nodesIntercept');
cy.visit(nodeCreatorFeature.url);
@@ -39,10 +40,13 @@ describe('Node Creator', () => {
it('should open node creator on trigger tab if no trigger is on canvas', () => {
nodeCreatorFeature.getters.canvasAddButton().click();
nodeCreatorFeature.getters.nodeCreator().contains('When should this workflow run?').should('be.visible');
nodeCreatorFeature.getters
.nodeCreator()
.contains('When should this workflow run?')
.should('be.visible');
nodeCreatorFeature.getters.nodeCreatorTabs().should('not.exist');
})
});
it('should see all tabs when opening via plus button', () => {
nodeCreatorFeature.actions.openNodeCreator();
@@ -55,9 +59,9 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.getCreatorItem('On App Event').click();
nodeCreatorFeature.getters.activeSubcategory().should('have.text', 'On App Event');
// Go back
nodeCreatorFeature.getters.activeSubcategory().find('button').click()
nodeCreatorFeature.getters.activeSubcategory().find('button').click();
nodeCreatorFeature.getters.activeSubcategory().should('not.exist');
})
});
it('should search for nodes', () => {
nodeCreatorFeature.actions.openNodeCreator();
@@ -67,32 +71,38 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.creatorItem().should('have.length', 1);
nodeCreatorFeature.getters.searchBar().find('input').clear().type('manual123');
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);
nodeCreatorFeature.getters.noResults()
.should('exist')
.should('contain.text', 'We didn\'t make that... yet');
nodeCreatorFeature.getters
.noResults()
.should('exist')
.should('contain.text', "We didn't make that... yet");
nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image');
nodeCreatorFeature.getters.creatorItem().should('have.length', 1);
nodeCreatorFeature.getters.searchBar().find('input').clear().type('this node totally does not exist');
nodeCreatorFeature.getters
.searchBar()
.find('input')
.clear()
.type('this node totally does not exist');
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);
nodeCreatorFeature.getters.searchBar().find('input').clear()
nodeCreatorFeature.getters.searchBar().find('input').clear();
nodeCreatorFeature.getters.getCreatorItem('On App Event').click();
nodeCreatorFeature.getters.searchBar().find('input').clear().type('edit image');
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);
nodeCreatorFeature.getters.noResults()
.should('exist')
.should('contain.text', 'To see all results, click here');
nodeCreatorFeature.getters
.noResults()
.should('exist')
.should('contain.text', 'To see all results, click here');
nodeCreatorFeature.getters.noResults().contains('click here').click();
nodeCreatorFeature.getters.nodeCreatorTabs().should('exist');
nodeCreatorFeature.getters.getCreatorItem('Edit Image').should('exist');
nodeCreatorFeature.getters.selectedTab().should('have.text', 'All');
nodeCreatorFeature.getters.searchBar().find('button').click();
nodeCreatorFeature.getters.searchBar().find('input').should('be.empty')
})
nodeCreatorFeature.getters.searchBar().find('input').should('be.empty');
});
it('should add manual trigger node', () => {
nodeCreatorFeature.getters.canvasAddButton().click();
@@ -105,8 +115,8 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.nodeCreator().should('not.exist');
// TODO: Replace once we have canvas feature utils
cy.get('div').contains("Add first step").should('exist');
})
cy.get('div').contains('Add first step').should('exist');
});
it('check if non-core nodes are rendered', () => {
cy.wait('@nodesIntercept').then((interception) => {
const nodes = interception.response?.body as INodeTypeDescription[];
@@ -118,29 +128,29 @@ describe('Node Creator', () => {
const categories = Object.keys(categorizedNodes);
categories.forEach((category: string) => {
// Core Nodes contains subcategories which we'll test separately
if(category === 'Core Nodes') return;
if (category === 'Core Nodes') return;
nodeCreatorFeature.actions.toggleCategory(category)
nodeCreatorFeature.actions.toggleCategory(category);
// Check if all nodes are present
nodeCreatorFeature.getters.nodeItemName().then($elements => {
nodeCreatorFeature.getters.nodeItemName().then(($elements) => {
const visibleNodes: string[] = [];
$elements.each((_, element) => {
visibleNodes.push(element.textContent?.trim() || '');
})
});
const visibleCategoryNodes = (categorizedNodes[category] as INodeTypeDescription[])
.filter(node => !node.hidden)
.map(node => node.displayName?.trim());
.filter((node) => !node.hidden)
.map((node) => node.displayName?.trim());
cy.wrap(visibleCategoryNodes).each((categoryNode: string) => {
expect(visibleNodes).to.include(categoryNode);
});
})
});
nodeCreatorFeature.actions.toggleCategory(category)
})
})
})
nodeCreatorFeature.actions.toggleCategory(category);
});
});
});
it('should render and select community node', () => {
cy.wait('@nodesIntercept').then(() => {
@@ -154,19 +164,25 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.getCreatorItem(customCategory).should('exist');
nodeCreatorFeature.actions.toggleCategory(customCategory);
nodeCreatorFeature.getters.getCreatorItem(customNode).findChildByTestId('node-creator-item-tooltip').should('exist');
nodeCreatorFeature.getters.getCreatorItem(customNode).contains(customNodeDescription).should('exist');
nodeCreatorFeature.getters
.getCreatorItem(customNode)
.findChildByTestId('node-creator-item-tooltip')
.should('exist');
nodeCreatorFeature.getters
.getCreatorItem(customNode)
.contains(customNodeDescription)
.should('exist');
nodeCreatorFeature.actions.selectNode(customNode);
// TODO: Replace once we have canvas feature utils
cy.get('.data-display .node-name').contains(customNode).should('exist');
const nodeParameters = () => cy.getByTestId('node-parameters')
const nodeParameters = () => cy.getByTestId('node-parameters');
const firstParameter = () => nodeParameters().find('.parameter-item').eq(0);
const secondParameter = () => nodeParameters().find('.parameter-item').eq(1);
// Check correct fields are rendered
nodeParameters().should('exist')
nodeParameters().should('exist');
// Test property text input
firstParameter().contains('Test property').should('exist');
firstParameter().find('input.el-input__inner').should('have.value', 'Some default');
@@ -174,11 +190,17 @@ describe('Node Creator', () => {
secondParameter().find('label').contains('Resource').should('exist');
secondParameter().find('input.el-input__inner').should('have.value', 'option2');
secondParameter().find('.el-select').click();
secondParameter().find('.el-select-dropdown__list').should('exist')
secondParameter().find('.el-select-dropdown__list').should('exist');
// Check if all options are rendered and select the fourth one
secondParameter().find('.el-select-dropdown__list').children().should('have.length', 4);
secondParameter().find('.el-select-dropdown__list').children().eq(3).contains('option4').should('exist').click();
secondParameter()
.find('.el-select-dropdown__list')
.children()
.eq(3)
.contains('option4')
.should('exist')
.click();
secondParameter().find('input.el-input__inner').should('have.value', 'option4');
})
})
});
});
});

View File

@@ -18,7 +18,7 @@ describe('NDV', () => {
workflowPage.actions.addInitialNodeToCanvas('Manual Trigger');
workflowPage.getters.canvasNodes().first().dblclick();
ndv.getters.container().should('be.visible');
ndv.getters.backToCanvas().click()
ndv.getters.backToCanvas().click();
ndv.getters.container().should('not.be.visible');
});
@@ -31,13 +31,13 @@ describe('NDV', () => {
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
cy.readClipboard().then(url => {
cy.readClipboard().then((url) => {
cy.request({
method: 'GET',
url,
}).then((resp) => {
expect(resp.status).to.eq(200)
})
expect(resp.status).to.eq(200);
});
});
ndv.getters.runDataDisplayMode().should('have.length.at.least', 1).and('be.visible');

View File

@@ -53,7 +53,10 @@ describe('Workflow Actions', () => {
WorkflowPage.actions.saveWorkflowOnButtonClick();
WorkflowPage.actions.renameWorkflow(NEW_WORKFLOW_NAME);
WorkflowPage.getters.isWorkflowSaved();
WorkflowPage.getters.workflowNameInputContainer().invoke('attr', 'title').should('eq', NEW_WORKFLOW_NAME);
WorkflowPage.getters
.workflowNameInputContainer()
.invoke('attr', 'title')
.should('eq', NEW_WORKFLOW_NAME);
});
it('should add tags', () => {
@@ -97,7 +100,7 @@ describe('Workflow Actions', () => {
WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME);
WorkflowPage.getters.canvasNodes().should('have.have.length', 2);
cy.get("#node-creator").should('not.exist');
cy.get('#node-creator').should('not.exist');
cy.get('body').type(metaKey, { delay: 500, release: false }).type('a');
cy.get('.jtk-drag-selected').should('have.length', 2);
cy.get('body').type(metaKey, { delay: 500, release: false }).type('c');
@@ -105,7 +108,7 @@ describe('Workflow Actions', () => {
});
it('should paste nodes', () => {
cy.fixture('Test_workflow-actions_paste-data.json').then(data => {
cy.fixture('Test_workflow-actions_paste-data.json').then((data) => {
cy.get('body').paste(JSON.stringify(data));
WorkflowPage.getters.canvasNodes().should('have.have.length', 2);
});
@@ -126,10 +129,9 @@ describe('Workflow Actions', () => {
});
it('should import workflow from file', () => {
WorkflowPage.getters.workflowImportInput().selectFile(
'cypress/fixtures/Test_workflow-actions_paste-data.json',
{ force: true }
);
WorkflowPage.getters
.workflowImportInput()
.selectFile('cypress/fixtures/Test_workflow-actions_paste-data.json', { force: true });
cy.waitForLoad();
WorkflowPage.actions.zoomToFit();
WorkflowPage.getters.canvasNodes().should('have.length', 2);
@@ -145,17 +147,49 @@ describe('Workflow Actions', () => {
WorkflowPage.getters.workflowMenuItemSettings().click();
// Change all settings
WorkflowPage.getters.workflowSettingsErrorWorkflowSelect().find('li').should('have.length', 2);
WorkflowPage.getters.workflowSettingsErrorWorkflowSelect().find('li').last().click({ force: true });
WorkflowPage.getters
.workflowSettingsErrorWorkflowSelect()
.find('li')
.last()
.click({ force: true });
WorkflowPage.getters.workflowSettingsTimezoneSelect().find('li').should('exist');
WorkflowPage.getters.workflowSettingsTimezoneSelect().find('li').eq(1).click({ force: true });
WorkflowPage.getters.workflowSettingsSaveFiledExecutionsSelect().find('li').should('have.length', 3);
WorkflowPage.getters.workflowSettingsSaveFiledExecutionsSelect().find('li').last().click({ force: true });
WorkflowPage.getters.workflowSettingsSaveSuccessExecutionsSelect().find('li').should('have.length', 3);
WorkflowPage.getters.workflowSettingsSaveSuccessExecutionsSelect().find('li').last().click({ force: true });
WorkflowPage.getters.workflowSettingsSaveManualExecutionsSelect().find('li').should('have.length', 3);
WorkflowPage.getters.workflowSettingsSaveManualExecutionsSelect().find('li').last().click({ force: true });
WorkflowPage.getters.workflowSettingsSaveExecutionProgressSelect().find('li').should('have.length', 3);
WorkflowPage.getters.workflowSettingsSaveExecutionProgressSelect().find('li').last().click({ force: true });
WorkflowPage.getters
.workflowSettingsSaveFiledExecutionsSelect()
.find('li')
.should('have.length', 3);
WorkflowPage.getters
.workflowSettingsSaveFiledExecutionsSelect()
.find('li')
.last()
.click({ force: true });
WorkflowPage.getters
.workflowSettingsSaveSuccessExecutionsSelect()
.find('li')
.should('have.length', 3);
WorkflowPage.getters
.workflowSettingsSaveSuccessExecutionsSelect()
.find('li')
.last()
.click({ force: true });
WorkflowPage.getters
.workflowSettingsSaveManualExecutionsSelect()
.find('li')
.should('have.length', 3);
WorkflowPage.getters
.workflowSettingsSaveManualExecutionsSelect()
.find('li')
.last()
.click({ force: true });
WorkflowPage.getters
.workflowSettingsSaveExecutionProgressSelect()
.find('li')
.should('have.length', 3);
WorkflowPage.getters
.workflowSettingsSaveExecutionProgressSelect()
.find('li')
.last()
.click({ force: true });
WorkflowPage.getters.workflowSettingsTimeoutWorkflowSwitch().click();
WorkflowPage.getters.workflowSettingsTimeoutForm().find('input').first().type('1');
// Save settings
@@ -163,5 +197,4 @@ describe('Workflow Actions', () => {
WorkflowPage.getters.workflowSettingsModal().should('not.exist');
WorkflowPage.getters.successToast().should('exist');
});
});

View File

@@ -1,55 +1,51 @@
{
"properties": [{
"displayName": "Test property",
"name": "testProp",
"type": "string",
"required": true,
"noDataExpression": false,
"default": "Some default"
},
{
"displayName": "Resource",
"name": "resource",
"type": "options",
"noDataExpression": true,
"options": [{
"name": "option1",
"value": "option1"
},
{
"name": "option2",
"value": "option2"
},
{
"name": "option3",
"value": "option3"
},
{
"name": "option4",
"value": "option4"
}
],
"default": "option2"
}
],
"displayName": "E2E Node",
"name": "@e2e/n8n-nodes-e2e",
"group": [
"transform"
],
"properties": [
{
"displayName": "Test property",
"name": "testProp",
"type": "string",
"required": true,
"noDataExpression": false,
"default": "Some default"
},
{
"displayName": "Resource",
"name": "resource",
"type": "options",
"noDataExpression": true,
"options": [
{
"name": "option1",
"value": "option1"
},
{
"name": "option2",
"value": "option2"
},
{
"name": "option3",
"value": "option3"
},
{
"name": "option4",
"value": "option4"
}
],
"default": "option2"
}
],
"displayName": "E2E Node",
"name": "@e2e/n8n-nodes-e2e",
"group": ["transform"],
"codex": {
"categories": ["Custom Category"]
},
"version": 1,
"description": "Demonstrate rendering of node",
"defaults": {
"name": "E2E Node "
},
"inputs": [
"main"
],
"outputs": [
"main"
],
"icon": "fa:network-wired"
"version": 1,
"description": "Demonstrate rendering of node",
"defaults": {
"name": "E2E Node "
},
"inputs": ["main"],
"outputs": ["main"],
"icon": "fa:network-wired"
}

View File

@@ -1,83 +1,74 @@
{
"name": "ff739753-9d6e-46a7-94d3-25bd03dd4973",
"nodes": [
{
"parameters": {},
"id": "c30d1114-d7f7-44dc-b55a-15312ef2d76d",
"name": "On clicking 'execute'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
600,
580
]
},
{
"parameters": {
"options": {}
},
"id": "5bf514bd-65ae-4a1c-8b69-a01bfeaad411",
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
820,
580
]
},
{
"parameters": {
"options": {}
},
"id": "02bf49e9-44b2-4f4e-8cb2-8c02399208af",
"name": "Set1",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
1040,
580
]
}
],
"pinData": {
"On clicking 'execute'": [
{
"json": {
"start": true
}
}
]
},
"connections": {
"On clicking 'execute'": {
"main": [
[
{
"node": "Set",
"type": "main",
"index": 0
}
]
]
},
"Set": {
"main": [
[
{
"node": "Set1",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"hash": "abd7b28aa2605c96ba24474d72cbe610",
"id": 3,
"meta": {
"instanceId": "08a83d394781701f5c18052cde68e8d92c88b26f5cc8809eb10ad545f14015cb"
},
"tags": []
}
"name": "ff739753-9d6e-46a7-94d3-25bd03dd4973",
"nodes": [
{
"parameters": {},
"id": "c30d1114-d7f7-44dc-b55a-15312ef2d76d",
"name": "On clicking 'execute'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [600, 580]
},
{
"parameters": {
"options": {}
},
"id": "5bf514bd-65ae-4a1c-8b69-a01bfeaad411",
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [820, 580]
},
{
"parameters": {
"options": {}
},
"id": "02bf49e9-44b2-4f4e-8cb2-8c02399208af",
"name": "Set1",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [1040, 580]
}
],
"pinData": {
"On clicking 'execute'": [
{
"json": {
"start": true
}
}
]
},
"connections": {
"On clicking 'execute'": {
"main": [
[
{
"node": "Set",
"type": "main",
"index": 0
}
]
]
},
"Set": {
"main": [
[
{
"node": "Set1",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"hash": "abd7b28aa2605c96ba24474d72cbe610",
"id": 3,
"meta": {
"instanceId": "08a83d394781701f5c18052cde68e8d92c88b26f5cc8809eb10ad545f14015cb"
},
"tags": []
}

View File

@@ -2,35 +2,40 @@
"meta": {
"instanceId": "1a30c82b98a30444ad25bce513655a5e02be772d361403542c23172be6062f04"
},
"nodes": [{
"parameters": {
"rule": {
"interval": [{}]
}
"nodes": [
{
"parameters": {
"rule": {
"interval": [{}]
}
},
"id": "a898563b-d2a4-4b15-a979-366872e801b0",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [420, 260]
},
"id": "a898563b-d2a4-4b15-a979-366872e801b0",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [420, 260]
}, {
"parameters": {
"options": {}
},
"id": "b9a13e3d-bfa5-4873-959f-fd3d67e380d9",
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [640, 260]
}],
{
"parameters": {
"options": {}
},
"id": "b9a13e3d-bfa5-4873-959f-fd3d67e380d9",
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [640, 260]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[{
"node": "Set",
"type": "main",
"index": 0
}]
[
{
"node": "Set",
"type": "main",
"index": 0
}
]
]
}
}

View File

@@ -1,4 +1,4 @@
import { IE2ETestPage, IE2ETestPageElement } from "../types";
import { IE2ETestPage, IE2ETestPageElement } from '../types';
export class BasePage implements IE2ETestPage {
getters: Record<string, IE2ETestPageElement> = {};

View File

@@ -1,4 +1,4 @@
import { BasePage } from "./base";
import { BasePage } from './base';
export class CredentialsPage extends BasePage {
url = '/credentials';
@@ -8,12 +8,15 @@ export class CredentialsPage extends BasePage {
searchInput: () => cy.getByTestId('resources-list-search'),
emptyList: () => cy.getByTestId('resources-list-empty'),
credentialCards: () => cy.getByTestId('resources-list-item'),
credentialCard: (credentialName: string) => this.getters.credentialCards()
.contains(credentialName)
.parents('[data-test-id="resources-list-item"]'),
credentialCardActions: (credentialName: string) => this.getters.credentialCard(credentialName)
.findChildByTestId('credential-card-actions'),
credentialDeleteButton: () => cy.getByTestId('action-toggle-dropdown').filter(':visible').contains('Delete'),
credentialCard: (credentialName: string) =>
this.getters
.credentialCards()
.contains(credentialName)
.parents('[data-test-id="resources-list-item"]'),
credentialCardActions: (credentialName: string) =>
this.getters.credentialCard(credentialName).findChildByTestId('credential-card-actions'),
credentialDeleteButton: () =>
cy.getByTestId('action-toggle-dropdown').filter(':visible').contains('Delete'),
sort: () => cy.getByTestId('resources-list-sort'),
sortOption: (label: string) => this.getters.sort().contains(label).first(),
filtersTrigger: () => cy.getByTestId('resources-list-filters-trigger'),

View File

@@ -1,4 +1,4 @@
import { BasePage } from "../base";
import { BasePage } from '../base';
import { INodeTypeDescription } from '../../packages/workflow';
export class NodeCreator extends BasePage {
@@ -7,7 +7,8 @@ export class NodeCreator extends BasePage {
plusButton: () => cy.getByTestId('node-creator-plus-button'),
canvasAddButton: () => cy.getByTestId('canvas-add-button'),
searchBar: () => cy.getByTestId('search-bar'),
getCreatorItem: (label: string) => this.getters.creatorItem().contains(label).parents('[data-test-id="item-iterator-item"]'),
getCreatorItem: (label: string) =>
this.getters.creatorItem().contains(label).parents('[data-test-id="item-iterator-item"]'),
getNthCreatorItem: (n: number) => this.getters.creatorItem().eq(n),
nodeCreator: () => cy.getByTestId('node-creator'),
nodeCreatorTabs: () => cy.getByTestId('node-creator-type-selector'),
@@ -18,13 +19,14 @@ export class NodeCreator extends BasePage {
noResults: () => cy.getByTestId('categorized-no-results'),
nodeItemName: () => cy.getByTestId('node-creator-item-name'),
activeSubcategory: () => cy.getByTestId('categorized-items-subcategory'),
expandedCategories: () => this.getters.creatorItem().find('>div').filter('.active').invoke('text'),
expandedCategories: () =>
this.getters.creatorItem().find('>div').filter('.active').invoke('text'),
};
actions = {
openNodeCreator: () => {
cy.waitForLoad();
this.getters.plusButton().click();
this.getters.nodeCreator().should('be.visible')
this.getters.nodeCreator().should('be.visible');
},
selectNode: (displayName: string) => {
this.getters.getCreatorItem(displayName).click();
@@ -33,15 +35,20 @@ export class NodeCreator extends BasePage {
this.getters.nodeCreatorTabs().contains(tab).click();
},
toggleCategory: (category: string) => {
this.getters.getCreatorItem(category).click()
this.getters.getCreatorItem(category).click();
},
categorizeNodes: (nodes: INodeTypeDescription[]) => {
const categorizedNodes = nodes.reduce((acc, node) => {
const categories = (node?.codex?.categories || []).map((category: string) => category.trim());
const categories = (node?.codex?.categories || []).map((category: string) =>
category.trim(),
);
categories.forEach((category: {[key: string]: INodeTypeDescription[]}) => {
categories.forEach((category: { [key: string]: INodeTypeDescription[] }) => {
// Node creator should show only the latest version of a node
const newerVersion = nodes.find((n: INodeTypeDescription) => n.name === node.name && (n.version > node.version || Array.isArray(n.version)));
const newerVersion = nodes.find(
(n: INodeTypeDescription) =>
n.name === node.name && (n.version > node.version || Array.isArray(n.version)),
);
if (acc[category] === undefined) {
acc[category] = [];
@@ -49,9 +56,9 @@ export class NodeCreator extends BasePage {
acc[category].push(newerVersion ?? node);
});
return acc;
}, {})
}, {});
return categorizedNodes;
}
},
};
}

View File

@@ -1,16 +1,20 @@
import { BasePage } from "../base";
import { BasePage } from '../base';
export class CredentialsModal extends BasePage {
getters = {
newCredentialModal: () => cy.getByTestId('selectCredential-modal', { timeout: 5000 }),
editCredentialModal: () => cy.getByTestId('editCredential-modal', { timeout: 5000 }),
newCredentialTypeSelect: () => cy.getByTestId('new-credential-type-select'),
newCredentialTypeOption: (credentialType: string) => cy.getByTestId('new-credential-type-select-option').contains(credentialType),
newCredentialTypeOption: (credentialType: string) =>
cy.getByTestId('new-credential-type-select-option').contains(credentialType),
newCredentialTypeButton: () => cy.getByTestId('new-credential-type-button'),
connectionParameters: () => cy.getByTestId('credential-connection-parameter'),
connectionParameter: (fieldName: string) => this.getters.connectionParameters().contains(fieldName)
.parents('[data-test-id="credential-connection-parameter"]')
.find('.n8n-input input'),
connectionParameter: (fieldName: string) =>
this.getters
.connectionParameters()
.contains(fieldName)
.parents('[data-test-id="credential-connection-parameter"]')
.find('.n8n-input input'),
name: () => cy.getByTestId('credential-name'),
nameInput: () => cy.getByTestId('credential-name').find('input'),
// Saving of the credentials takes a while on the CI so we need to increase the timeout
@@ -24,14 +28,14 @@ export class CredentialsModal extends BasePage {
},
save: (test = false) => {
cy.intercept('POST', '/rest/credentials').as('saveCredential');
if(test) {
if (test) {
cy.intercept('POST', '/rest/credentials/test').as('testCredential');
}
this.getters.saveButton().click();
cy.wait('@saveCredential');
if(test) cy.wait('@testCredential')
if (test) cy.wait('@testCredential');
this.getters.saveButton().should('contain.text', 'Saved');
},
close: () => {

View File

@@ -1,4 +1,4 @@
import { BasePage } from "../base";
import { BasePage } from '../base';
export class MessageBox extends BasePage {
getters = {

View File

@@ -1,4 +1,4 @@
import { BasePage } from "./base";
import { BasePage } from './base';
export class NDV extends BasePage {
getters = {
@@ -12,5 +12,5 @@ export class NDV extends BasePage {
dataContainer: () => cy.getByTestId('ndv-data-container'),
runDataDisplayMode: () => cy.getByTestId('ndv-run-data-display-mode'),
digital: () => cy.getByTestId('ndv-run-data-display-mode'),
}
};
}

View File

@@ -1,11 +1,11 @@
import { BasePage } from "./base";
import { BasePage } from './base';
export class SettingsUsersPage extends BasePage {
url = '/settings/users';
getters = {
setUpOwnerButton: () => cy.getByTestId('action-box').find('button'),
}
};
actions = {
goToOwnerSetup: () => this.getters.setUpOwnerButton().click(),
}
};
}

View File

@@ -1,8 +1,9 @@
import { BasePage } from "../base";
import { BasePage } from '../base';
export class MainSidebar extends BasePage {
getters = {
menuItem: (menuLabel: string) => cy.getByTestId('menu-item').filter(`:contains("${menuLabel}")`),
menuItem: (menuLabel: string) =>
cy.getByTestId('menu-item').filter(`:contains("${menuLabel}")`),
settings: () => this.getters.menuItem('Settings'),
templates: () => this.getters.menuItem('Templates'),
workflows: () => this.getters.menuItem('Workflows'),
@@ -19,7 +20,7 @@ export class MainSidebar extends BasePage {
goToCredentials: () => {
this.getters.credentials().should('be.visible');
cy.get('[data-old-overflow]').should('not.exist');
this.getters.credentials().click()
this.getters.credentials().click();
},
};
}

View File

@@ -1,4 +1,4 @@
import { BasePage } from "../base";
import { BasePage } from '../base';
export class SettingsSidebar extends BasePage {
getters = {

View File

@@ -1,4 +1,4 @@
import { BasePage } from "./base";
import { BasePage } from './base';
export class SigninPage extends BasePage {
url = '/signin';
@@ -7,5 +7,5 @@ export class SigninPage extends BasePage {
email: () => cy.getByTestId('email'),
password: () => cy.getByTestId('password'),
submit: () => cy.get('button'),
}
};
}

View File

@@ -1,4 +1,4 @@
import { BasePage } from "./base";
import { BasePage } from './base';
// todo rename to setup
export class SignupPage extends BasePage {
@@ -11,5 +11,5 @@ export class SignupPage extends BasePage {
password: () => cy.getByTestId('password'),
submit: () => cy.get('button'),
skip: () => cy.get('a'),
}
};
}

View File

@@ -4,13 +4,16 @@ export class WorkflowPage extends BasePage {
url = '/workflow/new';
getters = {
workflowNameInputContainer: () => cy.getByTestId('workflow-name-input', { timeout: 5000 }),
workflowNameInput: () => this.getters.workflowNameInputContainer().then(($el) => cy.wrap($el.find('input'))),
workflowNameInput: () =>
this.getters.workflowNameInputContainer().then(($el) => cy.wrap($el.find('input'))),
workflowImportInput: () => cy.getByTestId('workflow-import-input'),
workflowTags: () => cy.getByTestId('workflow-tags'),
workflowTagsContainer: () => cy.getByTestId('workflow-tags-container'),
workflowTagsInput: () => this.getters.workflowTagsContainer().then(($el) => cy.wrap($el.find('input').first())),
workflowTagsInput: () =>
this.getters.workflowTagsContainer().then(($el) => cy.wrap($el.find('input').first())),
workflowTagElements: () => cy.get('[data-test-id="workflow-tags-container"] span.tags > span'),
firstWorkflowTagElement: () => cy.get('[data-test-id="workflow-tags-container"] span.tags > span:nth-child(1)'),
firstWorkflowTagElement: () =>
cy.get('[data-test-id="workflow-tags-container"] span.tags > span:nth-child(1)'),
workflowTagsDropdown: () => cy.getByTestId('workflow-tags-dropdown'),
newTagLink: () => cy.getByTestId('new-tag-link'),
saveButton: () => cy.getByTestId('workflow-save-button'),
@@ -18,7 +21,8 @@ export class WorkflowPage extends BasePage {
nodeCreatorPlusButton: () => cy.getByTestId('node-creator-plus-button'),
canvasPlusButton: () => cy.getByTestId('canvas-plus-button'),
canvasNodes: () => cy.getByTestId('canvas-node'),
canvasNodeByName: (nodeName: string) => this.getters.canvasNodes().filter(`:contains("${nodeName}")`),
canvasNodeByName: (nodeName: string) =>
this.getters.canvasNodes().filter(`:contains("${nodeName}")`),
ndvParameterInput: (parameterName: string) =>
cy.getByTestId(`parameter-input-${parameterName}`),
ndvOutputPanel: () => cy.getByTestId('output-panel'),
@@ -51,13 +55,19 @@ export class WorkflowPage extends BasePage {
workflowSettingsModal: () => cy.getByTestId('workflow-settings-dialog'),
workflowSettingsErrorWorkflowSelect: () => cy.getByTestId('workflow-settings-error-workflow'),
workflowSettingsTimezoneSelect: () => cy.getByTestId('workflow-settings-timezone'),
workflowSettingsSaveFiledExecutionsSelect: () => cy.getByTestId('workflow-settings-save-failed-executions'),
workflowSettingsSaveSuccessExecutionsSelect: () => cy.getByTestId('workflow-settings-save-success-executions'),
workflowSettingsSaveManualExecutionsSelect: () => cy.getByTestId('workflow-settings-save-manual-executions'),
workflowSettingsSaveExecutionProgressSelect: () => cy.getByTestId('workflow-settings-save-execution-progress'),
workflowSettingsTimeoutWorkflowSwitch: () => cy.getByTestId('workflow-settings-timeout-workflow'),
workflowSettingsSaveFiledExecutionsSelect: () =>
cy.getByTestId('workflow-settings-save-failed-executions'),
workflowSettingsSaveSuccessExecutionsSelect: () =>
cy.getByTestId('workflow-settings-save-success-executions'),
workflowSettingsSaveManualExecutionsSelect: () =>
cy.getByTestId('workflow-settings-save-manual-executions'),
workflowSettingsSaveExecutionProgressSelect: () =>
cy.getByTestId('workflow-settings-save-execution-progress'),
workflowSettingsTimeoutWorkflowSwitch: () =>
cy.getByTestId('workflow-settings-timeout-workflow'),
workflowSettingsTimeoutForm: () => cy.getByTestId('workflow-settings-timeout-form'),
workflowSettingsSaveButton: () => cy.getByTestId('workflow-settings-save-button').find('button'),
workflowSettingsSaveButton: () =>
cy.getByTestId('workflow-settings-save-button').find('button'),
inlineExpressionEditorInput: () => cy.getByTestId('inline-expression-editor-input'),
inlineExpressionEditorOutput: () => cy.getByTestId('inline-expression-editor-output'),
@@ -124,7 +134,7 @@ export class WorkflowPage extends BasePage {
cy.get('body').type('{enter}');
},
addTags: (tags: string[]) => {
tags.forEach(tag => {
tags.forEach((tag) => {
this.getters.workflowTagsInput().type(tag);
this.getters.workflowTagsInput().type('{enter}');
});
@@ -142,10 +152,10 @@ export class WorkflowPage extends BasePage {
},
hitRedo: () => {
const metaKey = Cypress.platform === 'darwin' ? '{meta}' : '{ctrl}';
cy.get('body').
type(metaKey, { delay: 500, release: false }).
type('{shift}', { release: false }).
type('z');
cy.get('body')
.type(metaKey, { delay: 500, release: false })
.type('{shift}', { release: false })
.type('z');
},
selectAll: () => {
const metaKey = Cypress.platform === 'darwin' ? '{meta}' : '{ctrl}';

View File

@@ -1,4 +1,4 @@
import { BasePage } from "./base";
import { BasePage } from './base';
export class WorkflowsPage extends BasePage {
url = '/workflows';
@@ -8,18 +8,21 @@ export class WorkflowsPage extends BasePage {
searchBar: () => cy.getByTestId('resources-list-search'),
createWorkflowButton: () => cy.getByTestId('resources-list-add'),
workflowCards: () => cy.getByTestId('resources-list-item'),
workflowCard: (workflowName: string) => this.getters.workflowCards()
.contains(workflowName)
.parents('[data-test-id="resources-list-item"]'),
workflowTags: (workflowName: string) => this.getters.workflowCard(workflowName)
.findChildByTestId('workflow-card-tags'),
workflowActivator: (workflowName: string) => this.getters.workflowCard(workflowName)
.findChildByTestId('workflow-card-activator'),
workflowActivatorStatus: (workflowName: string) => this.getters.workflowActivator(workflowName)
.findChildByTestId('workflow-activator-status'),
workflowCardActions: (workflowName: string) => this.getters.workflowCard(workflowName)
.findChildByTestId('workflow-card-actions'),
workflowDeleteButton: () => cy.getByTestId('action-toggle-dropdown').filter(':visible').contains('Delete')
workflowCard: (workflowName: string) =>
this.getters
.workflowCards()
.contains(workflowName)
.parents('[data-test-id="resources-list-item"]'),
workflowTags: (workflowName: string) =>
this.getters.workflowCard(workflowName).findChildByTestId('workflow-card-tags'),
workflowActivator: (workflowName: string) =>
this.getters.workflowCard(workflowName).findChildByTestId('workflow-card-activator'),
workflowActivatorStatus: (workflowName: string) =>
this.getters.workflowActivator(workflowName).findChildByTestId('workflow-activator-status'),
workflowCardActions: (workflowName: string) =>
this.getters.workflowCard(workflowName).findChildByTestId('workflow-card-actions'),
workflowDeleteButton: () =>
cy.getByTestId('action-toggle-dropdown').filter(':visible').contains('Delete'),
// Not yet implemented
// myWorkflows: () => cy.getByTestId('my-workflows'),
// allWorkflows: () => cy.getByTestId('all-workflows'),
@@ -35,6 +38,6 @@ export class WorkflowsPage extends BasePage {
this.getters.workflowDeleteButton().click();
cy.get('button').contains('delete').click();
}
}
},
};
}

View File

@@ -24,44 +24,50 @@
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
import { WorkflowsPage, SigninPage, SignupPage } from "../pages";
import { N8N_AUTH_COOKIE } from "../constants";
import { WorkflowsPage, SigninPage, SignupPage } from '../pages';
import { N8N_AUTH_COOKIE } from '../constants';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import { MessageBox } from '../pages/modals/message-box';
Cypress.Commands.add('getByTestId', (selector, ...args) => {
return cy.get(`[data-test-id="${selector}"]`, ...args)
})
return cy.get(`[data-test-id="${selector}"]`, ...args);
});
Cypress.Commands.add('createFixtureWorkflow', (fixtureKey, workflowName) => {
const WorkflowPage = new WorkflowPageClass()
const WorkflowPage = new WorkflowPageClass();
// We need to force the click because the input is hidden
WorkflowPage.getters.workflowImportInput().selectFile(`cypress/fixtures/${fixtureKey}`, { force: true});
WorkflowPage.getters
.workflowImportInput()
.selectFile(`cypress/fixtures/${fixtureKey}`, { force: true });
WorkflowPage.getters.workflowNameInput().should('be.disabled');
WorkflowPage.getters.workflowNameInput().parent().click()
WorkflowPage.getters.workflowNameInput().parent().click();
WorkflowPage.getters.workflowNameInput().should('be.enabled');
WorkflowPage.getters.workflowNameInput().clear().type(workflowName).type('{enter}');
WorkflowPage.getters.saveButton().should('contain', 'Saved');
})
});
Cypress.Commands.add('findChildByTestId', { prevSubject: true }, (subject: Cypress.Chainable<JQuery<HTMLElement>>, childTestId) => {
return subject.find(`[data-test-id="${childTestId}"]`);
})
Cypress.Commands.add(
'findChildByTestId',
{ prevSubject: true },
(subject: Cypress.Chainable<JQuery<HTMLElement>>, childTestId) => {
return subject.find(`[data-test-id="${childTestId}"]`);
},
);
Cypress.Commands.add('waitForLoad', () => {
cy.getByTestId('node-view-loader').should('not.exist', { timeout: 10000 });
cy.get('.el-loading-mask').should('not.exist', { timeout: 10000 });
})
});
Cypress.Commands.add(
'signin',
({ email, password }) => {
const signinPage = new SigninPage();
const workflowsPage = new WorkflowsPage();
Cypress.Commands.add('signin', ({ email, password }) => {
const signinPage = new SigninPage();
const workflowsPage = new WorkflowsPage();
cy.session([email, password], () => {
cy.session(
[email, password],
() => {
cy.visit(signinPage.url);
signinPage.getters.form().within(() => {
@@ -77,7 +83,8 @@ Cypress.Commands.add(
validate() {
cy.getCookie(N8N_AUTH_COOKIE).should('exist');
},
});
},
);
});
Cypress.Commands.add('setup', ({ email, firstName, lastName, password }) => {
@@ -98,7 +105,7 @@ Cypress.Commands.add('setup', ({ email, firstName, lastName, password }) => {
}
});
});
})
});
Cypress.Commands.add('skipSetup', () => {
const signupPage = new SignupPage();
@@ -112,7 +119,6 @@ Cypress.Commands.add('skipSetup', () => {
if (url.endsWith(signupPage.url)) {
signupPage.getters.skip().click();
Confirmation.getters.header().should('contain.text', 'Skip owner account setup?');
Confirmation.actions.confirm();
@@ -123,7 +129,7 @@ Cypress.Commands.add('skipSetup', () => {
}
});
});
})
});
Cypress.Commands.add('resetAll', () => {
cy.task('reset');
@@ -135,25 +141,29 @@ Cypress.Commands.add('setupOwner', (payload) => {
});
Cypress.Commands.add('grantBrowserPermissions', (...permissions: string[]) => {
if(Cypress.isBrowser('chrome')) {
cy.wrap(Cypress.automation('remote:debugger:protocol', {
command: 'Browser.grantPermissions',
params: {
permissions,
origin: window.location.origin,
},
}));
if (Cypress.isBrowser('chrome')) {
cy.wrap(
Cypress.automation('remote:debugger:protocol', {
command: 'Browser.grantPermissions',
params: {
permissions,
origin: window.location.origin,
},
}),
);
}
});
Cypress.Commands.add('readClipboard', () => cy.window().its('navigator.clipboard').invoke('readText'));
Cypress.Commands.add('readClipboard', () =>
cy.window().its('navigator.clipboard').invoke('readText'),
);
Cypress.Commands.add('paste', { prevSubject: true }, (selector, pastePayload) => {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
cy.wrap(selector).then($destination => {
cy.wrap(selector).then(($destination) => {
const pasteEvent = Object.assign(new Event('paste', { bubbles: true, cancelable: true }), {
clipboardData: {
getData: () => pastePayload
}
clipboardData: {
getData: () => pastePayload,
},
});
$destination[0].dispatchEvent(pasteEvent);
});

View File

@@ -13,5 +13,4 @@
// https://on.cypress.io/configuration
// ***********************************************************
import './commands'
import './commands';

View File

@@ -16,8 +16,11 @@ interface SetupPayload {
declare global {
namespace Cypress {
interface Chainable {
getByTestId(selector: string, ...args: (Partial<Loggable & Timeoutable & Withinable & Shadow> | undefined)[]): Chainable<JQuery<HTMLElement>>
findChildByTestId(childTestId: string): Chainable<JQuery<HTMLElement>>
getByTestId(
selector: string,
...args: (Partial<Loggable & Timeoutable & Withinable & Shadow> | undefined)[]
): Chainable<JQuery<HTMLElement>>;
findChildByTestId(childTestId: string): Chainable<JQuery<HTMLElement>>;
createFixtureWorkflow(fixtureKey: string, workflowName: string): void;
signin(payload: SigninPayload): void;
setup(payload: SetupPayload): void;
@@ -27,8 +30,8 @@ declare global {
waitForLoad(): void;
grantBrowserPermissions(...permissions: string[]): void;
readClipboard(): Chainable<string>;
paste(pastePayload: string): void,
drag(selector: string, xDiff: number, yDiff: number): void,
paste(pastePayload: string): void;
drag(selector: string, xDiff: number, yDiff: number): void;
}
}
}

View File

@@ -1,4 +1,6 @@
export type IE2ETestPageElement = (...args: any[]) =>
export type IE2ETestPageElement = (
...args: any[]
) =>
| Cypress.Chainable<JQuery<HTMLElement>>
| Cypress.Chainable<JQuery<HTMLInputElement>>
| Cypress.Chainable<JQuery<HTMLButtonElement>>;