From 4cf1f437e56debe9507774bbad15855406f9bb7d Mon Sep 17 00:00:00 2001 From: Frank Kong Date: Fri, 23 Jun 2023 11:29:20 -0400 Subject: [PATCH] test(lighthouse): update lighthouse test files Signed-off-by: Frank Kong --- .changeset/lemon-cycles-enjoy.md | 6 +- .github/vale/Vocab/Backstage/accept.txt | 1 + .../AuditList/AuditListForEntity.test.tsx | 75 ++++++++++++++++--- .../AuditList/AuditListForEntity.tsx | 11 +-- .../Cards/LastLighthouseAuditCard.test.tsx | 36 ++++++++- .../src/hooks/useWebsiteForEntity.test.tsx | 17 +++++ 6 files changed, 120 insertions(+), 26 deletions(-) diff --git a/.changeset/lemon-cycles-enjoy.md b/.changeset/lemon-cycles-enjoy.md index ff77d0d3d8..1df7905030 100644 --- a/.changeset/lemon-cycles-enjoy.md +++ b/.changeset/lemon-cycles-enjoy.md @@ -2,6 +2,6 @@ '@backstage/plugin-lighthouse': patch --- -Added more verbose components (used to render `null`) when no audits for a website corresponding to the provided url was found -Added `Create New Audit` button for the `AuditListForEntity` component used by `EntityLighthouseContent` and `EmbeddedRouter` -Removed error alert from `errorApi` if error was due to no audits being found for a website (empty database query result) +Added more verbose components (used to render `null`) when no audits for a website corresponding to the provided url were found. +Added `Create New Audit` button for the `AuditListForEntity` component used by `EntityLighthouseContent` and `EmbeddedRouter`. +Removed error alert from `errorApi` if error was due to no audits being found for a website (empty database query result). diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index 901e890318..627e0aa0f3 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -409,6 +409,7 @@ unregistration untracked upsert upvote +url URIs URLs utils diff --git a/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx b/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx index d1ed72c3fb..42b02692a9 100644 --- a/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx +++ b/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx @@ -26,16 +26,31 @@ import { lighthouseApiRef } from '../../api'; import { useWebsiteForEntity } from '../../hooks/useWebsiteForEntity'; import * as data from '../../__fixtures__/website-list-response.json'; import { AuditListForEntity } from './AuditListForEntity'; +import { rootRouteRef } from '../../plugin'; +import { fireEvent, screen } from '@testing-library/react'; jest.mock('../../hooks/useWebsiteForEntity', () => ({ useWebsiteForEntity: jest.fn(), })); +jest.mock('react-router-dom', () => { + const actual = jest.requireActual('react-router-dom'); + const mockNavigation = jest.fn(); + return { + ...actual, + useNavigate: jest.fn(() => mockNavigation), + }; +}); + const useWebsiteForEntityMock = useWebsiteForEntity as jest.Mock; const websiteListResponse = data as WebsiteListResponse; const entityWebsite = websiteListResponse.items[0]; +const testAppOptions = { + mountedRoutes: { '/': rootRouteRef }, +}; + describe('', () => { afterEach(() => { jest.resetAllMocks(); @@ -73,39 +88,77 @@ describe('', () => { loading: false, error: null, }); - const { findByText } = await renderInTestApp(subject()); - expect(await findByText(entityWebsite.url)).toBeInTheDocument(); + const rendered = await renderInTestApp(subject(), testAppOptions); + const create_audit_button = await rendered.findByText('Create New Audit'); + const support_button = await rendered.findByText('Support'); + expect(await rendered.findByText(entityWebsite.url)).toBeInTheDocument(); + expect(await rendered.findByText('Latest Audit')).toBeInTheDocument(); + expect(create_audit_button).toBeInTheDocument(); + expect(support_button).toBeInTheDocument(); }); - it('renders a Progress element where the data is loading', async () => { + it('renders a Progress element when the data is loading', async () => { useWebsiteForEntityMock.mockReturnValue({ value: null, loading: true, error: null, }); - const { findByTestId } = await renderInTestApp(subject()); + const { findByTestId } = await renderInTestApp(subject(), testAppOptions); expect(await findByTestId('progress')).toBeInTheDocument(); }); - it('renders nothing where there is an error loading data', async () => { + it('renders a WarningPanel when there is an error loading data', async () => { useWebsiteForEntityMock.mockReturnValue({ value: null, loading: false, - error: 'error', + error: { name: 'error', message: 'error loading data' }, }); - const { queryByTestId } = await renderInTestApp(subject()); - expect(queryByTestId('AuditListTable')).toBeNull(); + await renderInTestApp(subject(), testAppOptions); + const expandIcon = screen.getByText('Error: Could not load audit list.'); + fireEvent.click(expandIcon); + expect( + screen.getByText('Error: Could not load audit list.'), + ).toBeInTheDocument(); + expect(screen.getByText('error loading data')).toBeInTheDocument(); }); - it('renders nothing where there is not data', async () => { + it('renders an empty table when there is no data', async () => { useWebsiteForEntityMock.mockReturnValue({ value: null, loading: false, error: null, }); - const { queryByTestId } = await renderInTestApp(subject()); - expect(queryByTestId('AuditListTable')).toBeNull(); + const rendered = await renderInTestApp(subject(), testAppOptions); + const create_audit_button = await rendered.findByText('Create New Audit'); + const support_button = await rendered.findByText('Support'); + expect( + await rendered.findByText('No records to display'), + ).toBeInTheDocument(); + expect(await rendered.findByText('Latest Audit')).toBeInTheDocument(); + expect(create_audit_button).toBeInTheDocument(); + expect(support_button).toBeInTheDocument(); + }); + + it('renders an empty table when there is no data and error loading data due to empty database query result', async () => { + useWebsiteForEntityMock.mockReturnValue({ + value: null, + loading: false, + error: { + name: 'error', + message: 'no audited website found for url unit-test-url', + }, + }); + + const rendered = await renderInTestApp(subject(), testAppOptions); + const create_audit_button = await rendered.findByText('Create New Audit'); + const support_button = await rendered.findByText('Support'); + expect( + await rendered.findByText('No records to display'), + ).toBeInTheDocument(); + expect(await rendered.findByText('Latest Audit')).toBeInTheDocument(); + expect(create_audit_button).toBeInTheDocument(); + expect(support_button).toBeInTheDocument(); }); }); diff --git a/plugins/lighthouse/src/components/AuditList/AuditListForEntity.tsx b/plugins/lighthouse/src/components/AuditList/AuditListForEntity.tsx index 950cc5e7b3..4c8de4d786 100644 --- a/plugins/lighthouse/src/components/AuditList/AuditListForEntity.tsx +++ b/plugins/lighthouse/src/components/AuditList/AuditListForEntity.tsx @@ -57,19 +57,14 @@ export const AuditListForEntity = () => { - + ); if (loading) { content = ; - } else if ( - error && - !error.message.includes('no audited website found for url') - ) { + } + if (error && !error.message.includes('no audited website found for url')) { // We only want to display this warning panel when its caused by an error other than no audits for the website content = ( diff --git a/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx b/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx index 09b21fd028..fd54dd99c8 100644 --- a/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx +++ b/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx @@ -26,6 +26,7 @@ import { import { useWebsiteForEntity } from '../../hooks/useWebsiteForEntity'; import * as data from '../../__fixtures__/website-list-response.json'; import { LastLighthouseAuditCard } from './LastLighthouseAuditCard'; +import { fireEvent, screen } from '@testing-library/react'; jest.mock('../../hooks/useWebsiteForEntity', () => ({ useWebsiteForEntity: jest.fn(), @@ -147,17 +148,22 @@ describe('', () => { (useWebsiteForEntity as jest.Mock).mockReturnValue({ value: null, loading: false, - error: 'error', + error: { name: 'error', message: 'error loading data' }, }); }); - it('renders nothing', async () => { - const { queryByTestId } = await renderInTestApp( + it('renders a WarningPanel', async () => { + await renderInTestApp( , ); - expect(queryByTestId('AuditListTable')).toBeNull(); + const expandIcon = screen.getByText('Error: Could not load audit list.'); + fireEvent.click(expandIcon); + expect( + screen.getByText('Error: Could not load audit list.'), + ).toBeInTheDocument(); + expect(screen.getByText('error loading data')).toBeInTheDocument(); }); }); @@ -179,4 +185,26 @@ describe('', () => { expect(queryByTestId('AuditListTable')).toBeNull(); }); }); + + describe('where error was due to an empty database query result', () => { + beforeEach(() => { + (useWebsiteForEntity as jest.Mock).mockReturnValue({ + value: null, + loading: false, + error: { + name: 'error', + message: 'no audited website found for url unit-test-url', + }, + }); + }); + + it('renders EmptyState card', async () => { + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('No Audits Found')).toBeInTheDocument(); + }); + }); }); diff --git a/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx b/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx index 7ab717c57d..199ede3049 100644 --- a/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx +++ b/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx @@ -98,4 +98,21 @@ describe('useWebsiteForEntity', () => { expect(mockErrorApi.post).toHaveBeenCalledWith(error); }); }); + + describe('where there is an error regarding "no audited websites for url"', () => { + const error = new Error('no audited website found for url unit-test-url'); + + beforeEach(() => { + (mockLighthouseApi.getWebsiteByUrl as jest.Mock).mockRejectedValueOnce( + error, + ); + }); + + it('does not post the error to the error api and returns the error to the caller', async () => { + const { result, waitForNextUpdate } = subject(); + await waitForNextUpdate(); + expect(result.current?.error).toBe(error); + expect(mockErrorApi.post).not.toHaveBeenCalledWith(error); + }); + }); });