diff --git a/cypress/e2e/3-default-owner.cy.ts b/cypress/e2e/3-default-owner.cy.ts index 5f1682c35f5a6..75d241456316a 100644 --- a/cypress/e2e/3-default-owner.cy.ts +++ b/cypress/e2e/3-default-owner.cy.ts @@ -1,9 +1,115 @@ -describe('Authentication', () => { - it('should skip owner setup', () => { - cy.skipSetup(); +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 { MainSidebar, SettingsSidebar } from "../pages/sidebar"; + +const mainSidebar = new MainSidebar(); +const settingsSidebar = new SettingsSidebar(); + +const workflowsPage = new WorkflowsPage(); +const signupPage = new SignupPage(); +const workflowPage = new WorkflowPage(); + +const credentialsPage = new CredentialsPage(); +const credentialsModal = new CredentialsModal(); + +const settingsUsersPage = new SettingsUsersPage(); + +const messageBox = new MessageBox(); + +const username = DEFAULT_USER_EMAIL; +const password = DEFAULT_USER_PASSWORD; +const firstName = randFirstName(); +const lastName = randLastName(); + +describe('Default owner', () => { + // todo test should redirect to setup if have not skipped + + beforeEach(() => { + cy.task('db:reset'); }); - // todo test for adding workflow - // todo test for setting up UM again through settings - // todo test that workflows migrated successfully + it('should be able to use n8n without user management and setup UM', () => { + describe('should skip owner setup', () => { + cy.skipSetup(); + cy.url().should('include', workflowsPage.url); + }); + + describe('should be able to create workflows', () => { + workflowsPage.getters.newWorkflowButtonCard().should('be.visible'); + workflowsPage.getters.newWorkflowButtonCard().click(); + + cy.createFixtureWorkflow('Test_workflow_1.json', `Test workflow`); + + // reload page, ensure owner still has access + cy.reload(); + + workflowPage.getters.workflowNameInput().should('contain.value', 'Test workflow'); + }); + + describe('should be able to add new credentials', () => { + cy.visit(credentialsPage.url); + + credentialsPage.getters.emptyListCreateCredentialButton().click(); + + credentialsModal.getters.newCredentialModal().should('be.visible'); + credentialsModal.getters.newCredentialTypeSelect().should('be.visible'); + credentialsModal.getters.newCredentialTypeOption('Notion API').click(); + + credentialsModal.getters.newCredentialTypeButton().click(); + + credentialsModal.getters.connectionParameter('API Key').type('1234567890'); + + credentialsModal.actions.setName('My awesome Notion account'); + credentialsModal.actions.save(); + + credentialsModal.actions.close(); + + credentialsModal.getters.newCredentialModal().should('not.exist'); + credentialsModal.getters.editCredentialModal().should('not.exist'); + + credentialsPage.getters.credentialCards().should('have.length', 1); + }); + + describe('should be able to setup UM from settings', () => { + mainSidebar.getters.settings().should('be.visible'); + mainSidebar.actions.goToSettings(); + cy.url().should('include', settingsUsersPage.url); + + settingsUsersPage.actions.goToOwnerSetup(); + + cy.url().should('include', signupPage.url); + }); + + describe('should be able to setup instance and migrate workflows and credentials', () => { + cy.signup(username, firstName, lastName, password); + + messageBox.getters.content().should('contain.text', '1 existing workflow and 1 credential') + + messageBox.actions.confirm(); + }); + + describe('should be redirected back to users page after setup', () => { + cy.url().should('include', settingsUsersPage.url); + // todo test users and that owner exist + }); + + describe('can click back to workflows and have migrated workflow after setup', () => { + settingsSidebar.actions.back(); + + cy.url().should('include', workflowsPage.url); + + workflowsPage.getters.workflowCards().should('have.length', 1); + }); + + describe('can click back to main menu and have migrated credential after setup', () => { + mainSidebar.actions.goToCredentials(); + + cy.url().should('include', workflowsPage.url); + + workflowsPage.getters.workflowCards().should('have.length', 1); + }); + }); }); + diff --git a/cypress/pages/index.ts b/cypress/pages/index.ts index 17a3e0efffb06..0cea524db6343 100644 --- a/cypress/pages/index.ts +++ b/cypress/pages/index.ts @@ -3,4 +3,6 @@ export * from './credentials'; export * from './signin'; export * from './signup'; export * from './workflows'; +export * from './workflow'; export * from './modals'; +export * from './settings-users'; diff --git a/cypress/pages/modals/credentials-modal.ts b/cypress/pages/modals/credentials-modal.ts index d7d45f2262cb0..92d3aaa871d6c 100644 --- a/cypress/pages/modals/credentials-modal.ts +++ b/cypress/pages/modals/credentials-modal.ts @@ -6,13 +6,15 @@ export class CredentialsModal extends BasePage { newCredentialTypeSelect: () => cy.getByTestId('new-credential-type-select'), newCredentialTypeOption: (credentialType: string) => cy.getByTestId('new-credential-type-select-option').contains(credentialType), newCredentialTypeButton: () => cy.getByTestId('new-credential-type-button'), + editCredentialModal: () => cy.getByTestId('editCredential-modal', { timeout: 5000 }), 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'), name: () => cy.getByTestId('credential-name'), nameInput: () => cy.getByTestId('credential-name').find('input'), - saveButton: () => cy.getByTestId('credential-save-button') + saveButton: () => cy.getByTestId('credential-save-button'), + closeButton: () => this.getters.editCredentialModal().find('.el-dialog__close'), }; actions = { setName: (name: string) => { @@ -21,6 +23,9 @@ export class CredentialsModal extends BasePage { }, save: () => { this.getters.saveButton().click(); - } + }, + close: () => { + this.getters.closeButton().click(); + }, }; } diff --git a/cypress/pages/modals/index.ts b/cypress/pages/modals/index.ts index aaa7d6d707016..24f5101aed2df 100644 --- a/cypress/pages/modals/index.ts +++ b/cypress/pages/modals/index.ts @@ -1 +1,2 @@ export * from './credentials-modal'; +export * from './message-box'; diff --git a/cypress/pages/modals/message-box.ts b/cypress/pages/modals/message-box.ts index 55f76cd9fd026..388fc00cadbaf 100644 --- a/cypress/pages/modals/message-box.ts +++ b/cypress/pages/modals/message-box.ts @@ -4,6 +4,7 @@ export class MessageBox extends BasePage { getters = { modal: () => cy.get('.el-message-box', { withinSubject: null }), header: () => this.getters.modal().find('.el-message-box__title'), + content: () => this.getters.modal().find('.el-message-box__content'), confirm: () => this.getters.modal().find('.btn--confirm'), cancel: () => this.getters.modal().find('.btn--cancel'), }; diff --git a/cypress/pages/settings-users.ts b/cypress/pages/settings-users.ts new file mode 100644 index 0000000000000..e75282163ffcc --- /dev/null +++ b/cypress/pages/settings-users.ts @@ -0,0 +1,11 @@ +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(), + } +} diff --git a/cypress/pages/sidebar/index.ts b/cypress/pages/sidebar/index.ts new file mode 100644 index 0000000000000..3bfa6a680155d --- /dev/null +++ b/cypress/pages/sidebar/index.ts @@ -0,0 +1,2 @@ +export * from './main-sidebar'; +export * from './settings-sidebar'; diff --git a/cypress/pages/sidebar/main-sidebar.ts b/cypress/pages/sidebar/main-sidebar.ts new file mode 100644 index 0000000000000..85e853627a5f0 --- /dev/null +++ b/cypress/pages/sidebar/main-sidebar.ts @@ -0,0 +1,15 @@ +import { BasePage } from "../base"; + +export class MainSidebar extends BasePage { + getters = { + settings: () => cy.getByTestId('menu-item-settings', { timeout: 5000 }), + templates: () => cy.getByTestId('menu-item-templates'), + workflows: () => cy.getByTestId('menu-item-workflows'), + credentials: () => cy.getByTestId('menu-item-credentials'), + executions: () => cy.getByTestId('menu-item-executions'), + }; + actions = { + goToSettings: () => this.getters.settings().click(), + goToCredentials: () => this.getters.credentials().click(), + }; +} diff --git a/cypress/pages/sidebar/settings-sidebar.ts b/cypress/pages/sidebar/settings-sidebar.ts new file mode 100644 index 0000000000000..41d87598e3245 --- /dev/null +++ b/cypress/pages/sidebar/settings-sidebar.ts @@ -0,0 +1,14 @@ +import { BasePage } from "../base"; + +export class SettingsSidebar extends BasePage { + getters = { + personal: () => cy.getByTestId('menu-item-settings-personal'), + users: () => cy.getByTestId('menu-item-settings-users'), + api: () => cy.getByTestId('menu-item-settings-api'), + communityNodes: () => cy.getByTestId('menu-item-settings-community-nodes'), + back: () => cy.getByTestId('settings-back'), + }; + actions = { + back: () => this.getters.back().click(), + }; +} diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index 2a9615cdcae09..538a4086aacd8 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -3,7 +3,7 @@ import { BasePage } from "./base"; export class WorkflowPage extends BasePage { url = '/workflow/new'; getters = { - workflowNameInput: () => cy.getByTestId('workflow-name-input').then($el => cy.wrap($el.find('input'))), + workflowNameInput: () => cy.getByTestId('workflow-name-input', { timeout: 5000 }).then($el => cy.wrap($el.find('input'))), workflowImportInput: () => cy.getByTestId('workflow-import-input'), workflowTags: () => cy.getByTestId('workflow-tags'), saveButton: () => cy.getByTestId('save-button'), diff --git a/packages/cli/src/databases/entities/Role.ts b/packages/cli/src/databases/entities/Role.ts index ec6831916b38c..49851d30b193a 100644 --- a/packages/cli/src/databases/entities/Role.ts +++ b/packages/cli/src/databases/entities/Role.ts @@ -6,8 +6,8 @@ import { SharedWorkflow } from './SharedWorkflow'; import { SharedCredentials } from './SharedCredentials'; import { AbstractEntity } from './AbstractEntity'; -type RoleNames = 'owner' | 'member' | 'user' | 'editor'; -type RoleScopes = 'global' | 'workflow' | 'credential'; +export type RoleNames = 'owner' | 'member' | 'user' | 'editor'; +export type RoleScopes = 'global' | 'workflow' | 'credential'; @Entity() @Unique(['scope', 'name']) diff --git a/packages/design-system/src/components/N8nActionBox/ActionBox.vue b/packages/design-system/src/components/N8nActionBox/ActionBox.vue index a2233d83fd361..aa5004e13253e 100644 --- a/packages/design-system/src/components/N8nActionBox/ActionBox.vue +++ b/packages/design-system/src/components/N8nActionBox/ActionBox.vue @@ -1,5 +1,5 @@