Skip to content

Commit b075e80

Browse files
authored
Merge pull request #155 from jpinsonneau/cypress
Cypress integration tests
2 parents 0cf1f52 + 3a07beb commit b075e80

File tree

11 files changed

+2652
-92
lines changed

11 files changed

+2652
-92
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
/plugin-backend
99
/coverage.out
1010
tmp.Dockerfile
11+
/web/cypress/videos

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ test-frontend:
7171
@echo "### Testing frontend"
7272
cd web && npm run test
7373

74+
.PHONY: cypress
75+
cypress:
76+
@echo "### Opening cypress"
77+
cd web && npm run cypress:open
78+
7479
.PHONY: test
7580
test: test-backend test-frontend
7681

web/cypress.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"defaultCommandTimeout": 10000,
3+
"projectId": "tjknpb"
4+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/// <reference types="cypress" />
2+
3+
import * as c from '../../support/const'
4+
5+
describe('netflow-table', () => {
6+
beforeEach(() => {
7+
cy.openNetflowTrafficPage();
8+
});
9+
10+
it('displays table and rows', () => {
11+
cy.get('#table-container').should('exist');
12+
//expect 100 results without filters
13+
cy.get('#table-container').find('tr').its('length').should('be.gte', 100);
14+
cy.get('#flowsCount').contains('100 flows');
15+
16+
cy.addCommonFilter('namespace', c.namespace);
17+
cy.addCommonFilter('name', c.pod);
18+
cy.changeQueryOption('Match all');
19+
cy.changeQueryOption('Both');
20+
cy.changeQueryOption('1000');
21+
cy.changeTimeRange('Last 1 day');
22+
});
23+
24+
it('manage columns', () => {
25+
//first open modal
26+
cy.openColumnsModal();
27+
28+
//Select all columns
29+
cy.get('#columns-modal').contains('Select all').click();
30+
31+
//Save
32+
cy.get('#columns-modal').contains('Save').click();
33+
cy.checkColumns(23, 45);
34+
35+
//reopen modal
36+
cy.openColumnsModal();
37+
38+
//Unselect all columns
39+
cy.get('#columns-modal').contains('Unselect all').click();
40+
41+
//Save should be disabled
42+
cy.get('#columns-modal').contains('Save').should('be.disabled');
43+
44+
//Select some columns
45+
cy.selectColumns(['Start Time', 'Names', 'Packets']);
46+
47+
//Save new columns
48+
cy.get('#columns-modal').contains('Save').click();
49+
50+
//Should not have nested columns and have 3 columns
51+
cy.checkColumns(0, 3);
52+
53+
//reopen modal
54+
cy.openColumnsModal();
55+
56+
//add End Time, Owners, Ports
57+
//remove Packets
58+
cy.selectColumns(['End Time', 'Owners', 'Ports', 'Packets']);
59+
60+
//Save new columns
61+
cy.get('#columns-modal').contains('Save').click();
62+
63+
//Should not have nested columns and have 5 columns
64+
cy.checkColumns(0, 5);
65+
66+
//reopen modal
67+
cy.openColumnsModal();
68+
69+
//Restore default columns
70+
cy.get('#columns-modal').contains('Restore default columns').click();
71+
72+
//Save default columns
73+
cy.get('#columns-modal').contains('Save').click();
74+
cy.checkColumns();
75+
});
76+
77+
it('sort columns', () => {
78+
//TODO: check data after each sort
79+
cy.sortColumn('Name');
80+
cy.sortColumn('Namespace');
81+
cy.sortColumn('Port');
82+
cy.sortColumn('Packets');
83+
});
84+
})
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/// <reference types="cypress" />
2+
3+
import * as c from '../../support/const'
4+
5+
describe('netflow-topology', () => {
6+
beforeEach(() => {
7+
cy.openNetflowTrafficPage();
8+
//move to topology view
9+
cy.get('#topologyViewButton').click();
10+
});
11+
12+
it('displays topology and namespaces', () => {
13+
cy.get('.pf-topology-visualization-surface').should('exist');
14+
//expect some namespaces & edges in the default layer
15+
cy.get('[data-layer-id="default"]').children().its('length').should('be.gte', 100);
16+
17+
cy.addCommonFilter('namespace', c.namespace, true);
18+
cy.addCommonFilter('name', c.pod, true);
19+
cy.changeMetricFunction('Rate');
20+
cy.changeMetricFunction('Max');
21+
cy.changeMetricFunction('Avg');
22+
cy.changeMetricFunction('Sum');
23+
cy.changeMetricType('Packets');
24+
cy.changeMetricType('Bytes');
25+
cy.changeQueryOption('Both', true);
26+
cy.changeQueryOption('Match all', true);
27+
cy.changeTimeRange('Last 1 day', true);
28+
});
29+
30+
it('find network observability namespace', () => {
31+
//type our namespace name and press enter
32+
cy.get('#search-topology-element-input').type(`${c.namespace}{enter}`);
33+
//cy.get('.node-highlighted').should('exist');
34+
35+
//should show the drawer
36+
cy.get('.pf-c-drawer__panel-main').should('exist');
37+
cy.get('#metrics').should('exist');
38+
cy.get('.pf-c-chart').should('exist');
39+
40+
//close drawer
41+
cy.get('.pf-c-drawer__close').click();
42+
cy.get('.pf-c-drawer__panel-main').should('not.exist');
43+
});
44+
45+
it('update options', () => {
46+
//open options panel
47+
cy.get('.pf-topology-control-bar').find('#options').click();
48+
cy.get('.pf-c-drawer__panel-main').should('exist');
49+
50+
//select some displays
51+
cy.dropdownSelect('layout-dropdown', 'Cola');
52+
cy.dropdownSelect('layout-dropdown', 'Dagre');
53+
cy.dropdownSelect('layout-dropdown', 'Concentric');
54+
cy.dropdownSelect('layout-dropdown', 'Grid');
55+
56+
//select some scopes / groups
57+
cy.dropdownSelect('scope-dropdown', 'host');
58+
cy.get('#group-dropdown').should('be.disabled');
59+
60+
cy.dropdownSelect('scope-dropdown', 'namespace');
61+
cy.dropdownSelect('group-dropdown', 'hosts');
62+
63+
cy.dropdownSelect('scope-dropdown', 'owner');
64+
cy.dropdownSelect('group-dropdown', 'namespaces');
65+
66+
cy.dropdownSelect('scope-dropdown', 'resource');
67+
cy.dropdownSelect('group-dropdown', 'owners');
68+
69+
//toggle switches
70+
cy.get('#group-collapsed-switch').click();
71+
cy.dropdownSelect('group-dropdown', 'none');
72+
cy.get('#group-collapsed-switch').should('be.disabled');
73+
74+
cy.get('#edges-tag-switch').should('not.be.disabled');
75+
cy.get('#edges-tag-switch').click();
76+
cy.get('#edges-switch').click();
77+
cy.get('#edges-tag-switch').should('be.disabled');
78+
79+
cy.get('#badge-switch').click();
80+
81+
cy.dropdownSelect('truncate-dropdown', '10');
82+
});
83+
})

