Skip to content

Commit

Permalink
Fix failing e2e tests
Browse files Browse the repository at this point in the history
- fix cluster dashboard events test
- fix and greatly improve flaky events test
- fix hpa test
- functional fixes
  - fix sorting/filtering events by object type
  - fix hpa columns
  • Loading branch information
richard-cox committed Jan 7, 2025
1 parent dc5a5a3 commit df685b0
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -265,30 +265,39 @@ describe('Cluster Dashboard', { testIsolation: 'off', tags: ['@explorer', '@admi

clusterDashboard.eventsList().resourceTable().sortableTable().checkRowCount(true, 1);

const expectedHeaders = ['Reason', 'Object', 'Message', 'Name', 'Date'];
let expectedHeaders = ['Reason', 'Object', 'Message', 'Name', 'Date'];

clusterDashboard.eventsList().resourceTable().sortableTable().tableHeaderRow()
.within('.table-header-container .content')
.each((el, i) => {
expect(el.text().trim()).to.eq(expectedHeaders[i]);
});
cy.isVaiCacheEnabled().then((isVaiCacheEnabled) => {
if (isVaiCacheEnabled) {
expectedHeaders = ['Reason', 'Object', 'Message', 'Name', 'First Seen', 'Last Seen', 'Count'];
}

clusterDashboard.fullEventsLink().click();
cy.wait('@eventsNoData');
const events = new EventsPagePo('local');
clusterDashboard.eventsList().resourceTable().sortableTable().tableHeaderRow()
.self()
.scrollIntoView();
clusterDashboard.eventsList().resourceTable().sortableTable().tableHeaderRow()
.within('.table-header-container .content')
.each((el, i) => {
expect(el.text().trim()).to.eq(expectedHeaders[i]);
});

events.waitForPage();
clusterDashboard.fullEventsLink().click();
cy.wait('@eventsNoData');
const events = new EventsPagePo('local');

events.eventslist().resourceTable().sortableTable().checkRowCount(true, 1);
events.waitForPage();

const expectedFullHeaders = ['State', 'Last Seen', 'Type', 'Reason', 'Object',
'Subobject', 'Source', 'Message', 'First Seen', 'Count', 'Name', 'Namespace'];
events.eventslist().resourceTable().sortableTable().checkRowCount(true, 1);

events.eventslist().resourceTable().sortableTable().tableHeaderRow()
.within('.table-header-container .content')
.each((el, i) => {
expect(el.text().trim()).to.eq(expectedFullHeaders[i]);
});
const expectedFullHeaders = ['State', 'Last Seen', 'Type', 'Reason', 'Object',
'Subobject', 'Source', 'Message', 'First Seen', 'Count', 'Name', 'Namespace'];

events.eventslist().resourceTable().sortableTable().tableHeaderRow()
.within('.table-header-container .content')
.each((el, i) => {
expect(el.text().trim()).to.eq(expectedFullHeaders[i]);
});
});
});

describe('Cluster dashboard with limited permissions', () => {
Expand Down
149 changes: 94 additions & 55 deletions cypress/e2e/tests/pages/explorer/dashboard/events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import SortableTablePo from '@/cypress/e2e/po/components/sortable-table.po';
const cluster = 'local';
const clusterDashboard = new ClusterDashboardPagePo(cluster);
const events = new EventsPagePo(cluster);
const pageSize = 10;
// Should be enough to create at least 3 pages of events
const podCount = 15;

describe('Events', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] }, () => {
before(() => {
Expand All @@ -20,7 +23,12 @@ describe('Events', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] },
let nsName2: string;

before('set up', () => {
cy.updateNamespaceFilter(cluster, 'none', '{\"local\":[]}');
cy.tableRowsPerPageAndPreferences(pageSize, {
clusterName: cluster,
groupBy: 'none',
namespaceFilter: '{\"local\":[]}',
allNamespaces: 'true',
});

cy.createE2EResourceName('ns1').then((ns1) => {
nsName1 = ns1;
Expand All @@ -30,7 +38,7 @@ describe('Events', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] },
// create pods
let i = 0;

while (i < 125) {
while (i < podCount) {
const podName = Cypress._.uniqueId(Date.now().toString());

cy.createPod(nsName1, podName, 'nginx:latest', false, { createNameOptions: { prefixContext: true } }).then((resp) => {
Expand Down Expand Up @@ -61,73 +69,99 @@ describe('Events', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] },
EventsPagePo.navTo();
events.waitForPage();

cy.getRancherResource('v1', 'events').then((resp: Cypress.Response<any>) => {
// Why 500? there's a hardcoded figure to stops ui from storing more than 500 events ...
const count = resp.body.count < 500 ? resp.body.count : 500;
let vaiCacheEnabled = false;

// Test break down if less than 400...
expect(count).to.be.greaterThan(400);
cy.isVaiCacheEnabled()
.then((isVaiCacheEnabled) => {
vaiCacheEnabled = isVaiCacheEnabled;

// pagination is visible
events.sortableTable().pagination().checkVisible();
return cy.getRancherResource('v1', 'events');
})
.then((resp: Cypress.Response<any>) => {
let count = resp.body.count;

const loadingPo = new LoadingPo('.title .resource-loading-indicator');
if (!vaiCacheEnabled && resp.body.count > 500) {
// Why 500? there's a hardcoded figure to stops ui from storing more than 500 events ...
count = 500;
}

loadingPo.checkNotExists();
// Test break down if less than 3 pages...
expect(count).to.be.greaterThan(3 * pageSize);

// basic checks on navigation buttons
events.sortableTable().pagination().beginningButton().isDisabled();
events.sortableTable().pagination().leftButton().isDisabled();
events.sortableTable().pagination().rightButton().isEnabled();
events.sortableTable().pagination().endButton().isEnabled();
// pagination is visible
events.sortableTable().pagination().checkVisible();

// check text before navigation
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`1 - 100 of ${ count } Events`);
});
const loadingPo = new LoadingPo('.title .resource-loading-indicator');

// navigate to next page - right button
events.sortableTable().pagination().rightButton().click();
loadingPo.checkNotExists();

// check text and buttons after navigation
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`101 - 200 of ${ count } Events`);
});
events.sortableTable().pagination().beginningButton().isEnabled();
events.sortableTable().pagination().leftButton().isEnabled();
// basic checks on navigation buttons
events.sortableTable().pagination().beginningButton().isDisabled();
events.sortableTable().pagination().leftButton().isDisabled();
events.sortableTable().pagination().rightButton().isEnabled();
events.sortableTable().pagination().endButton().isEnabled();

// navigate to first page - left button
events.sortableTable().pagination().leftButton().click();
// check text before navigation
events.sortableTable().pagination().self().scrollIntoView();

// check text and buttons after navigation
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`1 - 100 of ${ count } Events`);
});
events.sortableTable().pagination().beginningButton().isDisabled();
events.sortableTable().pagination().leftButton().isDisabled();
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`1 - ${ pageSize } of ${ count } Events`);
});

// navigate to last page - end button
events.sortableTable().pagination().endButton().scrollIntoView()
.click();
// navigate to next page - right button
events.sortableTable().pagination().rightButton().click();

// check row count on last page
events.sortableTable().checkRowCount(false, 100);
// check text and buttons after navigation
events.sortableTable().pagination().self().scrollIntoView();
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`${ pageSize + 1 } - ${ 2 * pageSize } of ${ count } Events`);
});
events.sortableTable().pagination().beginningButton().isEnabled();
events.sortableTable().pagination().leftButton().isEnabled();

