diff --git a/.changeset/twenty-humans-visit.md b/.changeset/twenty-humans-visit.md index 6235164602..e543d30145 100644 --- a/.changeset/twenty-humans-visit.md +++ b/.changeset/twenty-humans-visit.md @@ -2,4 +2,5 @@ '@backstage/plugin-techdocs-react': patch --- -Add `toLowerEntityRefMaybe()` function for handling `techdocs.legacyUseCaseSensitiveTripletPaths` flag. +Add `toLowerEntityRefMaybe()` helper function for handling `techdocs.legacyUseCaseSensitiveTripletPaths` flag. +Pass modified `entityRef` to `TechDocsReaderPageContext` to handle the `techdocs.legacyUseCaseSensitiveTripletPaths` flag. diff --git a/plugins/techdocs-react/src/context.test.tsx b/plugins/techdocs-react/src/context.test.tsx index 14669dc336..efc695bff0 100644 --- a/plugins/techdocs-react/src/context.test.tsx +++ b/plugins/techdocs-react/src/context.test.tsx @@ -21,6 +21,7 @@ import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; import { TestApiProvider } from '@backstage/test-utils'; import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; +import { configApiRef } from '@backstage/core-plugin-api'; import { techdocsApiRef } from './api'; import { useTechDocsReaderPage, TechDocsReaderPageProvider } from './context'; @@ -55,72 +56,137 @@ const techdocsApiMock = { getTechDocsMetadata: jest.fn().mockResolvedValue(mockTechDocsMetadata), }; -const wrapper = ({ - entityRef = { - kind: mockEntityMetadata.kind, - name: mockEntityMetadata.metadata.name, - namespace: mockEntityMetadata.metadata.namespace!!, - }, - children, -}: { - entityRef?: CompoundEntityRef; - children: React.ReactNode; -}) => ( - - - - {children} - - - -); - describe('useTechDocsReaderPage', () => { - it('should set title', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsReaderPage(), - { wrapper }, + describe('when legacyUseCaseSensitiveTripletPaths is false', () => { + const configApiMock = { + getOptionalBoolean: jest.fn().mockReturnValue(undefined), + }; + + const wrapper = ({ + entityRef = { + kind: mockEntityMetadata.kind, + name: mockEntityMetadata.metadata.name, + namespace: mockEntityMetadata.metadata.namespace!!, + }, + children, + }: { + entityRef?: CompoundEntityRef; + children: React.ReactNode; + }) => ( + + + + {children} + + + ); - expect(result.current.title).toBe(''); + it('should set title', async () => { + const { result, waitForNextUpdate } = renderHook( + () => useTechDocsReaderPage(), + { wrapper }, + ); - act(() => result.current.setTitle('test site title')); + expect(result.current.title).toBe(''); - await waitForNextUpdate(); + act(() => result.current.setTitle('test site title')); - expect(result.current.title).toBe('test site title'); + await waitForNextUpdate(); + + expect(result.current.title).toBe('test site title'); + }); + + it('should set subtitle', async () => { + const { result, waitForNextUpdate } = renderHook( + () => useTechDocsReaderPage(), + { wrapper }, + ); + + expect(result.current.subtitle).toBe(''); + + act(() => result.current.setSubtitle('test site subtitle')); + + await waitForNextUpdate(); + + expect(result.current.subtitle).toBe('test site subtitle'); + }); + + it('should set shadow root', async () => { + const { result, waitForNextUpdate } = renderHook( + () => useTechDocsReaderPage(), + { wrapper }, + ); + + // mock shadowroot + const shadowRoot = mockShadowRoot(); + + act(() => result.current.setShadowRoot(shadowRoot)); + + await waitForNextUpdate(); + + expect(result.current.shadowRoot?.innerHTML).toBe( + '

Shadow DOM Mock

', + ); + }); + + it('should set entityRef as lowercase', async () => { + const lowercaseEntityRef = { + kind: mockEntityMetadata.kind.toLocaleLowerCase(), + name: mockEntityMetadata.metadata.name.toLocaleLowerCase(), + namespace: mockEntityMetadata.metadata.namespace?.toLocaleLowerCase(), + }; + const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); + + expect(result.current.entityRef).toStrictEqual(lowercaseEntityRef); + }); }); - it('should set subtitle', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsReaderPage(), - { wrapper }, + describe('when legacyUseCaseSensitiveTripletPaths is true', () => { + const configApiMock = { + getOptionalBoolean: jest.fn().mockReturnValue(true), + }; + + const wrapper = ({ + entityRef = { + kind: mockEntityMetadata.kind, + name: mockEntityMetadata.metadata.name, + namespace: mockEntityMetadata.metadata.namespace!!, + }, + children, + }: { + entityRef?: CompoundEntityRef; + children: React.ReactNode; + }) => ( + + + + {children} + + + ); - expect(result.current.subtitle).toBe(''); + it('entityRef is not modified', async () => { + const caseSensitiveEntityRef = { + kind: mockEntityMetadata.kind, + name: mockEntityMetadata.metadata.name, + namespace: mockEntityMetadata.metadata.namespace!!, + }; - act(() => result.current.setSubtitle('test site subtitle')); + const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); - await waitForNextUpdate(); - - expect(result.current.subtitle).toBe('test site subtitle'); - }); - - it('should set shadow root', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsReaderPage(), - { wrapper }, - ); - - // mock shadowroot - const shadowRoot = mockShadowRoot(); - - act(() => result.current.setShadowRoot(shadowRoot)); - - await waitForNextUpdate(); - - expect(result.current.shadowRoot?.innerHTML).toBe( - '

Shadow DOM Mock

', - ); + expect(result.current.entityRef).toStrictEqual(caseSensitiveEntityRef); + }); }); }); diff --git a/plugins/techdocs-react/src/context.tsx b/plugins/techdocs-react/src/context.tsx index 4f2fa26164..66faf858fa 100644 --- a/plugins/techdocs-react/src/context.tsx +++ b/plugins/techdocs-react/src/context.tsx @@ -33,11 +33,13 @@ import { createVersionedValueMap, } from '@backstage/version-bridge'; -import { useApi } from '@backstage/core-plugin-api'; +import { configApiRef, useApi } from '@backstage/core-plugin-api'; import { techdocsApiRef } from './api'; import { TechDocsEntityMetadata, TechDocsMetadata } from './types'; +import { toLowercaseEntityRefMaybe } from './helpers'; + const areEntityRefsEqual = ( prevEntityRef: CompoundEntityRef, nextEntityRef: CompoundEntityRef, @@ -107,6 +109,7 @@ export type TechDocsReaderPageProviderProps = { export const TechDocsReaderPageProvider = memo( ({ entityRef, children }: TechDocsReaderPageProviderProps) => { const techdocsApi = useApi(techdocsApiRef); + const config = useApi(configApiRef); const metadata = useAsync(async () => { return techdocsApi.getTechDocsMetadata(entityRef); @@ -126,7 +129,7 @@ export const TechDocsReaderPageProvider = memo( const value = { metadata, - entityRef, + entityRef: toLowercaseEntityRefMaybe(entityRef, config), entityMetadata, shadowRoot, setShadowRoot,