web/cypress/plugins/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference types="cypress" />
2+
// ***********************************************************
3+
// This plugins/index.js can be used to load plugins
4+
//
5+
// You can change the location of this file or turn off loading
6+
// the plugins file with the 'pluginsFile' configuration option.
7+
//
8+
// You can read more here:
9+
// https://on.cypress.io/plugins-guide
10+
// ***********************************************************
11+
12+
// This function is called when a project is opened or re-opened (e.g. due to
13+
// the project's config changing)
14+
15+
/**
16+
* @type {Cypress.PluginConfig}
17+
*/
18+
// eslint-disable-next-line no-unused-vars
19+
module.exports = (on, config) => {
20+
// `on` is used to hook into various events Cypress emits
21+
// `config` is the resolved Cypress config
22+
}

web/cypress/support/commands.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// ***********************************************
2+
// This commands.js file
3+
// create various custom commands and overwrite
4+
// existing commands.
5+
//
6+
// For more comprehensive examples of custom
7+
// commands please read more here:
8+
// https://on.cypress.io/custom-commands
9+
// ***********************************************
10+
11+
import * as c from './const'
12+
13+
Cypress.Commands.add('openNetflowTrafficPage', () => {
14+
//clear local storage to ensure to be in default view = table
15+
cy.clearLocalStorage();
16+
cy.visit(c.url);
17+
});
18+
19+
Cypress.Commands.add('checkColumns', (groups = 5, cols = 9) => {
20+
if (groups === 0) {
21+
//Should not have nested columns
22+
cy.get('thead>tr').should('have.length', 1);
23+
24+
//Should have correct number of columns
25+
cy.get('thead>tr').children().should('have.length', cols);
26+
} else {
27+
//Should have nested columns
28+
cy.get('thead>tr').should('have.length', 2);
29+
30+
//Should have correct number of groups
31+
cy.get('thead>tr').eq(0).children().should('have.length', groups);
32+
//Should have correct number of columns
33+
cy.get('thead>tr').eq(1).children().should('have.length', cols);
34+
}
35+
});
36+
37+
Cypress.Commands.add('openColumnsModal', () => {
38+
cy.get('#manage-columns-button').click();
39+
cy.get('#columns-modal').should('exist');
40+
});
41+
42+
Cypress.Commands.add('selectColumns', (names) => {
43+
for (let i = 0; i < names.length; i++) {
44+
cy.get('.modal-body').contains(names[i]).click();
45+
}
46+
});
47+
48+
Cypress.Commands.add('sortColumn', (name) => {
49+
cy.get('thead').contains(name).click();
50+
cy.get('[aria-sort="ascending"]').should('have.length', 1);
51+
cy.get('[aria-sort="descending"]').should('have.length', 0);
52+
cy.get('thead').contains(name).click();
53+
cy.get('[aria-sort="ascending"]').should('have.length', 0);
54+
cy.get('[aria-sort="descending"]').should('have.length', 1);
55+
});
56+
57+
Cypress.Commands.add('dropdownSelect', (id, name) => {
58+
cy.get(`#${id}`).click();
59+
cy.get('.pf-c-dropdown__menu').should('exist');
60+
cy.get('.pf-c-dropdown__menu').find(`#${name}`).click();
61+
});
62+
63+
Cypress.Commands.add('checkContent', (topology) => {
64+
if (topology) {
65+
cy.get('[data-layer-id="default"]').children().its('length').should('be.gte', 5);
66+
} else {
67+
cy.get('#table-container').find('tr').its('length').should('be.gte', 5);
68+
}
69+
});
70+
71+
Cypress.Commands.add('addCommonFilter', (filter, value, topology) => {
72+
cy.get('#column-filter-toggle').click();
73+
cy.get('.pf-c-accordion__expanded-content-body').find(`#${filter}`).click();
74+
cy.get('.pf-c-accordion__expanded-content-body').should('not.exist');
75+
cy.get('#column-filter-dropdown').parent().children().eq(1).type(`${value}{enter}`);
76+
cy.checkContent(topology);
77+
});
78+
79+
Cypress.Commands.add('changeQueryOption', (name, topology) => {
80+
cy.get('[aria-label="Options menu"]').click();
81+
cy.get('#query-options-dropdown').contains(name).click();
82+
cy.get('[aria-label="Options menu"]').click();
83+
cy.checkContent(topology);
84+
});
85+
86+
Cypress.Commands.add('changeTimeRange', (name, topology) => {
87+
cy.get('#time-range-dropdown-dropdown').click();
88+
cy.get('.pf-c-dropdown__menu').contains(name).click();
89+
cy.checkContent(topology);
90+
});
91+
92+
Cypress.Commands.add('changeMetricFunction', (name) => {
93+
cy.get('#metricFunction-dropdown').click();
94+
cy.get('.pf-c-dropdown__menu').contains(name).click();
95+
cy.get('[data-layer-id="default"]').children().its('length').should('be.gte', 5);
96+
});
97+
98+
Cypress.Commands.add('changeMetricType', (name) => {
99+
cy.get('#metricType-dropdown').click();
100+
cy.get('.pf-c-dropdown__menu').contains(name).click();
101+
cy.get('[data-layer-id="default"]').children().its('length').should('be.gte', 5);
102+
});

web/cypress/support/const.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//set all your shared const here
2+
export const url = 'http://localhost:9000/netflow-traffic';
3+
export const namespace = 'network-observability{enter}';
4+
export const pod = 'flowlogs-pipeline';

web/cypress/support/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// ***********************************************************
2+
// This support/index.js is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can read more here:
9+
// https://on.cypress.io/configuration
10+
// ***********************************************************
11+
12+
import './commands'

0 commit comments

Comments
 (0)