console/cypress/e2e/clusters/update-cluster.cy.ts

507 lines
16 KiB
TypeScript

import cluster from '../../fixtures/clusters/cluster/cluster.json';
import updateCluster from '../../fixtures/clusters/cluster/update-cluster.json';
import _ from 'lodash';
describe('Update cluster', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: cluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000&seed_peer_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.visit('/clusters/1/edit');
cy.viewport(1440, 1080);
});
it('when data is loaded', () => {
// Show cluster information.
cy.get('.MuiPaper-root > .css-0 > :nth-child(2)').should('contain', 'cluster-1');
cy.get('.PrivateSwitchBase-input').should('be.checked').check({ force: true });
// Show scopes.
cy.get('#location').should('have.value', 'China|Hang|Zhou');
cy.get(':nth-child(2) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root')
.should('contain', 'Hangzhou')
.and('contain', 'Shanghai');
cy.get(':nth-child(3) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root')
.should('contain', '10.0.0.0/8')
.and('contain', '192.168.0.0/16')
.and('contain', '172.16.0.0/12');
cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root')
.should('contain', 'cluster-1')
.and('contain', 'cluster-2')
.and('contain', 'cluster-3');
// Show config.
cy.get('#seedPeerLoadLimit').should('have.value', 300);
cy.get('#peerLoadLimit').should('have.value', 51);
cy.get('#candidateParentLimit').should('have.value', 4);
cy.get('#filterParentLimit').should('have.value', 40);
cy.get('#jobRateLimit').should('have.value', 15);
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/2',
},
(req) => {
req.reply({
statusCode: 200,
body: {
id: 0,
name: '',
bio: '',
scopes: {
idc: '',
location: '',
cidrs: null,
hostnames: null,
},
scheduler_cluster_id: 1,
seed_peer_cluster_id: 1,
scheduler_cluster_config: {
candidate_parent_limit: 0,
filter_parent_limit: 0,
},
seed_peer_cluster_config: {
load_limit: 0,
},
peer_cluster_config: {
load_limit: 0,
},
created_at: '2023-03-08T02:39:03Z',
updated_at: '2023-03-08T02:39:03Z',
is_default: false,
},
});
},
);
cy.visit('/clusters/2/edit');
// Show cluster information.
cy.get('.MuiPaper-outlined > .css-0 > :nth-child(1)').should('contain', '0');
cy.get('.MuiPaper-root > .css-0 > :nth-child(2)').should('contain', '');
cy.get('.PrivateSwitchBase-input').should('not.be.checked').check({ force: false });
// When location is empty.
cy.get('#location').should('have.value', '');
// When idc is empty.
cy.get(':nth-child(2) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').should(
'have.value',
'',
);
// When CIDRs is empty.
cy.get(':nth-child(3) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').should(
'have.value',
'',
);
// When Hostname is empty.
cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').should(
'have.value',
'',
);
// Show config.
cy.get('#seedPeerLoadLimit').should('have.value', 0);
cy.get('#peerLoadLimit').should('have.value', 0);
cy.get('#candidateParentLimit').should('have.value', 0);
cy.get('#filterParentLimit').should('have.value', 0);
cy.get('#jobRateLimit').should('have.value', 10);
});
it('can update cluster', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/clusters/1' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 200,
body: {},
});
});
cy.visit('/clusters/1');
// Click update cluster button.
cy.get('.css-bbra84-MuiButtonBase-root-MuiButton-root').click();
// Show cluster name.
cy.get('.MuiPaper-root > .css-0 > :nth-child(2)').should('be.visible').and('contain', 'cluster-1');
cy.get('.PrivateSwitchBase-input').click();
// Update cluster description.
cy.get('#description').clear();
cy.get('#description').type('update cluster-1');
// Update cluster Scopes.
cy.get('#location').clear();
cy.get('#location').type('China|Shang|Hai');
cy.get(':nth-child(2) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root')
.type('{selectall}')
.type('{backspace}');
cy.get(':nth-child(3) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(
'192.168.20.2{enter}',
);
// Update cluster Config.
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('400');
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('50');
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('5');
cy.get('#filterParentLimit').clear();
cy.get('#filterParentLimit').type('50');
cy.get('#jobRateLimit').clear();
cy.get('#jobRateLimit').type('20');
// Click save button.
cy.get('#save').click();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: updateCluster,
});
},
);
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/clusters/1');
cy.get('.show_container__osP4U > .MuiTypography-root').scrollIntoView();
// Check whether the cluster information is updated successfully.
cy.get('.information_clusterContainer__l8H8p > :nth-child(3) > .MuiTypography-subtitle1')
.should('be.visible')
.and('contain', 'update cluster-1');
cy.get('.information_clusterContainer__l8H8p > :nth-child(5) > .MuiTypography-subtitle1')
.should('be.visible')
.and('contain', 'No');
cy.get('#cidrs').click();
cy.get('.MuiDialogContent-root > :nth-child(4)').should('be.visible').and('contain', '192.168.20.2');
cy.get('body').click('topLeft');
cy.get('.MuiPaper-root > :nth-child(1) > .MuiTypography-body1')
.scrollIntoView()
.should('be.visible')
.and('contain', '400');
cy.get('#filter-parent-limit').should('be.visible').and('contain', '20');
});
it('click the `CANCEL button', () => {
cy.get('#cancel').click();
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/clusters/1');
});
it('try to update cluster with guest user', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/clusters/1' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
});
cy.guestSignin();
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'permission deny');
// Close error message.
cy.get(':nth-child(1) > .MuiSnackbar-root > .MuiPaper-root > .MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
describe('should handle API error response', () => {
it('get cluster API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('not.exist');
});
it('update cluster API error response', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/clusters/1' }, (req) => {
(req.body = ''),
req.reply({
forceNetworkError: true,
});
});
cy.get('#description').clear();
cy.get('#description').type('update cluster-1');
cy.get('#save').click();
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
describe('cannot update cluster with invalid attributes', () => {
it('try to verify information', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const description = _.times(1001, () => _.sample(characters)).join('');
cy.get('#description').clear();
cy.get('#description').type(description);
// Show verification error message.
cy.get('#description-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the length is 0-1000.');
// Submit form when validation fails.
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#description').clear();
// Verification passed.
cy.get('#description').type('cluster description');
});
it('try to verify scopes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const location = _.times(101, () => _.sample(characters)).join('');
// Should display location the validation error message.
cy.get('#location').type(location);
// Show verification error message.
cy.get('#location-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the length is 0-100.');
// Submit form when validation fails.
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#location').clear();
// Verification passed.
cy.get('#location').type('Beijing');
cy.get('#location-helper-text').should('not.exist');
// Should display idc the validation error message.
cy.get(':nth-child(2) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('hz');
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#idc-helper-text').should('be.visible').and('contain', `Please press ENTER to end the IDC creation.`);
// Verification passed.
cy.get(':nth-child(2) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('hz{enter}');
cy.get('#idc-helper-text').should('not.exist');
// Should display cidrs the validation error message.
cy.get(':nth-child(3) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(
'192.168.40.0/24',
);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
// Show verification error message.
cy.get('#cidrs-helper-text').should('be.visible').and('contain', `Please press ENTER to end the CIDRs creation.`);
cy.get(':nth-child(3) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(
'192.168.40.0/24{enter}',
);
cy.get('#cidrs-helper-text').should('not.exist');
// Should display hostnames the validation error message.
cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('cluster-2');
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
// Show verification error message.
cy.get('#hostnames-helper-text')
.should('be.visible')
.and('contain', `Please press ENTER to end the Hostnames creation.`);
cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(
'cluster-1{enter}',
);
cy.get('#hostnames-helper-text').should('not.exist');
});
it('try to verify config', () => {
// Should display seed peer load limit the validation error message.
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('50001');
// Show verification error message.
cy.get('#seedPeerLoadLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 0-50000.`);
// Submit form when validation fails.
cy.get('#save').click();
// cluster creation failed, the page is still in cluster/new!
cy.url().should('include', '/clusters/1/edit');
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('400');
// Verification passed.
cy.get('#seedPeerLoadLimit-helper-text').should('not.exist');
// Should display peer load limit the validation error message.
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('2001');
// Show verification error message.
cy.get('#peerLoadLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 0-2000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('50');
// Verification passed.
cy.get('#peerLoadLimit-helper-text').should('not.exist');
// Should display candidate parent limit the validation error message.
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('21');
// Show verification error message.
cy.get('#candidateParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-20.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('5');
cy.get('#candidateParentLimit-helper-text').should('not.exist');
// Should display filter parent limit the validation error message.
cy.get('#filterParentLimit').clear();
// Minimum validation range not reached.
cy.get('#filterParentLimit').type('9');
// Show verification error message.
cy.get('#filterParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 10-1000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#filterParentLimit').clear();
// Maximum verification range exceeded.
cy.get('#filterParentLimit').type('1001');
// Show verification error message.
cy.get('#filterParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 10-1000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#filterParentLimit').clear();
cy.get('#filterParentLimit').type('100');
// Verification passed.
cy.get('#filterParentLimit-helper-text').should('not.exist');
// Should display Job Rate Limit(requests per seconds) the validation error message.
cy.get('#jobRateLimit').invoke('val').should('eq', '15');
cy.get('#jobRateLimit').clear();
// Minimum validation range not reached.
cy.get('#jobRateLimit').type('0');
cy.get('#jobRateLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-1000000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#jobRateLimit').clear();
// Maximum verification range exceeded.
cy.get('#jobRateLimit').type('1000001');
cy.get('#jobRateLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-1000000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#jobRateLimit').clear();
cy.get('#jobRateLimit').type('100');
// Verification passed.
cy.get('#jobRateLimit-helper-text').should('not.exist');
});
});
});