-
Notifications
You must be signed in to change notification settings - Fork 8.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into ado-251-data-transformation-fixes
* master: ci(core): Add unit tests for "me" controller (no-changelog) (#5479) fix(core): Use stricter typing on queries in cli commands (no-changelog) (#5476) fix(editor): Fix Vite dev mode (no-changelog) (#5475) feat(editor): Add correct credential owner contact details for readonly credentials (#5208) feat: Add workflow and credential sharing access e2e tests (#5463) ci: Update the "Check Documentation URLs" workflow (no-changelog) (#5473) feat(editor): Upgrade to Storybook v7 (no-changelog) (#5454) docs: Update release notes link (#5472) test(editor): Add e2e tests for executions preview (#5458) 📚 Update CHANGELOG.md and main package.json to 0.215.2 🔖 Release n8n@0.215.2 fix(core): Fix the issue with test webhooks getting removed incorrectly (no-changelog) (#5466) # Conflicts: # pnpm-lock.yaml
- Loading branch information
Showing
38 changed files
with
2,238 additions
and
3,319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants'; | ||
import { | ||
CredentialsModal, | ||
CredentialsPage, | ||
NDV, | ||
WorkflowPage, | ||
WorkflowSharingModal, | ||
WorkflowsPage, | ||
} from '../pages'; | ||
|
||
/** | ||
* User U1 - Instance owner | ||
* User U2 - User, owns C1, W1, W2 | ||
* User U3 - User, owns C2 | ||
* | ||
* W1 - Workflow owned by User U2, shared with User U3 | ||
* W2 - Workflow owned by User U2 | ||
* | ||
* C1 - Credential owned by User U2 | ||
* C2 - Credential owned by User U3, shared with User U1 and User U2 | ||
*/ | ||
|
||
const credentialsPage = new CredentialsPage(); | ||
const credentialsModal = new CredentialsModal(); | ||
|
||
const workflowsPage = new WorkflowsPage(); | ||
const workflowPage = new WorkflowPage(); | ||
const workflowSharingModal = new WorkflowSharingModal(); | ||
const ndv = new NDV(); | ||
|
||
const instanceOwner = { | ||
email: `${DEFAULT_USER_EMAIL}one`, | ||
password: DEFAULT_USER_PASSWORD, | ||
firstName: 'User', | ||
lastName: 'U1', | ||
}; | ||
|
||
const users = [ | ||
{ | ||
email: `${DEFAULT_USER_EMAIL}two`, | ||
password: DEFAULT_USER_PASSWORD, | ||
firstName: 'User', | ||
lastName: 'U2', | ||
}, | ||
{ | ||
email: `${DEFAULT_USER_EMAIL}three`, | ||
password: DEFAULT_USER_PASSWORD, | ||
firstName: 'User', | ||
lastName: 'U3', | ||
}, | ||
]; | ||
|
||
describe('Sharing', () => { | ||
before(() => { | ||
cy.resetAll(); | ||
cy.setupOwner(instanceOwner); | ||
}); | ||
|
||
beforeEach(() => { | ||
cy.on('uncaught:exception', (err, runnable) => { | ||
expect(err.message).to.include('Not logged in'); | ||
return false; | ||
}); | ||
}); | ||
|
||
it('should invite User U2 and User U3 to instance', () => { | ||
cy.inviteUsers({ instanceOwner, users }); | ||
}); | ||
|
||
let workflowW2Url = ''; | ||
it('should create C1, W1, W2, share W1 with U3, as U2', () => { | ||
cy.signin(users[0]); | ||
|
||
cy.visit(credentialsPage.url); | ||
credentialsPage.getters.emptyListCreateCredentialButton().click(); | ||
credentialsModal.getters.newCredentialTypeOption('Notion API').click(); | ||
credentialsModal.getters.newCredentialTypeButton().click(); | ||
credentialsModal.getters.connectionParameter('API Key').type('1234567890'); | ||
credentialsModal.actions.setName('Credential C1'); | ||
credentialsModal.actions.save(); | ||
credentialsModal.actions.close(); | ||
|
||
cy.visit(workflowsPage.url); | ||
workflowsPage.getters.newWorkflowButtonCard().click(); | ||
workflowPage.actions.setWorkflowName('Workflow W1'); | ||
workflowPage.actions.addInitialNodeToCanvas('Manual Trigger'); | ||
workflowPage.actions.addNodeToCanvas('Notion', true, true); | ||
ndv.getters.credentialInput().should('contain', 'Credential C1'); | ||
ndv.actions.close(); | ||
|
||
workflowPage.actions.openShareModal(); | ||
workflowSharingModal.actions.addUser(users[1].email); | ||
workflowSharingModal.actions.save(); | ||
workflowPage.actions.saveWorkflowOnButtonClick(); | ||
|
||
cy.visit(workflowsPage.url); | ||
workflowsPage.getters.createWorkflowButton().click(); | ||
cy.createFixtureWorkflow('Test_workflow_1.json', 'Workflow W2'); | ||
cy.url().then((url) => { | ||
workflowW2Url = url; | ||
}); | ||
}); | ||
|
||
it('should create C2, share C2 with U1 and U2, as U3', () => { | ||
cy.signin(users[1]); | ||
|
||
cy.visit(credentialsPage.url); | ||
credentialsPage.getters.emptyListCreateCredentialButton().click(); | ||
credentialsModal.getters.newCredentialTypeOption('Airtable API').click(); | ||
credentialsModal.getters.newCredentialTypeButton().click(); | ||
credentialsModal.getters.connectionParameter('API Key').type('1234567890'); | ||
credentialsModal.actions.setName('Credential C2'); | ||
credentialsModal.actions.changeTab('Sharing'); | ||
credentialsModal.actions.addUser(instanceOwner.email); | ||
credentialsModal.actions.addUser(users[0].email); | ||
credentialsModal.actions.save(); | ||
credentialsModal.actions.close(); | ||
}); | ||
|
||
it('should open W1, add node using C2 as U3', () => { | ||
cy.signin(users[1]); | ||
|
||
cy.visit(workflowsPage.url); | ||
workflowsPage.getters.workflowCards().should('have.length', 1); | ||
workflowsPage.getters.workflowCard('Workflow W1').click(); | ||
workflowPage.actions.addNodeToCanvas('Airtable', true, true); | ||
ndv.getters.credentialInput().should('contain', 'Credential C2'); | ||
ndv.actions.close(); | ||
workflowPage.actions.saveWorkflowOnButtonClick(); | ||
|
||
workflowPage.actions.openNode('Notion'); | ||
ndv.getters | ||
.credentialInput() | ||
.find('input') | ||
.should('have.value', 'Credential C1') | ||
.should('be.disabled'); | ||
ndv.actions.close(); | ||
}); | ||
|
||
it('should not have access to W2, as U3', () => { | ||
cy.signin(users[1]); | ||
|
||
cy.visit(workflowW2Url); | ||
cy.waitForLoad(); | ||
cy.wait(1000); | ||
cy.get('.el-notification').contains('Could not find workflow').should('be.visible'); | ||
}); | ||
|
||
it('should have access to W1, W2, as U1', () => { | ||
cy.signin(instanceOwner); | ||
|
||
cy.visit(workflowsPage.url); | ||
workflowsPage.getters.workflowCards().should('have.length', 2); | ||
workflowsPage.getters.workflowCard('Workflow W1').click(); | ||
workflowPage.actions.openNode('Notion'); | ||
ndv.getters | ||
.credentialInput() | ||
.find('input') | ||
.should('have.value', 'Credential C1') | ||
.should('be.disabled'); | ||
ndv.actions.close(); | ||
|
||
cy.waitForLoad(); | ||
cy.visit(workflowsPage.url); | ||
workflowsPage.getters.workflowCard('Workflow W2').click(); | ||
workflowPage.actions.executeWorkflow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { WorkflowPage } from "../pages"; | ||
import { WorkflowExecutionsTab } from "../pages/workflow-executions-tab"; | ||
|
||
const workflowPage = new WorkflowPage(); | ||
const executionsTab = new WorkflowExecutionsTab(); | ||
|
||
// Test suite for executions tab | ||
describe('Current Workflow Executions', () => { | ||
before(() => { | ||
cy.resetAll(); | ||
cy.skipSetup(); | ||
workflowPage.actions.visit(); | ||
cy.waitForLoad(); | ||
cy.createFixtureWorkflow('Test_workflow_4_executions_view.json', `My test workflow`); | ||
createMockExecutions(); | ||
}); | ||
|
||
it('should render executions tab correctly', () => { | ||
cy.waitForLoad(); | ||
executionsTab.getters.executionListItems().should('have.length', 11); | ||
executionsTab.getters.successfulExecutionListItems().should('have.length', 9); | ||
executionsTab.getters.failedExecutionListItems().should('have.length', 2); | ||
executionsTab.getters.executionListItems().first().invoke('attr','class').should('match', /_active_/); | ||
}); | ||
|
||
}); | ||
|
||
|
||
const createMockExecutions = () => { | ||
workflowPage.actions.turnOnManualExecutionSaving(); | ||
executionsTab.actions.createManualExecutions(5); | ||
// Make some failed executions by enabling Code node with syntax error | ||
executionsTab.actions.toggleNodeEnabled('Error'); | ||
executionsTab.actions.createManualExecutions(2); | ||
// Then add some more successful ones | ||
executionsTab.actions.toggleNodeEnabled('Error'); | ||
executionsTab.actions.createManualExecutions(4); | ||
executionsTab.actions.switchToExecutionsTab(); | ||
cy.waitForLoad(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"meta": { | ||
"instanceId": "6b85439d79c07750ea49eced4bc2a12b283cfcba0ab2917cd4f3fee36080e869" | ||
}, | ||
"nodes": [ | ||
{ | ||
"parameters": { | ||
"jsCode": "// Loop over input items and add a new field\n// called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n error\n}\n\nreturn $input.all();" | ||
}, | ||
"id": "d0ab7e12-0e1b-4c08-8081-83107794f37d", | ||
"name": "Error", | ||
"type": "n8n-nodes-base.code", | ||
"typeVersion": 1, | ||
"position": [ | ||
680, | ||
460 | ||
], | ||
"disabled": true | ||
}, | ||
{ | ||
"parameters": {}, | ||
"id": "f5026145-66c1-463c-8ac8-46a1309a6632", | ||
"name": "On clicking 'execute'", | ||
"type": "n8n-nodes-base.manualTrigger", | ||
"typeVersion": 1, | ||
"position": [ | ||
460, | ||
460 | ||
] | ||
}, | ||
{ | ||
"parameters": { | ||
"jsCode": "// Loop over input items and add a new field\n// called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n}\n\nreturn $input.all();" | ||
}, | ||
"id": "9926f884-348a-4af0-872e-dd7c8b3da811", | ||
"name": "Code", | ||
"type": "n8n-nodes-base.code", | ||
"typeVersion": 1, | ||
"position": [ | ||
900, | ||
460 | ||
] | ||
} | ||
], | ||
"connections": { | ||
"Error": { | ||
"main": [ | ||
[ | ||
{ | ||
"node": "Code", | ||
"type": "main", | ||
"index": 0 | ||
} | ||
] | ||
] | ||
}, | ||
"On clicking 'execute'": { | ||
"main": [ | ||
[ | ||
{ | ||
"node": "Error", | ||
"type": "main", | ||
"index": 0 | ||
} | ||
] | ||
] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './credentials-modal'; | ||
export * from './message-box'; | ||
export * from './workflow-sharing-modal'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { BasePage } from '../base'; | ||
|
||
export class WorkflowSharingModal extends BasePage { | ||
getters = { | ||
modal: () => cy.getByTestId('workflowShare-modal', { timeout: 5000 }), | ||
usersSelect: () => cy.getByTestId('workflow-sharing-modal-users-select'), | ||
saveButton: () => cy.getByTestId('workflow-sharing-modal-save-button'), | ||
closeButton: () => this.getters.modal().find('.el-dialog__close').first(), | ||
}; | ||
actions = { | ||
addUser: (email: string) => { | ||
this.getters.usersSelect().click(); | ||
this.getters | ||
.usersSelect() | ||
.get('.el-select-dropdown__item') | ||
.contains(email.toLowerCase()) | ||
.click(); | ||
}, | ||
save: () => { | ||
this.getters.saveButton().click(); | ||
}, | ||
closeModal: () => { | ||
this.getters.closeButton().click(); | ||
}, | ||
}; | ||
} |
Oops, something went wrong.