Skip to content
19 changes: 1 addition & 18 deletions ui/apps/platform/cypress/constants/apiEndpoints.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const graphql = (operationName) => `/api/graphql?opname=${operationName}`;
export const graphql = (opname) => `/api/graphql?opname=${opname}`;

function searchObjToQuery(searchObj) {
let result = '';
Expand Down Expand Up @@ -84,7 +84,6 @@ export const auth = {
loginAuthProviders: '/v1/login/authproviders',
authProviders: '/v1/authProviders',
authStatus: '/v1/auth/status',
logout: '/sso/session/logout',
tokenRefresh: '/sso/session/tokenrefresh',
};

Expand All @@ -99,7 +98,6 @@ export const network = {
networkBaselineLock: '/v1/networkbaseline/*/lock',
networkBaselineUnlock: '/v1/networkbaseline/*/unlock',
networkBaselinePeers: '/v1/networkbaseline/*/peers',
networkBaselineStatus: '/v1/networkbaseline/*/status',
networkPoliciesGraph: '/v1/networkpolicies/cluster/*',
networkGraph: '/v1/networkgraph/cluster/*',
epoch: '/v1/networkpolicies/graph/epoch',
Expand Down Expand Up @@ -139,21 +137,6 @@ export const userAttributes = {
list: '/v1/userattributes/*',
};

const complianceEntitiesOp = {
clusters: 'clustersList',
deployments: 'deploymentsList',
namespaces: 'namespaceList', // singular: too bad, so sad
nodes: 'nodesList',
};

export const compliance = {
// For example, graphqlEntities('clusters')
graphqlEntities: (key) => graphql(complianceEntitiesOp[key]),
export: {
csv: '/api/compliance/export/csv',
},
};

export const logs = '/api/logimbue';

export const featureFlags = '/v1/featureflags';
Expand Down
13 changes: 5 additions & 8 deletions ui/apps/platform/cypress/helpers/clusters.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,20 @@ const routeMatcherMap = {
* For example, click View All button from System Health.
*/
export function reachClusters(interactionCallback, staticResponseMap) {
interactAndWaitForResponses(interactionCallback, { routeMatcherMap }, staticResponseMap);
interactAndWaitForResponses(interactionCallback, routeMatcherMap, staticResponseMap);

cy.get(selectors.clustersListHeading).contains('Clusters');
}

export function visitClustersFromLeftNav() {
visitFromLeftNavExpandable('Platform Configuration', 'Clusters', { routeMatcherMap });
visitFromLeftNavExpandable('Platform Configuration', 'Clusters', routeMatcherMap);

cy.location('pathname').should('eq', clustersUrl);
cy.get(selectors.clustersListHeading).contains('Clusters');
}

export function visitClusters(staticResponseMap) {
visit(clustersUrl, { routeMatcherMap }, staticResponseMap);
visit(clustersUrl, routeMatcherMap, staticResponseMap);

cy.get(selectors.clustersListHeading).contains('Clusters');
}
Expand All @@ -61,11 +62,7 @@ export function visitClusterById(clusterId, staticResponseMap) {
url: `${api.clusters.list}/${clusterId}`,
},
};
visit(
`${clustersUrl}/${clusterId}`,
{ routeMatcherMap: routeMatcherMapClusterById },
staticResponseMap
);
visit(`${clustersUrl}/${clusterId}`, routeMatcherMapClusterById, staticResponseMap);

cy.get(selectors.clustersListHeading).contains('Clusters');
}
Expand Down
22 changes: 10 additions & 12 deletions ui/apps/platform/cypress/helpers/collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,21 @@ const basePath = '/main/collections';
export const collectionsAlias = 'collections';
export const collectionsCountAlias = 'collections/count';

const requestConfigForCollections = {
routeMatcherMap: {
[collectionsAlias]: {
method: 'GET',
url: '/v1/collections?query.query=*',
},
[collectionsCountAlias]: {
method: 'GET',
url: '/v1/collectionscount?query.query=*',
},
const routeMatcherMapForCollections = {
[collectionsAlias]: {
method: 'GET',
url: '/v1/collections?query.query=*',
},
[collectionsCountAlias]: {
method: 'GET',
url: '/v1/collectionscount?query.query=*',
},
};

// visit

export function visitCollections(staticResponseMap) {
visit(basePath, requestConfigForCollections, staticResponseMap);
visit(basePath, routeMatcherMapForCollections, staticResponseMap);

cy.get('h1:contains("Collections")');
cy.get(`${navSelectors.navExpandable}:contains("Platform Configuration")`);
Expand All @@ -38,7 +36,7 @@ export function visitCollectionsFromLeftNav(staticResponseMap) {
visitFromLeftNavExpandable(
'Platform Configuration',
'Collections',
requestConfigForCollections,
routeMatcherMapForCollections,
staticResponseMap
);

Expand Down
59 changes: 31 additions & 28 deletions ui/apps/platform/cypress/helpers/compliance.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import * as api from '../constants/apiEndpoints';
import { headingPlural, selectors, url } from '../constants/CompliancePage';

import { interceptRequests, waitForResponses } from './request';
import { getRouteMatcherMapForGraphQL, interactAndWaitForResponses } from './request';
import { visit } from './visit';

const routeMatcherMap = {};
[
const routeMatcherMapForComplianceDashboard = getRouteMatcherMapForGraphQL([
'clustersCount',
'namespacesCount',
'nodesCount',
Expand All @@ -22,17 +20,10 @@ const routeMatcherMap = {};
'complianceStandards_NIST_800_190',
'complianceStandards_NIST_SP_800_53_Rev_4',
'complianceStandards_PCI_DSS_3_2',
].forEach((opname) => {
routeMatcherMap[opname] = {
method: 'POST',
url: api.graphql(opname),
};
});

const requestConfig = { routeMatcherMap };
]);

export function visitComplianceDashboard() {
visit(url.dashboard, requestConfig);
visit(url.dashboard, routeMatcherMapForComplianceDashboard);

cy.get('h1:contains("Compliance")');
}
Expand All @@ -41,15 +32,18 @@ export function visitComplianceDashboard() {
* Assume location is compliance dashboard.
*/
export function scanCompliance() {
cy.intercept('POST', api.graphql('triggerScan')).as('triggerScan');
interceptRequests(requestConfig);
const routeMatcherMapForTriggerScan = getRouteMatcherMapForGraphQL(['triggerScan']);
const routeMatcherMap = {
...routeMatcherMapForTriggerScan,
...routeMatcherMapForComplianceDashboard,
};

cy.get(selectors.scanButton).should('not.have.attr', 'disabled');
cy.get(selectors.scanButton).click();
cy.get(selectors.scanButton).should('have.attr', 'disabled');

cy.wait('@triggerScan');
waitForResponses(requestConfig);
interactAndWaitForResponses(() => {
cy.get(selectors.scanButton).click();
cy.get(selectors.scanButton).should('have.attr', 'disabled');
}, routeMatcherMap);

cy.get(selectors.scanButton).should('not.have.attr', 'disabled');
}
Expand All @@ -65,29 +59,38 @@ export function triggerScan() {
scanCompliance();
}

const opnameForEntities = {
clusters: 'clustersList', // just clusters would be even better, and so on
deployments: 'deploymentsList',
namespaces: 'namespaceList', // singular: too bad, so sad
nodes: 'nodesList',
};

/*
* For example, visitComplianceEntities('clusters')
*/
export function visitComplianceEntities(entitiesKey) {
cy.intercept('POST', api.graphql('searchOptions')).as('searchOptions');
cy.intercept('POST', api.compliance.graphqlEntities(entitiesKey)).as(entitiesKey);
const routeMatcherMap = getRouteMatcherMapForGraphQL([
'searchOptions',
opnameForEntities[entitiesKey],
]);

visit(url.entities[entitiesKey]);
visit(url.entities[entitiesKey], routeMatcherMap);

cy.wait(['@searchOptions', `@${entitiesKey}`]);
cy.get(`h1:contains("${headingPlural[entitiesKey]}")`);
}

/*
* For example, visitComplianceStandard('CIS Docker v1.2.0')
*/
export function visitComplianceStandard(standardName) {
cy.intercept('POST', api.graphql('searchOptions')).as('searchOptions');
cy.intercept('POST', api.graphql('getComplianceStandards')).as('getComplianceStandards');
cy.intercept('POST', api.graphql('controls')).as('controls');
const routeMatcherMap = getRouteMatcherMapForGraphQL([
'searchOptions',
'getComplianceStandards',
'controls',
]);

visit(`${url.controls}?s[standard]=${standardName}`);
visit(`${url.controls}?s[standard]=${standardName}`, routeMatcherMap);

cy.wait(['@searchOptions', '@getComplianceStandards', '@controls']);
cy.get(`h1:contains("${standardName}")`);
}
73 changes: 23 additions & 50 deletions ui/apps/platform/cypress/helpers/configWorkflowUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { graphql } from '../constants/apiEndpoints';
import { selectors as configManagementSelectors } from '../constants/ConfigManagementPage';
import { interactAndWaitForResponses } from './request';
import { getRouteMatcherMapForGraphQL, interactAndWaitForResponses } from './request';
import { visit } from './visit';

const basePath = '/main/configmanagement';
Expand Down Expand Up @@ -93,13 +92,9 @@ const widgetTitleForEntity = {
namespaces: 'Namespace',
};

function getRequestConfigForEntities(entitiesKey) {
function getRouteMatcherMapForEntities(entitiesKey) {
const opname = entitiesKey;
return {
routeMatcherMap: {
[opname]: graphql(opname),
},
};
return getRouteMatcherMapForGraphQL([opname]);
}

const opnameForEntity = {
Expand All @@ -116,13 +111,9 @@ const opnameForEntity = {
subjects: 'getSubject',
};

function getRequestConfigForEntity(entitiesKey) {
function getRouteMatcherMapForEntity(entitiesKey) {
const opname = opnameForEntity[entitiesKey];
return {
routeMatcherMap: {
[opname]: graphql(opname),
},
};
return getRouteMatcherMapForGraphQL([opname]);
}

const typeOfEntity = {
Expand All @@ -143,40 +134,30 @@ function opnameForPrimaryAndSecondaryEntities(entitiesKey1, entitiesKey2) {
return `${opnameForEntity[entitiesKey1]}_${typeOfEntity[entitiesKey2]}`;
}

const routeMatcherMapForDashboard = {};
[
const routeMatcherMapForConfigurationManagementDashboard = getRouteMatcherMapForGraphQL([
'numPolicies',
'numCISControls',
'policyViolationsBySeverity',
'runStatuses',
'complianceByControls',
'usersWithClusterAdminRoles',
'secrets',
].forEach((opname) => {
routeMatcherMapForDashboard[opname] = {
method: 'POST',
url: graphql(opname),
};
});

const requestConfigForDashboard = {
routeMatcherMap: routeMatcherMapForDashboard,
};
]);

export function visitConfigurationManagementDashboard() {
visit(basePath, requestConfigForDashboard);
visit(basePath, routeMatcherMapForConfigurationManagementDashboard);

cy.get('h1:contains("Configuration Management")');
}

export function visitConfigurationManagementEntities(entitiesKey) {
visit(getEntitiesPath(entitiesKey), getRequestConfigForEntities(entitiesKey));
visit(getEntitiesPath(entitiesKey), getRouteMatcherMapForEntities(entitiesKey));

cy.get(`h1:contains("${headingForEntities[entitiesKey]}")`);
}

export function visitConfigurationManagementEntitiesWithSearch(entitiesKey, search) {
visit(`${getEntitiesPath(entitiesKey)}${search}`, getRequestConfigForEntities(entitiesKey));
visit(`${getEntitiesPath(entitiesKey)}${search}`, getRouteMatcherMapForEntities(entitiesKey));

cy.get(`h1:contains("${headingForEntities[entitiesKey]}")`);
}
Expand All @@ -185,7 +166,7 @@ export function interactAndWaitForConfigurationManagementEntities(
interactionCallback,
entitiesKey
) {
interactAndWaitForResponses(interactionCallback, getRequestConfigForEntities(entitiesKey));
interactAndWaitForResponses(interactionCallback, getRouteMatcherMapForEntities(entitiesKey));

cy.location('pathname').should('eq', getEntitiesPath(entitiesKey));
cy.get(`h1:contains("${headingForEntities[entitiesKey]}")`);
Expand All @@ -195,7 +176,7 @@ export function interactAndWaitForConfigurationManagementEntityInSidePanel(
interactionCallback,
entitiesKey
) {
interactAndWaitForResponses(interactionCallback, getRequestConfigForEntity(entitiesKey));
interactAndWaitForResponses(interactionCallback, getRouteMatcherMapForEntity(entitiesKey));

cy.location('pathname').should('contain', getEntitiesPath(entitiesKey)); // contains because it ends with id
cy.get(
Expand All @@ -208,7 +189,7 @@ export function interactAndWaitForConfigurationManagementSecondaryEntityInSidePa
entitiesKey1,
entitiesKey2
) {
interactAndWaitForResponses(interactionCallback, getRequestConfigForEntity(entitiesKey2));
interactAndWaitForResponses(interactionCallback, getRouteMatcherMapForEntity(entitiesKey2));

cy.location('pathname').should('contain', getEntitiesPath(entitiesKey1)); // contains because it has id
cy.location('pathname').should('contain', segmentForEntity[entitiesKey2]); // contains because it has id
Expand All @@ -219,7 +200,7 @@ export function interactAndWaitForConfigurationManagementEntityPage(
interactionCallback,
entitiesKey
) {
interactAndWaitForResponses(interactionCallback, getRequestConfigForEntity(entitiesKey));
interactAndWaitForResponses(interactionCallback, getRouteMatcherMapForEntity(entitiesKey));

cy.location('pathname').should('contain', getEntityPagePath(entitiesKey)); // contains because it ends with id
cy.get(`h1 + div:contains("${headingForEntity[entitiesKey]}")`);
Expand All @@ -231,17 +212,16 @@ export function interactAndWaitForConfigurationManagementSecondaryEntities(
entitiesKey2
) {
const opname = opnameForPrimaryAndSecondaryEntities(entitiesKey1, entitiesKey2);
const requestConfig = {
routeMatcherMap: {
[opname]: graphql(opname),
},
};
const routeMatcherMap = getRouteMatcherMapForGraphQL([opname]);

interactAndWaitForResponses(interactionCallback, requestConfig);
interactAndWaitForResponses(interactionCallback, routeMatcherMap);
}

export function interactAndWaitForConfigurationManagementScan(interactionCallback) {
interactAndWaitForResponses(interactionCallback, requestConfigForDashboard);
interactAndWaitForResponses(
interactionCallback,
routeMatcherMapForConfigurationManagementDashboard
);
}

// specifying an "entityName" will try to select that row in the table
Expand Down Expand Up @@ -394,16 +374,9 @@ export function entityListCountMatchesTableLinkCount(entitiesKey1, entitiesKey2,

// 2. Visit secondary entities side panel.
const opname = opnameForPrimaryAndSecondaryEntities(entitiesKey1, entitiesKey2);
interactAndWaitForResponses(
() => {
cy.wrap($a).click();
},
{
routeMatcherMap: {
[opname]: graphql(opname),
},
}
);
interactAndWaitForResponses(() => {
cy.wrap($a).click();
}, getRouteMatcherMapForGraphQL([opname]));

const heading = headingForEntities[entitiesKey2];
cy.get(
Expand Down
Loading