diff --git a/console/cypress/helpers/common.ts b/console/cypress/helpers/common.ts index f0aa600c96b..2c06991edda 100644 --- a/console/cypress/helpers/common.ts +++ b/console/cypress/helpers/common.ts @@ -17,3 +17,11 @@ export const setPromptValue = (value: string | null) => { /* eslint-disable-next-line cypress/no-unnecessary-waiting */ cy.wait(7000); }; + +// This is works as setPromptValue with no unnecessary waiting +export const setPromptWithCb = (value: string | null, cb: () => void) => { + cy.window().then(win => { + cy.stub(win, 'prompt').returns(value); + cb(); + }); +}; diff --git a/console/cypress/integration/data/manage-database/spec.ts b/console/cypress/integration/data/manage-database/spec.ts new file mode 100644 index 00000000000..cfbfa7233ac --- /dev/null +++ b/console/cypress/integration/data/manage-database/spec.ts @@ -0,0 +1,119 @@ +import { setPromptWithCb } from '../../../helpers/common'; +import { baseUrl } from '../../../helpers/dataHelpers'; + +const config = { + host: 'localhost', + port: '5432', + dbName: 'gql_test', + username: 'gql_test', + password: '', +}; +const dbUrl = `postgres://${config.username}:${config.password}@${config.host}:${config.port}/${config.dbName}`; + +export const openManageDatabases = () => { + cy.getBySel('sidebar-manage-database').click(); + cy.url().should('eq', `${baseUrl}/data/manage`); +}; + +export const expandAddDatabaseForm = () => { + cy.get('button').contains('Connect Database').click(); + cy.url().should('eq', `${baseUrl}/data/manage/connect`); +}; + +export const expandConnectionSettingsform = () => { + cy.get('a').contains('Connection Settings').click(); +}; + +export const failsOnEmptyFormSubmission = () => { + cy.getBySel('save-database').click(); + cy.get('.notification-error').should('be.visible'); +}; + +export const addsNewPostgresDatabaseWithUrl = () => { + cy.getBySel('database-display-name').type('testDB1'); + cy.getBySel('database-type').select('postgres'); + cy.getBySel('database-url').type(dbUrl); + cy.getBySel('max-connections').type('50'); + cy.getBySel('idle-timeout').type('180'); + cy.getBySel('retries').type('1'); + cy.getBySel('save-database').click(); + cy.get('.notification-success') + .should('be.visible') + .and('contain', 'Database added successfully!'); + cy.url().should('eq', `${baseUrl}/data/manage`); +}; + +export const addsNewPgDBWithConParams = () => { + cy.getBySel('sidebar-manage-database').click(); + cy.get('button').contains('Connect Database').click(); + cy.get("input[type='radio']").eq(0).click(); + cy.getBySel('database-display-name').type('testDB2'); + cy.getBySel('database-type').select('postgres'); + cy.getBySel('host').type(config.host); + cy.getBySel('port').type(config.port); + cy.getBySel('username').type(config.username); + if (config.password) { + cy.getBySel('password').type(config.password); + } + cy.getBySel('database-name').type(config.dbName); + cy.getBySel('save-database').click(); + cy.get('.notification-success') + .should('be.visible') + .and('contain', 'Database added successfully!'); + cy.url().should('eq', `${baseUrl}/data/manage`); +}; + +export const addsNewPgDBWithEnvVar = () => { + cy.getBySel('sidebar-manage-database').click(); + cy.get('button').contains('Connect Database').click(); + cy.get("input[type='radio']").eq(2).click(); + cy.getBySel('database-display-name').type('testDB3'); + cy.getBySel('database-type').select('postgres'); + cy.getBySel('database-url-env').type('HASURA_GRAPHQL_DATABASE_URL'); + cy.getBySel('save-database').click(); + cy.get('.notification-success') + .should('be.visible') + .and('contain', 'Database added successfully!'); + cy.url().should('eq', `${baseUrl}/data/manage`); +}; + +export const failDuplicateNameDb = () => { + cy.getBySel('sidebar-manage-database').click(); + cy.get('button').contains('Connect Database').click(); + cy.getBySel('database-display-name').type('testDB1'); + cy.getBySel('database-url').type(dbUrl); + cy.getBySel('save-database').click(); + cy.get('.notification-error') + .should('be.visible') + .and('contain', 'Add data source failed') + .and('contain', 'source with name "testDB1" already exists'); +}; + +export const deleteTestDBWithUrl = () => { + cy.getBySel('sidebar-manage-database').click(); + setPromptWithCb('testDB1', () => { + cy.getBySel('testDB1').find('button').contains('Remove').click(); + cy.get('.notification-success') + .should('be.visible') + .and('contain', 'Data source removed successfully!'); + cy.window().its('prompt').should('be.called'); + }); +}; +export const deleteTestDBWithConParams = () => { + setPromptWithCb('testDB2', () => { + cy.getBySel('testDB2').find('button').contains('Remove').click(); + cy.get('.notification-success') + .should('be.visible') + .and('contain', 'Data source removed successfully!'); + cy.window().its('prompt').should('be.called'); + }); +}; +export const deleteTestDDWithEnvVar = () => { + setPromptWithCb('testDB3', () => { + cy.getBySel('testDB3').find('button').contains('Remove').click(); + cy.get('.notification-success') + .should('be.visible') + .and('contain', 'Data source removed successfully!'); + cy.window().its('prompt').should('be.called'); + }); +}; diff --git a/console/cypress/integration/data/manage-database/test.ts b/console/cypress/integration/data/manage-database/test.ts new file mode 100644 index 00000000000..4d88355e3e3 --- /dev/null +++ b/console/cypress/integration/data/manage-database/test.ts @@ -0,0 +1,60 @@ +import { setMetaData } from '../../validators/validators'; +import { getIndexRoute } from '../../../helpers/dataHelpers'; +import { + openManageDatabases, + expandAddDatabaseForm, + expandConnectionSettingsform, + failsOnEmptyFormSubmission, + addsNewPostgresDatabaseWithUrl, + failDuplicateNameDb, + addsNewPgDBWithConParams, + addsNewPgDBWithEnvVar, + deleteTestDBWithUrl, + deleteTestDBWithConParams, + deleteTestDDWithEnvVar, +} from './spec'; +import { testMode } from '../../../helpers/common'; + +const setup = () => { + describe('Setup route', () => { + it('Visit the index route', () => { + cy.visit(getIndexRoute()).then(setMetaData); + }); + }); +}; + +export const runManageDatabaseTests = () => { + describe('Manage Data sources Tests', () => { + it('Opens Manage Database route', openManageDatabases); + it('Opens Add database form', expandAddDatabaseForm); + it('Expands Connection settings form', expandConnectionSettingsform); + it('Fails on empty form submission', failsOnEmptyFormSubmission); + it( + 'Successfully creates a new postgres database with database url', + addsNewPostgresDatabaseWithUrl + ); + it( + 'Successfully creates a new postgres database with connection parameters', + addsNewPgDBWithConParams + ); + it( + 'Successfully creates a new postgres database with env variable ', + addsNewPgDBWithEnvVar + ); + it('Fails to connect db with duplicate name', failDuplicateNameDb); + it('Successfully deletes test DB added with URL', deleteTestDBWithUrl); + it( + 'Successfully deletes test DB added with connection params', + deleteTestDBWithConParams + ); + it( + 'Successfully deletes test DB added with env variable', + deleteTestDDWithEnvVar + ); + }); +}; + +if (testMode !== 'cli') { + setup(); + runManageDatabaseTests(); +} diff --git a/console/cypress/support/commands.ts b/console/cypress/support/commands.ts index c1f5a772e2b..a02267f1067 100644 --- a/console/cypress/support/commands.ts +++ b/console/cypress/support/commands.ts @@ -23,3 +23,11 @@ // // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +Cypress.Commands.add('getBySel', (selector, ...args) => { + return cy.get(`[data-test=${selector}]`, ...args); +}); + +Cypress.Commands.add('getBySelLike', (selector, ...args) => { + return cy.get(`[data-test*=${selector}]`, ...args); +}); diff --git a/console/cypress/support/index.d.ts b/console/cypress/support/index.d.ts index fbe43448779..fdcd3819db5 100644 --- a/console/cypress/support/index.d.ts +++ b/console/cypress/support/index.d.ts @@ -1,4 +1,17 @@ // type definition for all custom commands declare namespace Cypress { - interface Chainable {} + interface Chainable { + /** + * Custom command to select DOM element by data-test attribute. + * + * @example cy.getBySel('greeting') + */ + getBySel(value: string): Chainable; + /** + * Custom command to select DOM element by data-test* attribute. + * + * @example cy.getBySelLike('save_me') + */ + getBySelLike(value: string): Chainable; + } } diff --git a/console/src/components/Services/Data/DataSources/ConnectDatabase.tsx b/console/src/components/Services/Data/DataSources/ConnectDatabase.tsx index 9b78b7d688d..1079467483e 100644 --- a/console/src/components/Services/Data/DataSources/ConnectDatabase.tsx +++ b/console/src/components/Services/Data/DataSources/ConnectDatabase.tsx @@ -257,6 +257,7 @@ const ConnectDatabase: React.FC = props => { value={connectDBInputState.displayName} label="Database Display Name" placeholder="database name" + data-test="database-display-name" />