// check text after navigation
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`401 - ${ count } of ${ count } Events`);
});
// navigate to first page - left button
events.sortableTable().pagination().leftButton().click();

// check text and buttons after navigation
events.sortableTable().pagination().self().scrollIntoView();
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`1 - ${ pageSize } of ${ count } Events`);
});
events.sortableTable().pagination().beginningButton().isDisabled();
events.sortableTable().pagination().leftButton().isDisabled();

// navigate to first page - beginning button
events.sortableTable().pagination().beginningButton().click();
// navigate to last page - end button
events.sortableTable().pagination().endButton().scrollIntoView()
.click();

// check text and buttons after navigation
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`1 - 100 of ${ count } Events`);
// check row count on last page
events.sortableTable().checkRowCount(false, pageSize);

// check text after navigation
events.sortableTable().pagination().self().scrollIntoView();
events.sortableTable().pagination().paginationText().then((el) => {
let pages = Math.round(count / pageSize);

if (count % pageSize === 0) {
pages--;
}
const from = (pages * pageSize) + 1;
const to = count;

expect(el.trim()).to.eq(`${ from } - ${ to } of ${ to } Events`);
});

// navigate to first page - beginning button
events.sortableTable().pagination().beginningButton().click();

// check text and buttons after navigation
events.sortableTable().pagination().self().scrollIntoView();
events.sortableTable().pagination().paginationText().then((el) => {
expect(el.trim()).to.eq(`1 - ${ pageSize } of ${ count } Events`);
});
events.sortableTable().pagination().beginningButton().isDisabled();
events.sortableTable().pagination().leftButton().isDisabled();
});
events.sortableTable().pagination().beginningButton().isDisabled();
events.sortableTable().pagination().leftButton().isDisabled();
});
});

