From b6a8c56a8161ea9aba865ef67c76be1090e210e7 Mon Sep 17 00:00:00 2001 From: nikolar Date: Mon, 2 Dec 2024 20:09:30 -0800 Subject: [PATCH] add testing Signed-off-by: nikolar --- .../components/Grids/InfoCardGrid.test.tsx | 191 ++++++++++++++++++ .../home/components/Grids/InfoCardGrid.tsx | 39 ++-- .../components/TechDocsCustomHome.test.tsx | 129 ++++++++++++ .../home/components/TechDocsCustomHome.tsx | 13 +- 4 files changed, 349 insertions(+), 23 deletions(-) create mode 100644 plugins/techdocs/src/home/components/Grids/InfoCardGrid.test.tsx diff --git a/plugins/techdocs/src/home/components/Grids/InfoCardGrid.test.tsx b/plugins/techdocs/src/home/components/Grids/InfoCardGrid.test.tsx new file mode 100644 index 0000000000..dcb773120e --- /dev/null +++ b/plugins/techdocs/src/home/components/Grids/InfoCardGrid.test.tsx @@ -0,0 +1,191 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { rootDocsRouteRef } from '../../../routes'; +import { InfoCardGrid } from './InfoCardGrid'; + +describe('Entity Info Card Grid', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should render multiple entities', async () => { + await renderInTestApp( + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(await screen.findByText('TestTitle')).toBeInTheDocument(); + expect(await screen.findByText('TestTitle2')).toBeInTheDocument(); + }); + + it('should handle missing data gracefully', async () => { + await renderInTestApp( + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(await screen.findByText('testName')).toBeInTheDocument(); + }); + + it('should render links correctly', async () => { + await renderInTestApp( + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(await screen.findByText('TestTitle')).toBeInTheDocument(); + expect(await screen.findByText('TestTitle2')).toBeInTheDocument(); + const [button1, button2] = await screen.findAllByTestId('read-docs-link'); + expect(button1.getAttribute('href')).toContain( + '/docs/default/testkind/testname', + ); + expect(button2.getAttribute('href')).toContain( + '/docs/default/testkind2/testname2', + ); + }); + + it('should render entity title if available', async () => { + await renderInTestApp( + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(await screen.findByText('TestTitle')).toBeInTheDocument(); + }); + + it('should render entity name if title is not available', async () => { + await renderInTestApp( + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(await screen.findByText('testName')).toBeInTheDocument(); + }); +}); diff --git a/plugins/techdocs/src/home/components/Grids/InfoCardGrid.tsx b/plugins/techdocs/src/home/components/Grids/InfoCardGrid.tsx index 46293f9228..7a96c2af4c 100644 --- a/plugins/techdocs/src/home/components/Grids/InfoCardGrid.tsx +++ b/plugins/techdocs/src/home/components/Grids/InfoCardGrid.tsx @@ -38,11 +38,11 @@ const useStyles = makeStyles( ); /** - * Props for {@link InfoCardGird} + * Props for {@link InfoCardGrid} * * @public */ -export type InfoCardGirdProps = { +export type InfoCardGridProps = { entities: Entity[] | undefined; linkContent?: string | JSX.Element; linkDest?: (entity: Entity) => string; @@ -53,37 +53,40 @@ export type InfoCardGirdProps = { * * @public */ -export const InfoCardGird = (props: InfoCardGirdProps) => { +export const InfoCardGrid = (props: InfoCardGridProps) => { const { entities, linkContent, linkDest } = props; const classes = useStyles(); const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef); const config = useApi(configApiRef); + const linkDestination = (entity: Entity) => + typeof linkDest === 'function' + ? linkDest(entity) + : getRouteToReaderPageFor({ + namespace: toLowerMaybe( + entity.metadata.namespace ?? 'default', + config, + ), + kind: toLowerMaybe(entity.kind, config), + name: toLowerMaybe(entity.metadata.name, config), + }); + if (!entities) return null; return ( - + {!entities?.length ? null : entities.map(entity => (
{entity?.metadata?.description}
{linkContent || 'Read Docs'} diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx index 409d68a593..66e01ce780 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx @@ -96,4 +96,133 @@ describe('TechDocsCustomHome', () => { await screen.findByText('Second Tab Description'), ).toBeInTheDocument(); }); + it('should render ContentHeader based on showHeader prop', async () => { + const tabsConfig = [ + { + label: 'First Tab', + panels: [ + { + title: 'First Tab', + description: 'First Tab Description', + panelType: 'DocsCardGrid' as PanelType, + panelProps: { showHeader: false }, + filterPredicate: () => true, + }, + ], + }, + ]; + + await renderInTestApp( + + + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect( + screen.queryByText('Discover documentation in your ecosystem.'), + ).not.toBeInTheDocument(); + }); + it('should render SupportButton based on hideSupport prop', async () => { + const tabsConfig = [ + { + label: 'First Tab', + panels: [ + { + title: 'First Tab', + description: 'First Tab Description', + panelType: 'DocsCardGrid' as PanelType, + filterPredicate: () => true, + panelProps: { hideSupport: true }, + }, + ], + }, + ]; + + await renderInTestApp( + + + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect( + screen.queryByText('Discover documentation in your ecosystem.'), + ).not.toBeInTheDocument(); + }); + it('should hide subtitle when hideSubtitle is true', async () => { + const tabsConfig = [ + { + label: 'First Tab', + panels: [ + { + title: 'First Tab', + description: 'First Tab Description', + panelType: 'DocsCardGrid' as PanelType, + filterPredicate: () => true, + }, + ], + }, + ]; + + await renderInTestApp( + + + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(screen.getByText('Custom Title')).toBeInTheDocument(); + expect(screen.queryByText('Custom Subtitle')).not.toBeInTheDocument(); + }); + it('should render title and subtitle', async () => { + const tabsConfig = [ + { + label: 'First Tab', + panels: [ + { + title: 'First Tab', + description: 'First Tab Description', + panelType: 'DocsCardGrid' as PanelType, + filterPredicate: () => true, + }, + ], + }, + ]; + + await renderInTestApp( + + + , + { + mountedRoutes: { + '/docs/:namespace/:kind/:name/*': rootDocsRouteRef, + }, + }, + ); + + expect(screen.getByText('Custom Title')).toBeInTheDocument(); + expect(screen.getByText('Custom Subtitle')).toBeInTheDocument(); + }); }); diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx index 5024eab5c3..781d4b337c 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx @@ -26,7 +26,7 @@ import { } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; import { DocsTable } from './Tables'; -import { DocsCardGrid, InfoCardGird } from './Grids'; +import { DocsCardGrid, InfoCardGrid } from './Grids'; import { TechDocsPageWrapper } from './TechDocsPageWrapper'; import { TechDocsIndexPage } from './TechDocsIndexPage'; @@ -47,7 +47,7 @@ const panels = { DocsTable: DocsTable, DocsCardGrid: DocsCardGrid, TechDocsIndexPage: TechDocsIndexPage, - InfoCardGird: InfoCardGird, + InfoCardGrid: InfoCardGrid, }; /** @@ -59,7 +59,7 @@ export type PanelType = | 'DocsCardGrid' | 'DocsTable' | 'TechDocsIndexPage' - | 'InfoCardGird'; + | 'InfoCardGrid'; /** * Type representing a TechDocsCustomHome panel. @@ -172,7 +172,8 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => { error, } = useAsync(async () => { const response = await catalogApi.getEntities({ - filter: filter || { + filter: { + ...filter, [`metadata.annotations.${TECHDOCS_ANNOTATION}`]: CATALOG_FILTER_EXISTS, }, fields: [ @@ -184,7 +185,9 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => { 'spec.type', ], }); - return response.items; + return response.items.filter((entity: Entity) => { + return !!entity.metadata.annotations?.[TECHDOCS_ANNOTATION]; + }); }); const currentTabConfig = tabsConfig[selectedTab];