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

test: Add more tests for workflow/credential migrations when enabling UM #4719

Merged
merged 9 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
17 changes: 16 additions & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
const fetch = require('node-fetch');
const { defineConfig } = require('cypress');

const baseUrl = 'http://localhost:5678';

module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:5678',
baseUrl,
video: false,
screenshotOnRunFailure: true,
experimentalSessionAndOrigin: true,
experimentalInteractiveRunEvents: true,

setupNodeEvents(on) {
on('task', {
'db:reset': () => fetch(baseUrl + '/e2e/db/reset', { method: 'POST' }),
'db:setup-owner': (payload) =>
fetch(baseUrl + '/e2e/db/setup-owner', {
method: 'POST',
body: JSON.stringify(payload),
headers: { 'Content-Type': 'application/json' },
}),
});
},
},
});
17 changes: 11 additions & 6 deletions cypress/e2e/0-smoke.cy.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
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 username = DEFAULT_USER_EMAIL;
const email = DEFAULT_USER_EMAIL;
const password = DEFAULT_USER_PASSWORD;
const firstName = randFirstName();
const lastName = randLastName();

describe('Authentication', () => {
beforeEach(() => {
cy.task('db:reset');
});

it('should setup owner', () => {
cy.signup(username, firstName, lastName, password);
cy.signup(email, firstName, lastName, password);
});

it('should sign user in', () => {
cy.task('db:setup-owner', { email, password, firstName, lastName });
cy.on('uncaught:exception', (err, runnable) => {
expect(err.message).to.include('Not logged in');

return false;
})
});

cy.signin(username, password);
cy.signin(email, password);
});
});
118 changes: 112 additions & 6 deletions cypress/e2e/3-default-owner.cy.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
OlegIvaniv marked this conversation as resolved.
Show resolved Hide resolved
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);
});
});
});

2 changes: 2 additions & 0 deletions cypress/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
9 changes: 7 additions & 2 deletions cypress/pages/modals/credentials-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -21,6 +23,9 @@ export class CredentialsModal extends BasePage {
},
save: () => {
this.getters.saveButton().click();
}
},
close: () => {
this.getters.closeButton().click();
},
};
}
1 change: 1 addition & 0 deletions cypress/pages/modals/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './credentials-modal';
export * from './message-box';
1 change: 1 addition & 0 deletions cypress/pages/modals/message-box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
};
Expand Down
11 changes: 11 additions & 0 deletions cypress/pages/settings-users.ts
Original file line number Diff line number Diff line change
@@ -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(),
}
}
2 changes: 2 additions & 0 deletions cypress/pages/sidebar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './main-sidebar';
export * from './settings-sidebar';
15 changes: 15 additions & 0 deletions cypress/pages/sidebar/main-sidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BasePage } from "../base";

export class MainSidebar extends BasePage {
getters = {
settings: () => cy.getByTestId('menuitem-settings', { timeout: 5000 }),
templates: () => cy.getByTestId('menuitem-templates'),
workflows: () => cy.getByTestId('menuitem-workflows'),
credentials: () => cy.getByTestId('menuitem-credentials'),
executions: () => cy.getByTestId('menuitem-executions'),
OlegIvaniv marked this conversation as resolved.
Show resolved Hide resolved
};
actions = {
goToSettings: () => this.getters.settings().click(),
goToCredentials: () => this.getters.credentials().click(),
};
}
14 changes: 14 additions & 0 deletions cypress/pages/sidebar/settings-sidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { BasePage } from "../base";

export class SettingsSidebar extends BasePage {
getters = {
personal: () => cy.getByTestId('menuitem-settings-personal'),
users: () => cy.getByTestId('menuitem-settings-users'),
api: () => cy.getByTestId('menuitem-settings-api'),
communityNodes: () => cy.getByTestId('menuitem-settings-community-nodes'),
back: () => cy.getByTestId('settings-back'),
};
actions = {
back: () => this.getters.back().click(),
};
}
2 changes: 1 addition & 1 deletion cypress/pages/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"webhook": "./packages/cli/bin/n8n webhook",
"worker": "./packages/cli/bin/n8n worker",
"cypress:install": "cypress install",
"test:e2e:ui": "cross-env E2E_TESTS=true CYPRESS_BASE_URL=http://localhost:5678 start-server-and-test start http://localhost:5678/favicon.ico 'cypress open'",
"test:e2e:ui": "cross-env E2E_TESTS=true start-server-and-test start http://localhost:5678/favicon.ico 'cypress open'",
"test:e2e:dev": "cross-env E2E_TESTS=true CYPRESS_BASE_URL=http://localhost:8080 start-server-and-test dev http://localhost:8080/favicon.ico 'cypress open'",
"test:e2e:smoke": "cross-env E2E_TESTS=true start-server-and-test start http://localhost:5678/favicon.ico 'cypress run --headless --spec \"cypress/e2e/0-smoke.cy.ts\"'",
"test:e2e:all": "cross-env E2E_TESTS=true start-server-and-test start http://localhost:5678/favicon.ico 'cypress run'"
Expand All @@ -42,6 +42,7 @@
"@types/node": "^16.11.22",
"cross-env": "^7.0.3",
"cypress": "^10.0.3",
"node-fetch": "^2.6.7",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"jest-mock": "^29.3.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/Db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
export let isInitialized = false;
export const collections = {} as IDatabaseCollections;

let connection: Connection;
export let connection: Connection;

export async function transaction<T>(fn: (entityManager: EntityManager) => Promise<T>): Promise<T> {
return connection.transaction(fn);
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ class App {

setupErrorMiddleware(this.app);

if (process.env.E2E_TESTS === 'true') {
this.app.use('/e2e', require('./api/e2e.api').e2eController);
}

const urlBaseWebhook = WebhookHelpers.getWebhookBaseUrl();
const telemetrySettings: ITelemetrySettings = {
enabled: config.getEnv('diagnostics.enabled'),
Expand Down Expand Up @@ -431,6 +435,7 @@ class App {
'metrics',
'icons',
'types',
'e2e',
this.endpointWebhook,
this.endpointWebhookTest,
this.endpointPresetCredentials,
Expand Down
Loading