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

Apply PageObject pattern Clusters Overview tests. #3266

Merged
merged 18 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
237 changes: 60 additions & 177 deletions test/e2e/cypress/e2e/clusters_overview.cy.js
Original file line number Diff line number Diff line change
@@ -1,234 +1,117 @@
import { createUserRequestFactory } from '@lib/test-utils/factories';

import {
availableClusters,
healthyClusterScenario,
unhealthyClusterScenario,
} from '../fixtures/clusters-overview/available_clusters';

const clusterIdByName = (clusterName) =>
availableClusters.find(({ name }) => name === clusterName).id;

const clusterTags = {
hana_cluster_1: 'env1',
hana_cluster_2: 'env2',
hana_cluster_3: 'env3',
};
import * as clustersOverviewPage from '../pageObject/clusters-overview-po.js';

context('Clusters Overview', () => {
before(() => {
cy.preloadTestData();
cy.visit('/clusters');
cy.url().should('include', '/clusters');
before(() => clustersOverviewPage.preloadTestData());

beforeEach(() => {
clustersOverviewPage.interceptClustersEndpoint();
clustersOverviewPage.visit();
clustersOverviewPage.validateUrl();
});

describe('Registered Clusters should be available in the overview', () => {
it('should show all of the registered clusters', () => {
cy.get('.tn-clustername')
.its('length')
.should('eq', availableClusters.length);
clustersOverviewPage.allRegisteredClustersAreDisplayed();
});

it('should have 1 pages', () => {
cy.get(`[data-testid="pagination"]`).should('include.text', '1');
cy.get(`[data-testid="pagination"]`).should('not.include.text', '2');
clustersOverviewPage.paginationButtonsAreDisabled();
});

it('should show the expected clusters data', () => {
cy.get('.container').eq(0).as('clustersTable');
availableClusters.forEach((cluster, index) => {
cy.get('@clustersTable')
.find('tr')
.eq(index + 1)
.find('td')
.as('clusterRow');

cy.get('@clustersTable')
.contains('th', 'Name')
.invoke('index')
.then((i) => {
cy.get('@clusterRow').eq(i).should('contain', cluster.name);
});

cy.get('@clustersTable')
.contains('th', 'SID')
.invoke('index')
.then((i) => {
cy.get('@clusterRow').eq(i).should('contain', cluster.sid);
});

cy.get('@clustersTable')
.contains('th', 'Type')
.invoke('index')
.then((i) => {
cy.get('@clusterRow').eq(i).should('contain', cluster.type);
});
});
clustersOverviewPage.clustersDataIsDisplayedAsExpected();
});

describe('Unnamed cluster', () => {
before(() => {
cy.loadScenario('cluster-unnamed');
});

// Restore cluster name
after(() => {
cy.loadScenario('cluster-4-SOK');
});
before(() => clustersOverviewPage.loadScenario('cluster-unnamed'));

it('Unnamed clusters should use the ID as details page link', () => {
const clusterID = clusterIdByName('hana_cluster_1');
cy.get(`a:contains(${clusterID})`).should('be.visible');
clustersOverviewPage.clusterNameLinkIsDisplayedAsId('hana_cluster_1');
});

after(() => clustersOverviewPage.restoreClusterName());
});

// eslint-disable-next-line mocha/no-skipped-tests
describe.skip('Health status for each cluster is correct', () => {
before(() => {
cy.selectChecks(
clusterIdByName(healthyClusterScenario.clusterName),
healthyClusterScenario.checks
);
clustersOverviewPage.apiSelectChecksForHealthyCluster();
// wip: set expected results
cy.requestChecksExecution(
clusterIdByName(healthyClusterScenario.clusterName)
);

cy.selectChecks(
clusterIdByName(unhealthyClusterScenario.clusterName),
healthyClusterScenario.checks
);
clustersOverviewPage.apiRequestChecksForHealthyCluster();

clustersOverviewPage.apiSelectChecksForUnhealthyCluster();
// wip: set expected results
cy.requestChecksExecution(
clusterIdByName(unhealthyClusterScenario.clusterName)
);
clustersOverviewPage.apiRequestChecksForUnhealthyCluster();
});

after(() => {
cy.selectChecks(
clusterIdByName(healthyClusterScenario.clusterName),
[]
);

cy.selectChecks(
clusterIdByName(unhealthyClusterScenario.clusterName),
[]
);
clustersOverviewPage.apiRemoveHealthyClusterChecks();
clustersOverviewPage.apiRemoveUnhealthyClusterChecks();
});

it(`should have ${healthyClusterScenario.clusterName} displaying healthy state`, () => {
cy.get('td')
.contains(healthyClusterScenario.clusterName)
.parent()
.parent()
.prev()
.get('div > svg')
.should('have.class', 'fill-jungle-green-500');
it(`should have ${clustersOverviewPage.healthyClusterName} displaying healthy state`, () => {
clustersOverviewPage.healthyClusterNameDisplaysHealthyState();
});

it(`should have ${unhealthyClusterScenario.clusterName} displaying unhealthy state`, () => {
cy.get('td')
.contains(unhealthyClusterScenario.clusterName)
.parent()
.parent()
.prev()
.get('div > svg')
.should('have.class', 'fill-red-500');
it(`should have ${clustersOverviewPage.unhealthyClusterName} displaying unhealthy state`, () => {
clustersOverviewPage.unhealthyClusterNameDisplaysUnhealthyState();
});
});
});

describe('Clusters Tagging', () => {
before(() => {
cy.removeTagsFromView();
beforeEach(() => {
clustersOverviewPage.restoreClusterName();
clustersOverviewPage.apiRemoveAllTags();
});
const clustersByMatchingPattern = (pattern) => (clusterName) =>
clusterName.includes(pattern);
const taggingRules = [
['hana_cluster_1', clusterTags.hana_cluster_1],
['hana_cluster_2', clusterTags.hana_cluster_2],
['hana_cluster_3', clusterTags.hana_cluster_3],
];

taggingRules.forEach(([pattern, tag]) => {
describe(`Add tag '${tag}' to all clusters with '${pattern}' in the cluster name`, () => {
availableClusters
.map(({ name }) => name)
.filter(clustersByMatchingPattern(pattern))
.forEach((clusterName) => {
it(`should tag cluster '${clusterName}'`, () => {
cy.addTagByColumnValue(clusterName, tag);
});
});
});

it('should tag each cluster with the corresponding tag', () => {
clustersOverviewPage.setClusterTags();
clustersOverviewPage.eachClusterTagsIsCorrectlyDisplayed();
});
});

describe('Deregistration', () => {
const hanaCluster1 = {
name: 'hana_cluster_1',
hosts: [
'13e8c25c-3180-5a9a-95c8-51ec38e50cfc',
'0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4',
],
};

it(`should not display '${hanaCluster1.name}' after deregistering all its nodes`, () => {
cy.deregisterHost(hanaCluster1.hosts[0]);
cy.deregisterHost(hanaCluster1.hosts[1]);
cy.contains(hanaCluster1.name).should('not.exist');
before(() => {
clustersOverviewPage.apiRemoveAllTags();
clustersOverviewPage.apiSetTagsHanaCluster1();
clustersOverviewPage.apiDeregisterAllClusterHosts();
});

it(`should show cluster ${hanaCluster1.name} after registering it again with the previous tags`, () => {
cy.loadScenario(`cluster-${hanaCluster1.name}-restore`);
cy.contains(hanaCluster1.name).should('exist');
cy.contains('tr', hanaCluster1.name).within(() => {
cy.contains(clusterTags[hanaCluster1.name]).should('exist');
});
it(`should not display '${clustersOverviewPage.hanaCluster1.name}' after deregistering all its nodes`, () => {
clustersOverviewPage.clusterIsNotDisplayedWhenNodesAreDeregistered();
});

it(`should show cluster '${clustersOverviewPage.hanaCluster1.name}' after registering it again with the previous tags`, () => {
clustersOverviewPage.apiRestoreClusterHosts();
clustersOverviewPage.clusterNameIsDisplayed();
clustersOverviewPage.hanaCluster1TagsAreDisplayed();
});
});

describe('Forbidden action', () => {
beforeEach(() => {
cy.deleteAllUsers();
cy.logout();
const user = createUserRequestFactory.build({
password,
password_confirmation: password,
describe('Tag operations', () => {
beforeEach(() => {
clustersOverviewPage.apiRemoveAllTags();
clustersOverviewPage.apiSetTagsHanaCluster1();
clustersOverviewPage.apiDeleteAllUsers();
clustersOverviewPage.logout();
});
cy.wrap(user).as('user');
});

const password = 'password';

describe('Tag operations', () => {
it('should prevent a tag update when the user abilities are not compliant', () => {
cy.get('@user').then((user) => {
cy.createUserWithAbilities(user, []);
cy.login(user.username, password);
});

cy.visit('/clusters');

cy.contains('span', 'Add Tag').should('have.class', 'opacity-50');
cy.get('[data-test-id="tag-env1"]').should('have.class', 'opacity-50');
clustersOverviewPage.apiCreateUserWithoutAbilities();
clustersOverviewPage.loginWithoutTagAbilities();
clustersOverviewPage.visit();
clustersOverviewPage.addTagButtonsAreDisabled();
clustersOverviewPage.removeTagButtonIsDisabled();
});

it('should allow a tag update when the user abilities are compliant', () => {
cy.get('@user').then((user) => {
cy.createUserWithAbilities(user, [
{ name: 'all', resource: 'cluster_tags' },
]);
cy.login(user.username, password);
});

cy.visit('/clusters');

cy.contains('span', 'Add Tag').should('not.have.class', 'opacity-50');
cy.get('[data-test-id="tag-env1"]').should(
'not.have.class',
'opacity-50'
);
clustersOverviewPage.apiCreateUserWithClusterTagsAbilities();
clustersOverviewPage.loginWithTagAbilities();
clustersOverviewPage.visit();
clustersOverviewPage.addTagButtonsAreNotDisabled();
clustersOverviewPage.removeTagButtonIsEnabled();
});
});
});
Expand Down
4 changes: 1 addition & 3 deletions test/e2e/cypress/pageObject/about-po.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ const githubRepositoryLabel = 'div:contains("GitHub repository") + div a';
const amountOfSlesForSapSubscriptionsLabel =
'div:contains("SLES for SAP subscriptions") + div span';

export const visit = (_url = url) => {
return basePage.visit(_url);
};
export const visit = () => basePage.visit(url);

export const pageTitleIsDisplayed = () => {
return cy.get(pageTitle).should('have.text', 'About Trento Console');
Expand Down
36 changes: 32 additions & 4 deletions test/e2e/cypress/pageObject/base-po.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,10 @@ export const apiLoginAndCreateSession = (
};

export const logout = () => {
window.localStorage.removeItem('access_token');
window.localStorage.removeItem('refresh_token');
cy.window().then((win) => {
win.localStorage.removeItem('access_token');
win.localStorage.removeItem('refresh_token');
});
Cypress.session.clearAllSavedSessions();
};

Expand Down Expand Up @@ -170,12 +172,12 @@ export const preloadTestData = () => {
* scenario is sent in the second time.
*/
isTestDataLoaded().then((isLoaded) => {
if (!isLoaded) cy.loadScenario('healthy-27-node-SAP-cluster');
if (!isLoaded) loadScenario('healthy-27-node-SAP-cluster');
});
loadScenario('healthy-27-node-SAP-cluster');
};

const loadScenario = (scenario) => {
export const loadScenario = (scenario) => {
const [projectRoot, photofinishBinary, webAPIHost, webAPIPort] = [
Cypress.env('project_root'),
Cypress.env('photofinish_binary'),
Expand Down Expand Up @@ -204,3 +206,29 @@ const isTestDataLoaded = () =>
})
.then(({ body }) => body.length !== 0)
);

export const createUserWithAbilities = (payload, abilities) =>
apiLogin().then(({ accessToken }) =>
cy
.request({
url: '/api/v1/abilities',
method: 'GET',
auth: { bearer: accessToken },
body: {},
})
.then(({ body }) => {
const abilitiesWithID = abilities.map((ability) => ({
...body.find(
({ name, resource }) =>
ability.name === name && ability.resource === resource
),
}));

cy.request({
url: '/api/v1/users',
method: 'POST',
auth: { bearer: accessToken },
body: { ...payload, abilities: abilitiesWithID },
});
})
);
Loading
Loading