From 9b770f95294fc3643fd7bf0521b2e3b356fe49d0 Mon Sep 17 00:00:00 2001 From: Georgii Karataev Date: Tue, 21 Feb 2023 11:44:10 +0100 Subject: [PATCH] Implement tests for the page and header components Implements https://issues.redhat.com/browse/ESSNTL-3726. --- .../620f9ae75A8F6b83d78F3B55Af1c4b2C.json | 38 +++++++++++++ cypress/support/interceptors.js | 28 +++++++++ .../InventoryGroupDetail/GroupDetailHeader.js | 12 ++-- .../InventoryGroupDetail.cy.js | 57 +++++++++++++++++++ .../InventoryGroupDetail.js | 14 +++-- .../__tests__/GroupDetailHeader.test.js | 44 ++++++++++++++ .../__tests__/InventoryGroupDetail.test.js | 44 ++++++++++++++ src/components/InventoryGroupDetail/index.js | 10 +++- 8 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 cypress/fixtures/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C.json create mode 100644 src/components/InventoryGroupDetail/InventoryGroupDetail.cy.js create mode 100644 src/components/InventoryGroupDetail/__tests__/GroupDetailHeader.test.js create mode 100644 src/components/InventoryGroupDetail/__tests__/InventoryGroupDetail.test.js diff --git a/cypress/fixtures/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C.json b/cypress/fixtures/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C.json new file mode 100644 index 000000000..e52cc1577 --- /dev/null +++ b/cypress/fixtures/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C.json @@ -0,0 +1,38 @@ +{ + "count": 1, + "page": 1, + "per_page": 50, + "results": [ + { + "name": "ea velit incididunt", + "updated_at": "1998-04-17T22:00:00.0Z", + "id": "620f9ae75A8F6b83d78F3B55Af1c4b2C", + "account": "irure ea exercitation adipisicing velit", + "org_id": "non", + "created_at": "1994-07-28T22:00:00.0Z", + "host_ids": [ + "eEfb7FAa-1f0b-Bde3-a4FF-fDdCd5faA764", + "bb7417faE7f9eCdacEDDd0Fcae9Cf4BB", + "2095BB72Aa6E1d2D1DC48bdecF1085eb", + "E645A3Fb42B77c4eBf9faEfCad8f6F5a", + "7fb4fa758Cbc0A861C2Cb21695aeA9d6", + "f6BE4AafA6bF543693Fa3F1fadFaA4E9", + "D608C33f-5e6D-BBEF-Cab5-0FFE8eB1bAc4", + "Dd4De9b6-7f3a-ED3d-2a84-D60e4Af2Cd9d", + "ae08E8dd-FFdB-cBC1-BA2A-d0aaC61C1B55", + "dcaD88bD4CeaaDC8bceD5d730ffba4cF", + "5a9F9CDAE74F3116a9c848Eeb1C65EA0", + "f53eDCBe3Fb957BE5dBec9322f030F94", + "c6fbBE38-30D7-D7e9-C8C7-72F4a61Bea9c", + "20E5EedA1e3f2aC2dCaADDCa4BFEED5B", + "adEcDf6ac4A999ccecdbCe7E9e01e23C", + "Bf0E2e8C-7e96-f0C8-9fea-1bD5fa9E18ce", + "6349ADdf-8d6B-bF1e-F5AE-13f0B7ca4acE", + "DBD5E149-C967-12b3-Cc6B-6c9220bA32e1", + "4EC19BbD-b556-ED9E-33E7-Eb5Be40AaeDe", + "CE05B39b3FdDad8dDE2b5DebB7CABe7D" + ] + } + ], + "total": 1 +} diff --git a/cypress/support/interceptors.js b/cypress/support/interceptors.js index 64f40d27b..55e7668f2 100644 --- a/cypress/support/interceptors.js +++ b/cypress/support/interceptors.js @@ -1,6 +1,7 @@ /* eslint-disable camelcase */ import { DEFAULT_ROW_COUNT } from '@redhat-cloud-services/frontend-components-utilities'; import fixtures from '../fixtures/groups.json'; +import groupDetailFixtures from '../fixtures/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C.json'; export const groupsInterceptors = { 'successful with some items': () => @@ -31,3 +32,30 @@ export const groupsInterceptors = { }).as('getGroups'); } }; + +export const groupDetailInterceptors = { + successful: () => + cy + .intercept('GET', '/api/inventory/v1/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C', groupDetailFixtures) + .as('getGroupDetail'), + empty: () => + cy + .intercept('GET', '/api/inventory/v1/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C', { statusCode: 404 }) + .as('getGroupDetail'), + 'failed with server error': () => { + Cypress.on('uncaught:exception', () => { + return false; + }); + cy.intercept('GET', '/api/inventory/v1/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C', { statusCode: 500 }).as( + 'getGroupDetail' + ); + }, + 'long responding': () => { + cy.intercept('GET', '/api/inventory/v1/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C', (req) => { + req.reply({ + body: groupDetailFixtures, + delay: 42000000 // milliseconds + }); + }).as('getGroupDetail'); + } +}; diff --git a/src/components/InventoryGroupDetail/GroupDetailHeader.js b/src/components/InventoryGroupDetail/GroupDetailHeader.js index 81b8326cc..9ef4e4830 100644 --- a/src/components/InventoryGroupDetail/GroupDetailHeader.js +++ b/src/components/InventoryGroupDetail/GroupDetailHeader.js @@ -5,18 +5,18 @@ import { } from '@redhat-cloud-services/frontend-components'; import React from 'react'; import { useSelector } from 'react-redux'; -import { Link, useParams } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import { routes } from '../../Routes'; +import PropTypes from 'prop-types'; -const GroupDetailHeader = () => { +const GroupDetailHeader = ({ groupId }) => { const { uninitialized, loading, data } = useSelector((state) => state.groupDetail); - const { groupId } = useParams(); const nameOrId = uninitialized || loading ? ( ) : ( // in case of error, render just id from URL - data?.name || groupId + data?.results?.[0]?.name || groupId ); return ( @@ -32,4 +32,8 @@ const GroupDetailHeader = () => { ); }; +GroupDetailHeader.propTypes = { + groupId: PropTypes.string.isRequired +}; + export default GroupDetailHeader; diff --git a/src/components/InventoryGroupDetail/InventoryGroupDetail.cy.js b/src/components/InventoryGroupDetail/InventoryGroupDetail.cy.js new file mode 100644 index 000000000..e56e53713 --- /dev/null +++ b/src/components/InventoryGroupDetail/InventoryGroupDetail.cy.js @@ -0,0 +1,57 @@ +import { mount } from '@cypress/react'; +import React from 'react'; +import { Provider } from 'react-redux'; +import { MemoryRouter } from 'react-router-dom'; +import groupDetailFixtures from '../../../cypress/fixtures/groups/620f9ae75A8F6b83d78F3B55Af1c4b2C.json'; +import { groupDetailInterceptors as interceptors } from '../../../cypress/support/interceptors'; +import { getStore } from '../../store'; +import InventoryGroupDetail from './InventoryGroupDetail'; + +const TEST_GROUP_ID = '620f9ae75A8F6b83d78F3B55Af1c4b2C'; + +const mountPage = () => + mount( + + + + + + ); + +before(() => { + cy.window().then( + (window) => + (window.insights = { + chrome: { + isProd: false, + auth: { + getUser: () => { + return Promise.resolve({}); + } + } + } + }) + ); +}); + +describe('group detail page', () => { + it('name from server is rendered in header and breadcrumb', () => { + interceptors.successful(); + mountPage(); + + cy.wait('@getGroupDetail'); + cy.get('h1').contains(groupDetailFixtures.results[0].name); + cy.get('[data-ouia-component-type="PF4/Breadcrumb"] li') + .last() + .should('have.text', groupDetailFixtures.results[0].name); + }); + + it('skeletons rendered while fetching data', () => { + interceptors['long responding'](); + mountPage(); + + cy.get('[data-ouia-component-type="PF4/Breadcrumb"] li').last().find('.pf-c-skeleton'); + cy.get('h1').find('.pf-c-skeleton'); + cy.get('.pf-c-empty-state').find('.pf-c-spinner'); + }); +}); diff --git a/src/components/InventoryGroupDetail/InventoryGroupDetail.js b/src/components/InventoryGroupDetail/InventoryGroupDetail.js index fc18f6e43..f9eb9dd69 100644 --- a/src/components/InventoryGroupDetail/InventoryGroupDetail.js +++ b/src/components/InventoryGroupDetail/InventoryGroupDetail.js @@ -1,5 +1,4 @@ import React, { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; import useChrome from '@redhat-cloud-services/frontend-components/useChrome'; import { useDispatch, useSelector } from 'react-redux'; import { fetchGroupDetail } from '../../store/inventory-actions'; @@ -8,21 +7,20 @@ import { useState } from 'react'; import GroupDetailHeader from './GroupDetailHeader'; import GroupDetailSystems from './GroupDetailSystems'; import GroupDetailInfo from './GroupDetailInfo'; +import PropTypes from 'prop-types'; -const InventoryGroupDetail = () => { +const InventoryGroupDetail = ({ groupId }) => { const dispatch = useDispatch(); const { data } = useSelector((state) => state.groupDetail); const chrome = useChrome(); - const { groupId } = useParams(); - useEffect(() => { dispatch(fetchGroupDetail(groupId)); }, []); useEffect(() => { // if available, change ID to the group's name in the window title - chrome.updateDocumentTitle( + chrome?.updateDocumentTitle?.( `${data?.name || groupId} - Inventory Groups | Red Hat Insights` ); }, [data]); @@ -31,7 +29,7 @@ const InventoryGroupDetail = () => { return ( - + { ); }; +InventoryGroupDetail.propTypes = { + groupId: PropTypes.string.isRequired +}; + export default InventoryGroupDetail; diff --git a/src/components/InventoryGroupDetail/__tests__/GroupDetailHeader.test.js b/src/components/InventoryGroupDetail/__tests__/GroupDetailHeader.test.js new file mode 100644 index 000000000..10a77cc0e --- /dev/null +++ b/src/components/InventoryGroupDetail/__tests__/GroupDetailHeader.test.js @@ -0,0 +1,44 @@ +import '@testing-library/jest-dom'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import GroupDetailHeader from '../GroupDetailHeader'; + +jest.mock('react-redux', () => { + return { + ...jest.requireActual('react-redux'), + useSelector: () => ({ + uninitialized: false, + loading: false, + data: { + results: [ + { + name: 'group-name-1' + } + ] + } + }) + }; +}); + +describe('group detail header', () => { + let getByRole; + + beforeEach(() => { + const rendered = render( + + + + ); + getByRole = rendered.getByRole; + }); + + it('renders title and breadcrumbs', () => { + expect(getByRole('heading')).toBeInTheDocument(); + }); + + it('has breadcrumbs', () => { + expect(getByRole('navigation')).toHaveClass('pf-c-breadcrumb'); + expect(getByRole('navigation')).toHaveTextContent('group-name-1'); + }); +}); diff --git a/src/components/InventoryGroupDetail/__tests__/InventoryGroupDetail.test.js b/src/components/InventoryGroupDetail/__tests__/InventoryGroupDetail.test.js new file mode 100644 index 000000000..44f42fa57 --- /dev/null +++ b/src/components/InventoryGroupDetail/__tests__/InventoryGroupDetail.test.js @@ -0,0 +1,44 @@ +import '@testing-library/jest-dom'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import InventoryGroupDetail from '../InventoryGroupDetail'; + +jest.mock('react-redux', () => { + return { + ...jest.requireActual('react-redux'), + useSelector: () => ({ + uninitialized: false, + loading: false, + data: { + results: [ + { + name: 'group-name-1' + } + ] + } + }), + useDispatch: () => () => {} + }; +}); + +describe('group detail page component', () => { + let getByRole; + let container; + + beforeEach(() => { + const rendered = render( + + + + ); + getByRole = rendered.getByRole; + container = rendered.container; + }); + + it('renders two tabs', () => { + expect(getByRole('tablist')).toBeInTheDocument(); + expect(container.querySelectorAll('.pf-c-tabs__item')[0]).toHaveTextContent('Systems'); + expect(container.querySelectorAll('.pf-c-tabs__item')[1]).toHaveTextContent('Group info'); + }); +}); diff --git a/src/components/InventoryGroupDetail/index.js b/src/components/InventoryGroupDetail/index.js index a3695ffa0..91b334ef3 100644 --- a/src/components/InventoryGroupDetail/index.js +++ b/src/components/InventoryGroupDetail/index.js @@ -1,3 +1,11 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; import InventoryGroupDetail from './InventoryGroupDetail'; -export default InventoryGroupDetail; +const InventoryGroupDetailWrapper = () => { + const { groupId } = useParams(); + + return ; +}; + +export default InventoryGroupDetailWrapper;