it('filter events', () => {
Expand All @@ -138,7 +172,7 @@ describe('Events', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] },

events.sortableTable().checkVisible();
events.sortableTable().checkLoadingIndicatorNotVisible();
events.sortableTable().checkRowCount(false, 100);
events.sortableTable().checkRowCount(false, pageSize);

// filter by namespace
events.sortableTable().filter(nsName2);
Expand Down Expand Up @@ -201,7 +235,12 @@ describe('Events', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] },
});

after('clean up', () => {
cy.updateNamespaceFilter(cluster, 'none', '{"local":["all://user"]}');
cy.tableRowsPerPageAndPreferences(100, {
clusterName: cluster,
groupBy: 'none',
namespaceFilter: '{"local":["all://user"]}',
allNamespaces: 'false',
});

// delete namespace (this will also delete all pods in it)
cy.deleteRancherResource('v1', 'namespaces', nsName1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ describe('HorizontalPodAutoscalers', { testIsolation: 'off', tags: ['@explorer',
horizontalPodAutoscalersPage.waitForPage();
cy.wait('@horizontalpodautoscalerNoData');

const expectedHeaders = ['State', 'Name', 'Workload', 'Minimum Replicas', 'Maximum Replicas', 'Current Replicas', 'Age'];
const expectedHeaders = ['State', 'Name', 'Namespace', 'Workload', 'Minimum Replicas', 'Maximum Replicas', 'Current Replicas', 'Age'];

horizontalPodAutoscalersPage.list().resourceTable().sortableTable().tableHeaderRow()
.self()
.scrollIntoView();
horizontalPodAutoscalersPage.list().resourceTable().sortableTable().tableHeaderRow()
.get('.table-header-container .content')
.each((el, i) => {
Expand All @@ -39,7 +42,7 @@ describe('HorizontalPodAutoscalers', { testIsolation: 'off', tags: ['@explorer',
horizontalPodAutoscalersPage.header().selectNamespaceFilterOption('All Namespaces');

// check table headers are visible
const expectedHeaders = ['State', 'Name', 'Workload', 'Minimum Replicas', 'Maximum Replicas', 'Current Replicas', 'Age'];
const expectedHeaders = ['State', 'Name', 'Namespace', 'Workload', 'Minimum Replicas', 'Maximum Replicas', 'Current Replicas', 'Age'];

horizontalPodAutoscalersPage.list().resourceTable().sortableTable().tableHeaderRow()
.get('.table-header-container .content')
Expand All @@ -65,7 +68,7 @@ describe('HorizontalPodAutoscalers', { testIsolation: 'off', tags: ['@explorer',
horizontalPodAutoscalersPage.list().resourceTable().sortableTable().groupByButtons(1)
.click();

// check table headers are visible
// check table headers are visible (minus namespace given we're now grouped by it)
const expectedHeaders = ['State', 'Name', 'Workload', 'Minimum Replicas', 'Maximum Replicas', 'Current Replicas', 'Age'];

horizontalPodAutoscalersPage.list().resourceTable().sortableTable().tableHeaderRow()
Expand Down
8 changes: 7 additions & 1 deletion cypress/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ declare global {
deleteRancherResource(prefix: 'v3' | 'v1' | 'k8s', resourceType: string, resourceId: string, failOnStatusCode?: boolean): Chainable;
deleteNodeTemplate(nodeTemplateId: string, timeout?: number, failOnStatusCode?: boolean)

tableRowsPerPageAndNamespaceFilter(rows: number, cluster: string, groupBy: string, namespacefilter: string, interation?: number)
tableRowsPerPageAndNamespaceFilter(rows: number, clusterName: string, groupBy: string, namespaceFilter: string)
tableRowsPerPageAndPreferences(rows: number, preferences: { clusterName: string, groupBy: string, namespaceFilter: string, allNamespaces: string}, iteration?: number)

/**
* update namespace filter
Expand Down Expand Up @@ -162,6 +163,11 @@ declare global {
* Fetch the steve `revision` / timestamp of request
*/
fetchRevision(): Chainable<string>;

/**
* Check if the vai FF is enabled
*/
isVaiCacheEnabled(): Chainable<boolean>;
}
}
}
41 changes: 30 additions & 11 deletions cypress/support/commands/rancher-api-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1024,39 +1024,58 @@ Cypress.Commands.add('fetchRevision', () => {
});
});

Cypress.Commands.add('tableRowsPerPageAndNamespaceFilter', (rows: number, clusterName: string, groupBy: string, namespaceFilter: string, iteration = 0) => {
/**
* Check if the vai FF is enabled
*/
Cypress.Commands.add('isVaiCacheEnabled', () => {
return cy.getRancherResource('v1', 'management.cattle.io.features', 'ui-sql-cache', 200)
.then((res) => res.body.spec.value === true || res.body.spec.value === 'true');
});

Cypress.Commands.add('tableRowsPerPageAndPreferences', (rows: number, preferences: { clusterName: string, groupBy: string, namespaceFilter: string, allNamespaces: string}, iteration = 0) => {
const {
clusterName, groupBy, namespaceFilter, allNamespaces
} = preferences;

return cy.getRancherResource('v3', 'users?me=true').then((resp: Cypress.Response<any>) => {
const userId = resp.body.data[0].id.trim();
const payload = {
id: `${ userId }`,
type: 'userpreference',
data: {
cluster: clusterName,
'per-page': `${ rows }`,
'group-by': groupBy,
'ns-by-cluster': namespaceFilter
cluster: clusterName,
'per-page': `${ rows }`,
'group-by': groupBy,
'ns-by-cluster': namespaceFilter,
'all-namespaces': allNamespaces,
}
};

cy.log(`tableRowsPerPageAndNamespaceFilter: /v1/userpreferences/${ userId }. Payload: ${ JSON.stringify(payload) }`);
cy.log(`tableRowsPerPageAndPreferences: /v1/userpreferences/${ userId }. Payload: ${ JSON.stringify(payload) }`);

cy.setRancherResource('v1', 'userpreferences', userId, payload).then(() => {
return cy.waitForRancherResource('v1', 'userpreferences', userId, (resp: any) => compare(resp?.body, payload))
.then((res) => {
if (res) {
cy.log(`tableRowsPerPageAndNamespaceFilter: Success!`);
cy.log(`tableRowsPerPageAndPreferences: Success!`);
} else {
if (iteration < 3) {
cy.log(`tableRowsPerPageAndNamespaceFilter: Failed! Going to retry...`);
cy.log(`tableRowsPerPageAndPreferences: Failed! Going to retry...`);

return cy.tableRowsPerPageAndNamespaceFilter(rows, clusterName, groupBy, namespaceFilter, iteration + 1);
return cy.tableRowsPerPageAndPreferences(rows, preferences, iteration + 1);
}

cy.log(`tableRowsPerPageAndNamespaceFilter: Failed! Giving up...`);
cy.log(`tableRowsPerPageAndPreferences: Failed! Giving up...`);

return Promise.reject(new Error('tableRowsPerPageAndNamespaceFilter failed'));
return Promise.reject(new Error('tableRowsPerPageAndPreferences failed'));
}
});
});
});
});

Cypress.Commands.add('tableRowsPerPageAndNamespaceFilter', (rows: number, clusterName: string, groupBy: string, namespaceFilter: string) => {
return cy.tableRowsPerPageAndPreferences(rows, {
clusterName, groupBy, namespaceFilter
});
});
3 changes: 2 additions & 1 deletion shell/config/pagination-table-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export const STEVE_NAMESPACE_COL = {

export const STEVE_EVENT_OBJECT = {
...OBJECT,
sort: 'involvedObject.kind',
sort: 'involvedObject.kind',
search: 'involvedObject.kind',
};

export const STEVE_LIST_GROUPS = [{
Expand Down
Loading

0 comments on commit df685b0

Please sign in to comment.