diff --git a/cypress/utils/dashboards/commands.js b/cypress/utils/dashboards/commands.js new file mode 100644 index 000000000000..879385c32670 --- /dev/null +++ b/cypress/utils/dashboards/commands.js @@ -0,0 +1,106 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +Cypress.Commands.add('selectFromDataSourceSelector', (dataSourceTitle, dataSourceId) => { + // clean up the input field + cy.wait(1000); + cy.getElementByTestId('dataSourceSelectorComboBox').find('input').type(`{selectall}{backspace}`); + cy.waitForLoader(); + cy.getElementByTestId('dataSourceSelectorComboBox').should('have.attr', 'aria-expanded', 'false'); + cy.getElementByTestId('dataSourceSelectorComboBox') + .find(`button[data-test-subj="comboBoxToggleListButton"]`) + .then(($element) => { + if ($element.attr('aria-label') === 'Open list of options') { + $element.click(); + } + }); + cy.getElementByTestId('dataSourceSelectorComboBox').should('have.attr', 'aria-expanded', 'true'); + if (dataSourceId) { + cy.get(`#${dataSourceId}`).should('be.visible').trigger('click'); + } else if (dataSourceTitle) { + cy.get(`.euiFilterSelectItem[title="${dataSourceTitle}"]`) + .should('be.visible') + .trigger('click'); + } + cy.waitForLoader(); +}); + +Cypress.Commands.add( + 'selectFromDataSourceSelectorFromStandardPageHeader', + (dataSourceTitle, dataSourceId) => { + // clean up the input field + cy.wait(1000); + cy.getElementByTestId('dataSourceSelectableButton').click(); + cy.getElementByTestId('dataSourceSelectable').find('input').type(`{selectall}{backspace}`); + cy.waitForLoader(); + if (dataSourceId) { + cy.get(`#${dataSourceId}`).should('be.visible').trigger('click'); + } else if (dataSourceTitle) { + cy.get(`.euiSelectableListItem[title="${dataSourceTitle}"]`) + .should('be.visible') + .trigger('click'); + } + cy.waitForLoader(); + } +); + +Cypress.Commands.add( + // navigates to the workspace HomePage of a given workspace + 'navigateToWorkSpaceHomePage', + (url, workspaceName) => { + // Selecting the correct workspace + cy.visit(`${url}/app/workspace_list#`); + cy.openWorkspaceDashboard(workspaceName); + } +); + +Cypress.Commands.add( + //navigate to workspace specific pages + 'navigateToWorkSpaceSpecificPage', + (url, workspaceName, page) => { + // Navigating to the WorkSpace Home Page + cy.navigateToWorkSpaceHomePage(url, workspaceName); + + // Opening the side panel + cy.getElementByTestId('toggleNavButton').then((ele) => { + if (ele.length > 0) { + ele.first().click(); + } + }); + + cy.getElementByTestId(`collapsibleNavAppLink-${page}`).click(); + + cy.waitForLoader(); + } +); + +Cypress.Commands.add( + // creates an index pattern within the workspace + // Don't use * in the indexPattern it adds it by default at the end of name + 'createWorkspaceIndexPatterns', + (url, workspaceName, indexPattern, dataSource, timefieldName = '') => { + // Navigate to Workspace Specific IndexPattern Page + cy.navigateToWorkSpaceSpecificPage(url, workspaceName, 'indexPatterns'); + + cy.getElementByTestId('createIndexPatternButton').click({ force: true }); + + cy.get('[type="data-source"]').contains(dataSource).click(); + cy.getElementByTestId('createIndexPatternStepDataSourceNextStepButton').click(); + + cy.wait(1000); // Intentional Wait + + cy.getElementByTestId('createIndexPatternNameInput').clear().type(indexPattern); + cy.getElementByTestId('createIndexPatternGoToStep2Button').click(); + + if (timefieldName !== '') { + cy.getElementByTestId('createIndexPatternTimeFieldSelect').select(timefieldName); + } else { + cy.getElementByTestId('createIndexPatternTimeFieldSelect').select( + "I don't want to use the time filter" + ); + } + cy.getElementByTestId('createIndexPatternButton').click(); + } +); diff --git a/cypress/utils/dashboards/remove_workspace.js b/cypress/utils/dashboards/remove_workspace.js new file mode 100644 index 000000000000..89b7191b42dc --- /dev/null +++ b/cypress/utils/dashboards/remove_workspace.js @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export function removeSampleDataAndWorkspace(url, workspaceName) { + describe('removing workspace/sampledata', () => { + it('remove workspace', () => { + cy.visit(`${url}/app/workspace_list`); + cy.openWorkspaceDashboard(workspaceName); + cy.getElementByTestId('toggleNavButton').eq(0).should('exist').click(); + cy.wait(3000); + cy.getElementByTestId('collapsibleNavAppLink-workspace_detail').should('exist').click(); + cy.deleteWorkspace(workspaceName); + }); + }); +} diff --git a/cypress/utils/dashboards/setup_workspace.js b/cypress/utils/dashboards/setup_workspace.js new file mode 100644 index 000000000000..91fffe2cbf75 --- /dev/null +++ b/cypress/utils/dashboards/setup_workspace.js @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +const dataSourceTitle = Cypress.env('dataSourceTitle'); + +export function createWorkspaceAndSampleData(url, workspaceName) { + describe('checking home page', () => { + it('checking workspace initial page', () => { + cy.visit(`${url}/app/home`); + cy.getElementByTestId('workspace-initial-card-createWorkspace-button').should('be.visible'); + }); + }); + + describe('creating workspace', () => { + it('creating workspace with data source', () => { + cy.visit(`${url}/app/home`); + cy.createInitialWorkspaceWithDataSource(dataSourceTitle, workspaceName); + cy.wait(2000); + }); + }); + + describe('adding sample data to workspace', () => { + it('add sample data to data source', () => { + cy.visit(`${url}/app/workspace_list`); + cy.openWorkspaceDashboard(workspaceName); + cy.openSampleDataPage(); + cy.addSampleDataToDataSource(dataSourceTitle); + }); + }); +} diff --git a/cypress/utils/dashboards/workspace-plugin/commands.js b/cypress/utils/dashboards/workspace-plugin/commands.js new file mode 100644 index 000000000000..648b3119db88 --- /dev/null +++ b/cypress/utils/dashboards/workspace-plugin/commands.js @@ -0,0 +1,185 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { WORKSPACE_API_PREFIX } from './constants'; + +const BASE_PATH = Cypress.config('baseUrl'); + +Cypress.Commands.add('deleteWorkspaceById', (workspaceId) => { + cy.request({ + method: 'DELETE', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}/${workspaceId}`, + headers: { + 'osd-xsrf': true, + }, + }); +}); + +Cypress.Commands.add('deleteWorkspaceByName', (workspaceName) => { + cy.request({ + method: 'POST', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}/_list`, + headers: { + 'osd-xsrf': true, + }, + body: {}, + }).then((resp) => { + if (resp && resp.body && resp.body.success) { + resp.body.result.workspaces.map(({ name, id }) => { + if (workspaceName === name) { + cy.request({ + method: 'DELETE', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}/${id}`, + headers: { + 'osd-xsrf': true, + }, + }); + } + }); + } + }); +}); + +Cypress.Commands.add('createWorkspace', ({ settings, ...workspace } = {}) => { + return cy + .request({ + method: 'POST', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}`, + headers: { + 'osd-xsrf': true, + }, + body: { + attributes: { + ...workspace, + features: workspace.features || ['use-case-all'], + description: workspace.description || 'test_description', + }, + settings, + }, + }) + .then((resp) => { + if (resp && resp.body && resp.body.success) { + return resp.body.result.id; + } else { + throw new Error(`Create workspace ${workspace.name} failed!`); + } + }); +}); + +/** + * Check whether the given workspace is equal to the expected workspace or not, + * the given workspace is as exepcted when the name, description, features, and permissions are as expected. + */ +Cypress.Commands.add('checkWorkspace', (workspaceId, expected) => { + cy.request({ + method: 'GET', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}/${workspaceId}`, + }).then((resp) => { + if (resp && resp.body && resp.body.success) { + const { name, description, features, permissions } = resp.body.result; + if (name !== expected.name) { + throw new Error( + `workspace ${workspaceId} is not as expected, expected name is ${expected.name}, but is ${name}` + ); + } + if (description !== expected.description) { + throw new Error( + `workspace ${workspaceId} is not as expected, expected description is ${expected.description}, but is ${description}` + ); + } + + if (features && expected.features) { + const expectedFeatures = JSON.stringify(expected.features); + const actualFeatures = JSON.stringify(features); + if (features.length !== expected.features.length) { + throw new Error( + `workspace ${workspaceId} is not as expected, expected features are: ${expectedFeatures}, but are: ${actualFeatures}` + ); + } + expected.features.forEach((feature) => { + if (!features.includes(feature)) { + throw new Error( + `workspace ${workspaceId} is not as expected because the feature ${feature} is missing, expected features are: ${expectedFeatures}, but are: ${actualFeatures}` + ); + } + }); + } + + if (permissions && expected.permissions) { + const expectedPermissions = JSON.stringify(expected.permissions); + const actualPermissions = JSON.stringify(permissions); + if (Object.keys(permissions).length !== Object.keys(expected.permissions).length) { + throw new Error( + `permissions for workspace ${workspaceId} is not as expected, expected permissions are: ${expectedPermissions}, but are: ${actualPermissions}` + ); + } + + Object.entries(permissions).forEach(([key, value]) => { + if (!expected.permissions[key]) { + throw new Error( + `permissions for workspace ${workspaceId} is not as expected because the permission ${key} is missing, expected permissions are: ${expectedPermissions}, but are ${actualPermissions}` + ); + } else { + if ( + expected.permissions[key].users && + !checkPrincipalArrayEquals(expected.permissions[key].users, value.users) + ) { + throw new Error( + `permissions for workspace ${workspaceId} is not as expected, expected permissions are: ${expectedPermissions}, but are ${actualPermissions}` + ); + } + + if ( + expected.permissions[key].groups && + !checkPrincipalArrayEquals(expected.permissions[key].groups, value.groups) + ) { + throw new Error( + `permissions for workspace ${workspaceId} is not as expected, expected permissions are: ${expectedPermissions}, but are ${actualPermissions}` + ); + } + } + }); + } + } else { + throw new Error(`cannot find workspace ${workspaceId}`); + } + }); +}); + +function checkPrincipalArrayEquals(expectedPrincipals, actualPrincipals) { + if (expectedPrincipals.length !== actualPrincipals.length) { + return false; + } + + expectedPrincipals.forEach((principal) => { + if (!actualPrincipals.includes(principal)) { + return false; + } + }); + return true; +} + +Cypress.Commands.add('deleteAllWorkspaces', () => { + cy.request({ + method: 'POST', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}/_list`, + headers: { + 'osd-xsrf': true, + }, + body: {}, + }).then((resp) => { + if (resp && resp.body && resp.body.success) { + resp.body.result.workspaces.forEach(({ id }) => { + cy.request({ + method: 'DELETE', + url: `${BASE_PATH}${WORKSPACE_API_PREFIX}/${id}`, + headers: { + 'osd-xsrf': true, + }, + }); + }); + } + }); +}); diff --git a/cypress/utils/dashboards/workspace-plugin/constants.js b/cypress/utils/dashboards/workspace-plugin/constants.js new file mode 100644 index 000000000000..764f778bc6e0 --- /dev/null +++ b/cypress/utils/dashboards/workspace-plugin/constants.js @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const WORKSPACE_API_PREFIX = '/api/workspaces';