From 563dd82236a1628dcce389031193794bb9e2a913 Mon Sep 17 00:00:00 2001 From: LightOfHeaven1994 Date: Mon, 3 Feb 2025 17:38:36 +0100 Subject: [PATCH] chore(RHINENG-15653): Cleanup ReportsComponent --- cypress/fixtures/reports.json | 89 ---- cypress/utils/interceptors.js | 14 + src/SmartComponents/Reports/Reports.cy.js | 538 ++++++++++++++------ src/SmartComponents/Reports/Reports.js | 68 +-- src/SmartComponents/Reports/Reports.test.js | 71 --- src/SmartComponents/Reports/constants.js | 35 -- src/__factories__/reports.js | 50 ++ 7 files changed, 446 insertions(+), 419 deletions(-) delete mode 100644 cypress/fixtures/reports.json delete mode 100644 src/SmartComponents/Reports/constants.js create mode 100644 src/__factories__/reports.js diff --git a/cypress/fixtures/reports.json b/cypress/fixtures/reports.json deleted file mode 100644 index 7b8f775cf..000000000 --- a/cypress/fixtures/reports.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "profiles": { - "edges": [ - { "node": { - "id":"4051e704-f984-4bf6-81f4-cd2113a92d97", - "name":"PCI-DSS v3.2.1 Control Baseline for Red Hat Enterprise Linux 7", - "refId":"xccdf_org.ssgproject.content_profile_pci-dss", - "description":"Ensures PCI-DSS v3.2.1 security configuration settings are applied.", - "policyType":"PCI-DSS v3.2.1 Control Baseline for Red Hat Enterprise Linux 7", - "totalHostCount":4, - "testResultHostCount":2, - "compliantHostCount":1, - "unsupportedHostCount":1, - "osMajorVersion":"7", - "complianceThreshold":95.0, - "businessObjective":null, - "policy": { - "id":"4051e704-f984-4bf6-81f4-cd2113a92d97", - "name":"PCI-DSS v3.2.1 Control Baseline for Red Hat Enterprise Linux 7", - "__typename":"Profile" - }, - "benchmark": { - "id":"156f766e-082f-4e60-80e3-df8d6d908f6e", - "version":"0.1.66", - "__typename":"Benchmark" - }, - "__typename":"Profile" - }, - "__typename":"ProfileEdge" - }, - { - "node": { - "id": "1de468f1-5d4b-499a-88ce-82c040e6d1a0", - "name": "CIS Red Hat Enterprise Linux 8 Benchmark for Level 2 - Server", - "refId": "xccdf_org.ssgproject.content_profile_cis", - "description": "This profile defines a baseline that aligns to the \"Level 2 - Server\"\nconfiguration from the Center for Internet Security® Red Hat Enterprise\nLinux 8 Benchmark™, v1.0.1, released 2021-05-19.\n\nThis profile includes Center for Internet Security®\nRed Hat Enterprise Linux 8 CIS Benchmarks™ content.", - "policyType": "CIS Red Hat Enterprise Linux 8 Benchmark for Level 2 - Server", - "totalHostCount": 6, - "testResultHostCount": 0, - "compliantHostCount": 0, - "unsupportedHostCount": 1, - "osMajorVersion": "8", - "complianceThreshold": 99, - "businessObjective": null, - "policy": { - "id": "1de468f1-5d4b-499a-88ce-82c040e6d1a0", - "name": "CIS Red Hat Enterprise Linux 8 Benchmark for Level 2 - Server", - "__typename": "Profile" - }, - "benchmark": { - "id": "153f8a4a-0513-4ac1-bee0-3f37c7467c7d", - "version": "0.1.57", - "__typename": "Benchmark" - }, - "__typename": "Profile" - }, - "__typename": "ProfileEdge" - }, - { "node": { - "id":"1028080b-89f7-4d6c-8f73-fa50df0c4da9", - "name":"Example Server Profile", - "refId":"xccdf_org.ssgproject.content_profile_CS2", - "description":"This profile is an example of a customized server profile.", - "policyType":"Example Server Profile", - "totalHostCount":1, - "testResultHostCount":1, - "compliantHostCount":0, - "unsupportedHostCount":0, - "osMajorVersion":"6", - "complianceThreshold":100.0, - "businessObjective":null, - "policy": { - "id":"1028080b-89f7-4d6c-8f73-fa50df0c4da9", - "name":"Example Server Profile", - "__typename":"Profile" - }, - "benchmark": { - "id":"d35778a9-1fb9-40d8-bf9a-9b3043704b97", - "version":"0.1.28", - "__typename":"Benchmark" - }, - "__typename":"Profile" - }, - "__typename":"ProfileEdge" - } - ], - "__typename": "ProfileConnection" - } - } \ No newline at end of file diff --git a/cypress/utils/interceptors.js b/cypress/utils/interceptors.js index 39a64e989..b039b1932 100644 --- a/cypress/utils/interceptors.js +++ b/cypress/utils/interceptors.js @@ -27,3 +27,17 @@ export const featureFlagsInterceptors = { }); }, }; + +export const interceptReportsBatch = (endpoint, offset, dataSlice, total, limit=10) => { + cy.intercept(new RegExp(`/api/compliance/v2/${endpoint}?.*limit=${limit}.*offset=${offset}.*`), { + statusCode: 200, + body: { + data: dataSlice, + meta: { + limit: 10, + offset, + total: total, + } + } + }).as(`getReportsBatch${offset / 10 + 1}`); // getReportsBatch1, getReportsBatch2, etc +}; diff --git a/src/SmartComponents/Reports/Reports.cy.js b/src/SmartComponents/Reports/Reports.cy.js index 7db0938d3..781954dfa 100644 --- a/src/SmartComponents/Reports/Reports.cy.js +++ b/src/SmartComponents/Reports/Reports.cy.js @@ -1,57 +1,47 @@ -import React from 'react'; import Reports from './Reports'; -import { MemoryRouter } from 'react-router-dom'; -import { - ApolloProvider, - ApolloClient, - HttpLink, - InMemoryCache, -} from '@apollo/client'; -import { Provider } from 'react-redux'; -import { COMPLIANCE_API_ROOT } from '@/constants'; import { init } from 'Store'; -import fixtures from '../../../cypress/fixtures/reports.json'; import { featureFlagsInterceptors } from '../../../cypress/utils/interceptors'; -import FlagProvider from '@unleash/proxy-client-react'; - -const client = new ApolloClient({ - link: new HttpLink({ - credentials: 'include', - uri: COMPLIANCE_API_ROOT + '/graphql', - }), - cache: new InMemoryCache(), -}); +import { buildReports } from '../../__factories__/reports'; +import { interceptReportsBatch } from '../../../cypress/utils/interceptors'; + const mountComponent = () => { - cy.mount( - - - - - - - - - - ); + cy.mountWithContext(Reports, { store: init().getStore() }); }; -const profilesResp = Object.assign([], fixtures['profiles']['edges']); +const reportsData = buildReports(21); +const reportsResp = { + data: reportsData, + meta: { + total: reportsData.length, + }, +}; describe('Reports table tests', () => { beforeEach(() => { - featureFlagsInterceptors.apiV2Disabled(); - cy.intercept('**/graphql', { + featureFlagsInterceptors.apiV2Enabled(); + + cy.intercept('/api/compliance/v2/reports/os_versions', { statusCode: 200, - body: { - data: fixtures, - }, - }); + body: [6, 7, 8, 9], + }).as('getOsVersions'); + + // Ignore total and os_versions endpoints + cy.intercept( + 'api/compliance/v2/reports?limit=10&offset=0&sort_by=title%3Aasc&filter=%28with_reported_systems+%3D+true%29', + { + statusCode: 200, + body: reportsResp, + } + ).as('getReports'); + + cy.intercept( + '/api/compliance/v2/reports?limit=1&filter=with_reported_systems%3Dtrue', + { + statusCode: 200, + body: reportsResp, + } + ).as('getReportsTotal'); + mountComponent(); }); describe('defaults', () => { @@ -60,88 +50,210 @@ describe('Reports table tests', () => { }); }); - describe('table column filtering', () => { + describe('Table column sorting', () => { it('Sort by Name', () => { - let profileNames = []; - profilesResp.forEach((item) => { - profileNames.push(item['node']['name']); - }); - const ascendingSorted = [...profileNames].sort(); - const descendingSorted = [...profileNames].sort().reverse(); - + cy.wait('@getReports'); cy.get('th[data-label="Policy"]') .invoke('attr', 'aria-sort') .should('eq', 'ascending'); - cy.get('td[data-label="Policy"] a').each((item, index) => { - expect(Cypress.$(item).text()).to.eq(ascendingSorted[index]); - }); + + cy.intercept(/\/api\/compliance\/v2\/reports\?.*sort_by=title%3Adesc.*/, { + statusCode: 200, + body: { + data: reportsData.slice(0, 10), + meta: { + limit: 10, + total: reportsData.length, + }, + }, + }).as('getSortedReports'); cy.get('th[data-label="Policy"] > button').click(); + cy.wait('@getSortedReports') + .its('request.url') + .should('contain', 'sort_by=title%3Adesc'); cy.get('th[data-label="Policy"]') .invoke('attr', 'aria-sort') .should('eq', 'descending'); - cy.get('td[data-label="Policy"] a').each((item, index) => { - expect(Cypress.$(item).text()).to.eq(descendingSorted[index]); - }); }); it('Sort by Operating system', () => { - let rhelVersions = []; - profilesResp.forEach((item) => { - rhelVersions.push('RHEL ' + item['node']['osMajorVersion']); - }); - const ascendingSorted = [...rhelVersions].sort(); - const descendingSorted = [...rhelVersions].sort().reverse(); - + cy.wait('@getReports'); + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*sort_by=os_major_version%3Aasc.*/, + { + statusCode: 200, + body: { + data: reportsData.slice(0, 10), + meta: { + limit: 10, + total: reportsData.length, + }, + }, + } + ).as('getSortedReports'); cy.get('th[data-label="Operating system"] > button').click(); cy.get('th[data-label="Operating system"]') .invoke('attr', 'aria-sort') .should('eq', 'ascending'); - cy.get('td[data-label="Operating system"]').each((item, index) => { - expect(Cypress.$(item).text()).to.eq(ascendingSorted[index]); - }); - cy.get('th[data-label="Operating system"] > button').click(); + cy.wait('@getSortedReports') + .its('request.url') + .should('contain', 'sort_by=os_major_version%3Aasc'); + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*sort_by=os_major_version%3Adesc.*/, + { + statusCode: 200, + body: { + data: reportsData.slice(0, 10), + meta: { + limit: 10, + total: reportsData.length, + }, + }, + } + ).as('getSortedReports'); + + cy.get('th[data-label="Operating system"] > button').click(); cy.get('th[data-label="Operating system"]') .invoke('attr', 'aria-sort') .should('eq', 'descending'); - cy.get('td[data-label="Operating system"]').each((item, index) => { - expect(Cypress.$(item).text()).to.eq(descendingSorted[index]); - }); + cy.wait('@getSortedReports') + .its('request.url') + .should('contain', 'sort_by=os_major_version%3Adesc'); + }); + + it('Sort by Systems meeting compliance', () => { + cy.wait('@getReports'); + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*sort_by=percent_compliant%3Aasc.*/, + { + statusCode: 200, + body: { + data: reportsData.slice(0, 10), + meta: { + limit: 10, + total: reportsData.length, + }, + }, + } + ).as('getSortedReports'); + cy.get('th[data-label="Systems meeting compliance"] > button').click(); + cy.get('th[data-label="Systems meeting compliance"]') + .invoke('attr', 'aria-sort') + .should('eq', 'ascending'); + cy.wait('@getSortedReports') + .its('request.url') + .should('contain', 'sort_by=percent_compliant%3Aasc'); + + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*sort_by=percent_compliant%3Adesc.*/, + { + statusCode: 200, + body: { + data: reportsData.slice(0, 10), + meta: { + limit: 10, + total: reportsData.length, + }, + }, + } + ).as('getSortedReports'); + + cy.get('th[data-label="Systems meeting compliance"] > button').click(); + cy.get('th[data-label="Systems meeting compliance"]') + .invoke('attr', 'aria-sort') + .should('eq', 'descending'); + cy.wait('@getSortedReports') + .its('request.url') + .should('contain', 'sort_by=percent_compliant%3Adesc'); }); }); describe('table pagination', () => { - it.skip('Set per page elements', () => { - const perPage = [ - '10 per page', - '20 per page', - '50 per page', - '100 per page', - ]; - - cy.ouiaType('PF5/PaginationOptionsMenu', 'div') - .ouiaType('PF5/DropdownToggle', 'button') - .each(($pagOptMenu) => { - perPage.forEach(function (perPageValue) { - cy.wrap($pagOptMenu).click(); - cy.ouiaType('PF5/DropdownItem', 'button') - .contains(perPageValue) - .click(); - cy.get('table').should('have.length', 1); - }); - }); + it('Set per page elements', () => { + cy.wait('@getReports'); + cy.ouiaType('PF5/Toolbar', 'div') + .ouiaType('PF5/Pagination', 'div') + .ouiaType('PF5/MenuToggle', 'button') + .should('contain', `1 - 10 of ${reportsData.length}`); + + const perPageOptions = [20, 50, 100]; + perPageOptions.forEach((perPageValue) => { + const mockedRequestURL = new RegExp( + `/api/compliance/v2/reports.*[?&]limit=${perPageValue}(&|$).*` + ); + cy.intercept(mockedRequestURL, { + statusCode: 200, + body: { + data: reportsData.slice(0, perPageValue), + meta: { + limit: perPageValue, + total: reportsData.length, + }, + }, + }).as('getPaginatedReports'); + + cy.ouiaType('PF5/Toolbar', 'div') + .ouiaType('PF5/Pagination', 'div') + .ouiaType('PF5/MenuToggle', 'button') + .click(); + + cy.get('button[role="menuitem"]') + .contains(`${perPageValue} per page`) + .click(); + + cy.wait('@getPaginatedReports') + .its('request.url') + .should('contain', `limit=${perPageValue}`); + + cy.get('table') + .find('tbody') + .find('tr') + .should( + 'have.length', + reportsData.length > perPageValue + ? perPageValue + : reportsData.length + ); + }); }); }); describe('Reports download', () => { + beforeEach(() => { + cy.wait('@getReports'); + interceptReportsBatch( + 'reports', + 0, + reportsData.slice(0, 10), + reportsData.length + ); + interceptReportsBatch( + 'reports', + 10, + reportsData.slice(10, 20), + reportsData.length + ); + interceptReportsBatch( + 'reports', + 20, + reportsData.slice(20, 30), + reportsData.length + ); + }); it('CSV report download and content', () => { cy.get('button[aria-label="Export"]').click(); cy.get('button[aria-label="Export to CSV"]').click(); - // get the newest csv file - cy.exec('ls cypress/downloads | grep .csv | sort -n | tail -1').then( + + cy.wait('@getReportsBatch1'); + cy.wait('@getReportsBatch2'); + cy.wait('@getReportsBatch3'); + + // check if file downloaded and not empty + cy.exec(`ls cypress/downloads | grep .csv | sort -n | tail -1`).then( function (result) { let res = result.stdout; cy.readFile('cypress/downloads/' + res).should('not.be.empty'); @@ -151,7 +263,11 @@ describe('Reports table tests', () => { it('JSON report download and content', () => { cy.get('button[aria-label="Export"]').click(); cy.get('button[aria-label="Export to JSON"]').click(); - // get the newest csv file + cy.wait('@getReportsBatch1'); + cy.wait('@getReportsBatch2'); + cy.wait('@getReportsBatch3'); + + // validate json content cy.exec('ls cypress/downloads | grep .json | sort -n | tail -1').then( function (result) { let res = result.stdout; @@ -159,31 +275,27 @@ describe('Reports table tests', () => { .should('not.be.empty') .then((fileContent) => { assert( - fileContent.length === profilesResp.length, + fileContent.length === reportsData.length, 'Length of profiles is different' ); fileContent.forEach((item) => { - profilesResp.forEach((profile) => { - if (profile['node']['name'] == item['Policy']) { - let profileRHEL = - 'RHEL ' + profile['node']['osMajorVersion']; + reportsData.forEach((report) => { + if (report.title == item['policy']) { assert( - item['OperatingSystem'].includes(profileRHEL), - `Operating system values are not equal: JSON has ${item['OperatingSystem']} value but table has ${profileRHEL}` + item['operatingSystem'].includes(report.os_major_version), + `Operating system values are not equal: JSON has ${item['operatingSystem']} value but table has ${report.os_major_version}` ); - - let profilesSystemMeetingCompliance = `${profile['node']['compliantHostCount']} of ${profile['node']['testResultHostCount']} systems`; - let unsupportedCount = - profile['node']['unsupportedHostCount']; + let systemMeetingCompliance = `${report.compliant_system_count} of ${report.reported_system_count} systems`; + let unsupportedCount = report.unsupported_system_count; if (unsupportedCount != 0) { - profilesSystemMeetingCompliance = - profilesSystemMeetingCompliance + + systemMeetingCompliance = + systemMeetingCompliance + ` | ${unsupportedCount} unsupported`; } assert( - item['SystemsMeetingCompliance'] === - profilesSystemMeetingCompliance, - `Systems meeting compliance values are not equal: JSON has ${item['SystemsMeetingCompliance']} value but table has ${profilesSystemMeetingCompliance}` + item['systemsMeetingCompliance'] === + systemMeetingCompliance, + `Systems meeting compliance values are not equal: JSON has ${item['systemsMeetingCompliance']} value but json has ${report.compliant_system_count}` ); } }); @@ -194,84 +306,192 @@ describe('Reports table tests', () => { }); }); - describe.skip('Filter table', () => { - it('Search by non existing name', () => { - cy.ouiaId('ConditionalFilter', 'button').click(); - cy.ouiaId('Policy name', 'button').click(); - cy.ouiaId('ConditionalFilter', 'input').type('Foo bar'); + describe('Filter table', () => { + it.skip('Search by non existing name', () => { + // No matching results found is returned, table bug + cy.wait('@getReports'); + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*title\+%7E\+%22foo\+bar%22.*/, + { + statusCode: 200, + body: { + data: [], + meta: { + total: 0, + }, + }, + } + ).as('getFilteredReports'); + + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="Conditional filter toggle"]') + .click(); + // cy.ouiaId('ConditionalFilter', 'button').click(); + cy.ouiaId('Policy name', 'li').click(); + cy.ouiaId('ConditionalFilter', 'input').type('foo bar', { delay: 0 }); + cy.wait('@getFilteredReports') + .its('request.url') + .should('contain', 'title+%7E+%22foo+bar%22'); + cy.get('div[class="pf-v5-c-empty-state"]').contains( 'No matching reports found' ); }); it('Find report by Name', () => { - cy.ouiaId('ConditionalFilter', 'button').click(); - cy.ouiaId('Policy name', 'button').click(); - cy.ouiaId('ConditionalFilter', 'input').type('PCI-DSS v3.2.1 Control'); - cy.get('td[data-label="Policy"] a') - .should('have.length', 1) - .first() - .contains('PCI-DSS v3.2.1 Control'); - }); - it('Find report by Policy type', () => { - cy.ouiaId('ConditionalFilter', 'button').click(); - cy.ouiaId('Policy type', 'button').click(); - cy.ouiaId('Filter by policy type', 'div').click(); - cy.get('input[id$="Example Server Profile"]').click(); + cy.wait('@getReports'); + const reportTitle = reportsData[0].title; + const reportTitleReg = reportTitle.replace(/ /g, '\\+'); + const mockedRequestURL = new RegExp( + `/api/compliance/v2/reports.*title\\+%7E\\+%22${reportTitleReg}%22.*` + ); + + cy.intercept(mockedRequestURL, { + statusCode: 200, + body: { + data: [reportsData[0]], + meta: { + total: 1, + }, + }, + }).as('getFilteredReports'); + + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="Conditional filter toggle"]') + .click(); + // cy.ouiaId('ConditionalFilter', 'button').click(); + cy.ouiaId('Policy name', 'li').click(); + cy.ouiaId('ConditionalFilter', 'input').type(reportTitle, { delay: 0 }); + cy.wait('@getFilteredReports') + .its('request.url') + .should('contain', reportTitle.replace(/ /g, '+')); cy.get('td[data-label="Policy"] a') .should('have.length', 1) .first() - .contains('Example Server Profile'); + .contains(reportTitle); }); - it('Find report by Operating system', () => { - cy.ouiaId('ConditionalFilter', 'button').click(); - cy.ouiaId('Operating system', 'button').click(); - cy.ouiaId('Filter by operating system', 'div').click(); - cy.get('input[id$="-7"]').click(); + it.only('Find report by Operating system', () => { + cy.wait('@getReports'); + const reportOSVersion = reportsData[0].os_major_version; + const mockedRequestURL = new RegExp( + `/api/compliance/v2/reports.*os_major_version\\+%5E\\+%28${reportOSVersion}%29.*` + ); + cy.intercept(mockedRequestURL, { + statusCode: 200, + body: { + data: [reportsData[0]], + meta: { + total: 1, + }, + }, + }).as('getFilteredReports'); + + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="Conditional filter toggle"]') + .click(); + // cy.ouiaId('ConditionalFilter', 'button').click(); + cy.ouiaId('Operating system', 'li').click(); + // cy.ouiaId('Filter by operating system', 'div').click(); + cy.contains('button', 'Filter by operating system').click(); + cy.contains('span', 'RHEL 7').parent().find('input').check(); + cy.wait('@getFilteredReports') + .its('request.url') + .should('contain', `os_major_version+%5E+%28${reportOSVersion}%29`); cy.get('td[data-label="Operating system"]') .should('have.length', 1) .first() - .contains('RHEL 7'); + .contains(`RHEL ${reportOSVersion}`); }); it('Find report by Systems meeting compliance', () => { - cy.ouiaId('ConditionalFilter', 'button').click(); - cy.ouiaId('Systems meeting compliance', 'button').click(); - cy.ouiaId('Filter by systems meeting compliance', 'div').click(); - cy.get('input[id$="-50-69"]').click(); + cy.wait('@getReports'); + // percent_compliant+%3E%3D+90+AND+percent_compliant+%3C%3D+100%29%29 - cy.get('td[data-label="Policy"] > div > a') - .should('have.length', 1) - .first() - .contains('PCI-DSS v3.2.1 Control'); + // const mockedRequestURL = new RegExp(`/api/compliance/v2/reports.*percent_compliant\\+%3E%3D\\+90\\+AND\\+percent_compliant+%3C%3D+100%29%29.*`); + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*percent_compliant\+%3E%3D\+90\+AND\+percent_compliant\+%3C%3D\+100%29%29/, + { + statusCode: 200, + body: { + data: [reportsData[0]], + meta: { + total: 1, + }, + }, + } + ).as('getFilteredReports'); + + // cy.ouiaId('ConditionalFilter', 'button').click(); + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="Conditional filter toggle"]') + .click(); + + cy.ouiaId('Systems meeting compliance', 'li').click(); + cy.contains('button', 'Filter by systems meeting compliance').click(); + cy.contains('span', '90 - 100%').parent().find('input').check(); + cy.wait('@getFilteredReports') + .its('request.url') + .should( + 'contain', + `percent_compliant+%3E%3D+90+AND+percent_compliant+%3C%3D+100%29%29` + ); }); it('Clear filters works', () => { - cy.ouiaId('ConditionalFilter', 'button').click(); - cy.ouiaId('Policy name', 'button').click(); - cy.ouiaId('ConditionalFilter', 'input').type('Foo bar'); + cy.wait('@getReports'); + cy.intercept( + /\/api\/compliance\/v2\/reports\?.*title\+%7E\+%22foo\+bar%22.*/, + { + statusCode: 200, + body: { + data: [], + meta: { + total: 0, + }, + }, + } + ).as('getFilteredReports'); + + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="Conditional filter toggle"]') + .click(); + // cy.ouiaId('ConditionalFilter', 'button').click(); + cy.ouiaId('Policy name', 'li').click(); + cy.ouiaId('ConditionalFilter', 'input').type('foo bar', { delay: 0 }); + cy.wait('@getFilteredReports') + .its('request.url') + .should('contain', 'title+%7E+%22foo+bar%22'); cy.ouiaId('ClearFilters', 'button').should('be.visible').click(); + cy.wait('@getReports'); cy.ouiaId('ClearFilters', 'button').should('not.exist'); }); }); - // TODO pf/react-core 5.4.0 seems to have broken `ouiaId`s - describe.skip('Manage columns', () => { + describe('Manage columns', () => { it('Manage reports columns', () => { - cy.ouiaId('BulkActionsToggle', 'button').click(); + // TODO pf/react-core 5.4.0 seems to have broken `ouiaId`s + // cy.ouiaId('BulkActionsToggle', 'button').click(); + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="kebab dropdown toggle"]') + .click(); + cy.ouiaType('PF5/DropdownItem', 'li').first().find('button').click(); cy.get('input[checked]') .not('[disabled]') .each(($checkbox) => { cy.wrap($checkbox).click(); }); - cy.ouiaId('Save', 'button').click(); + cy.ouiaId('ColumnManagementModal-save-button', 'button').click(); cy.get('th[data-label="Operating system"]').should('not.exist'); cy.get('th[data-label="Systems meeting compliance"]').should('not.exist'); - cy.ouiaId('BulkActionsToggle', 'button').click(); + //cy.ouiaId('BulkActionsToggle', 'button').click(); + cy.ouiaId('PrimaryToolbar', 'div') + .get('button[aria-label="kebab dropdown toggle"]') + .click(); + cy.ouiaType('PF5/DropdownItem', 'li').first().find('button').click(); cy.get('button').contains('Select all').click(); - cy.ouiaId('Save', 'button').click(); + cy.ouiaId('ColumnManagementModal-save-button', 'button').click(); cy.get('th[data-label="Operating system"]').should('exist'); cy.get('th[data-label="Systems meeting compliance"]').should('exist'); @@ -279,12 +499,14 @@ describe('Reports table tests', () => { }); it('expect to render emptystate', () => { - cy.intercept('**/graphql', { + cy.intercept('api/compliance/v2/reports*', { statusCode: 200, - body: { - data: fixtures, - }, - }); - cy.get('table').should('have.length', 1); + body: { data: [], meta: { total: 0 } }, + }).as('getReports'); + cy.intercept('api/compliance/v2/policies*', { + statusCode: 200, + body: { data: [], meta: { total: 0 } }, + }).as('getPolicies'); + cy.contains('No policies are reporting'); }); }); diff --git a/src/SmartComponents/Reports/Reports.js b/src/SmartComponents/Reports/Reports.js index 28046b370..2d65e27ba 100644 --- a/src/SmartComponents/Reports/Reports.js +++ b/src/SmartComponents/Reports/Reports.js @@ -1,6 +1,4 @@ -import React, { useCallback, useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; -import { useQuery } from '@apollo/client'; +import React, { useCallback } from 'react'; import PageHeader, { PageHeaderTitle, } from '@redhat-cloud-services/frontend-components/PageHeader'; @@ -11,75 +9,20 @@ import { StateViewWithError, ReportsEmptyState, } from 'PresentationalComponents'; -import GatedComponents from '@/PresentationalComponents/GatedComponents'; import TableStateProvider from '@/Frameworks/AsyncTableTools/components/TableStateProvider'; import useComplianceQuery from 'Utilities/hooks/api/useComplianceQuery'; import useReportsOS from 'Utilities/hooks/api/useReportsOs'; import useReportsCount from 'Utilities/hooks/useReportsCount'; import dataSerialiser from 'Utilities/dataSerialiser'; import { reportDataMap as dataMap } from '../../constants'; -import { uniq } from 'Utilities/helpers'; -import { QUERY } from './constants'; import useExporter from '@/Frameworks/AsyncTableTools/hooks/useExporter'; -const profilesFromEdges = (data) => - (data?.profiles?.edges || []).map((profile) => profile.node); - const ReportsHeader = () => ( ); -//deprecated component -const ReportsWithGrahpQL = () => { - let profiles = []; - const location = useLocation(); - const filter = `has_policy_test_results = true AND external = false`; - - let { data, error, loading, refetch } = useQuery(QUERY, { - variables: { filter }, - }); - - useEffect(() => { - refetch(); - }, [location, refetch]); - - if (data) { - profiles = profilesFromEdges(data); - error = undefined; - loading = undefined; - } - const operatingSystems = - data && - uniq( - profiles?.map(({ osMajorVersion }) => osMajorVersion).filter((i) => !!i) - ); - - return ( - <> - -
- - - - - - {profiles && profiles.length > 0 ? ( - - ) : ( - - )} - - -
- - ); -}; - const ReportsWithRest = () => { // Required for correctly showing empty state const totalReports = useReportsCount(); @@ -140,11 +83,4 @@ const ReportsWithTableStateProvider = () => ( ); -const ReportsWrapper = () => ( - -); - -export default ReportsWrapper; +export default ReportsWithTableStateProvider; diff --git a/src/SmartComponents/Reports/Reports.test.js b/src/SmartComponents/Reports/Reports.test.js index a5a02a259..d18ed706f 100644 --- a/src/SmartComponents/Reports/Reports.test.js +++ b/src/SmartComponents/Reports/Reports.test.js @@ -2,89 +2,18 @@ import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import TestWrapper from '@redhat-cloud-services/frontend-components-utilities/TestingUtils/JestUtils/TestWrapper.js'; -import { useQuery } from '@apollo/client'; import useComplianceQuery from 'Utilities/hooks/api/useComplianceQuery'; import useReportsCount from 'Utilities/hooks/useReportsCount.js'; import useReportsOS from 'Utilities/hooks/api/useReportsOs.js'; -import { profiles } from '@/__fixtures__/profiles.js'; -import useAPIV2FeatureFlag from '@/Utilities/hooks/useAPIV2FeatureFlag.js'; import Reports from './Reports.js'; -jest.mock('@apollo/client'); -jest.mock('@/Utilities/hooks/useAPIV2FeatureFlag'); jest.mock('@/Utilities/hooks/api/useReports'); jest.mock('Utilities/hooks/api/useComplianceQuery', () => jest.fn()); jest.mock('Utilities/hooks/api/useReportsOs', () => jest.fn()); jest.mock('Utilities/hooks/useReportsCount', () => jest.fn()); -describe('Reports - GraphQL', () => { - beforeEach(() => { - useAPIV2FeatureFlag.mockImplementation(() => false); - }); - - const queryResultDefaults = { - error: undefined, - loading: undefined, - data: undefined, - refetch: jest.fn(), - }; - - it('expect to render properly and show the profile(s)', () => { - useQuery.mockImplementation(() => ({ - ...queryResultDefaults, - data: profiles, - })); - render( - - - - ); - - expect(screen.getAllByText('PCI-DSS').length).toEqual(10); - }); - - it('expect to render emptystate', () => { - useQuery.mockImplementation(() => ({ - ...queryResultDefaults, - data: { - profiles: { edges: [] }, - }, - })); - render( - - - - ); - - expect( - screen.getByRole('button', { name: 'Create new policy' }) - ).toBeInTheDocument(); - expect( - screen.getByRole('link', { name: 'Learn about OpenSCAP and Compliance' }) - ).toBeInTheDocument(); - }); - - it('expect to render loading', () => { - useQuery.mockImplementation(() => ({ - ...queryResultDefaults, - loading: true, - })); - render( - - - - ); - - expect(screen.getByLabelText('Loading')).toBeInTheDocument(); - }); -}); - describe('Reports - REST', () => { - beforeEach(() => { - useAPIV2FeatureFlag.mockImplementation(() => true); - }); - it('should use REST api', async () => { useReportsCount.mockImplementation(() => 0); useReportsOS.mockImplementation(() => ({ diff --git a/src/SmartComponents/Reports/constants.js b/src/SmartComponents/Reports/constants.js deleted file mode 100644 index 1d8bf0f05..000000000 --- a/src/SmartComponents/Reports/constants.js +++ /dev/null @@ -1,35 +0,0 @@ -import { gql } from '@apollo/client'; - -export const QUERY = gql` - query R_Profiles($filter: String!) { - profiles(search: $filter, limit: 1000) { - edges { - node { - id - name - refId - description - policyType - totalHostCount - testResultHostCount - compliantHostCount - unsupportedHostCount - osMajorVersion - complianceThreshold - businessObjective { - id - title - } - policy { - id - name - } - benchmark { - id - version - } - } - } - } - } -`; diff --git a/src/__factories__/reports.js b/src/__factories__/reports.js new file mode 100644 index 000000000..06e8ce8ac --- /dev/null +++ b/src/__factories__/reports.js @@ -0,0 +1,50 @@ +import { faker } from '@faker-js/faker'; + +export const buildReports = (length) => + [...Array(length)].map(() => { + const title = faker.lorem.words({ min: 2, max: 5 }); + const assigned_system_count = faker.number.int({ min: 0, max: 100 }); + const compliant_system_count = faker.number.int({ + min: 0, + max: assigned_system_count, + }); + const percent_compliant = + assigned_system_count > 0 + ? Math.round((compliant_system_count / assigned_system_count) * 100) + : 0; + const reported_system_count = faker.number.int({ + min: compliant_system_count, + max: assigned_system_count, + }); + const max_number_unsupported_systems = + reported_system_count - compliant_system_count; + const unsupported_system_count = faker.number.int({ + min: 0, + max: max_number_unsupported_systems, + }); + // TODO: we will probably need to fix it after https://issues.redhat.com/browse/RHINENG-14550 + return { + id: faker.string.uuid(), + title, + description: faker.lorem.paragraph(), + business_objective: faker.helpers.arrayElement([ + null, + faker.lorem.words(5), + ]), + compliance_threshold: faker.number.float({ + min: 0, + max: 100, + precision: 0.1, + }), + type: 'report', + os_major_version: faker.number.int({ min: 6, max: 9 }), + profile_title: title, + ref_id: faker.lorem.slug({ min: 1, max: 4 }), + all_systems_exposed: true, + percent_compliant: percent_compliant, + assigned_system_count: assigned_system_count, + compliant_system_count: compliant_system_count, + unsupported_system_count: unsupported_system_count, + reported_system_count: reported_system_count, + }; + });