tests(techdocs): fix broken tests
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
@@ -69,7 +69,7 @@ export const TechDocsReaderPage = ({
|
||||
if (defaultPath) {
|
||||
return defaultPath;
|
||||
}
|
||||
return params['*'] ?? '';
|
||||
return params['*'];
|
||||
}, [params, defaultPath]);
|
||||
|
||||
const entityName = useMemo(() => {
|
||||
|
||||
@@ -15,7 +15,17 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { TechDocsMetadata } from './types';
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
|
||||
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 { techdocsApiRef } from '../../../api';
|
||||
import { TechDocsMetadata } from '../../../types';
|
||||
|
||||
import {
|
||||
useEntityMetadata,
|
||||
useTechDocsMetadata,
|
||||
@@ -24,14 +34,17 @@ import {
|
||||
TechDocsMetadataProvider,
|
||||
TechDocsReaderPageProvider,
|
||||
} from './context';
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
|
||||
import { Entity, CompoundEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
const mockEntity: Entity = {
|
||||
const mockEntityMetadata: Entity = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: { name: 'test-component', namespace: 'default' },
|
||||
metadata: {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
},
|
||||
spec: {
|
||||
owner: 'test',
|
||||
},
|
||||
};
|
||||
|
||||
const mockTechDocsMetadata: TechDocsMetadata = {
|
||||
@@ -46,39 +59,42 @@ const mockShadowRoot = () => {
|
||||
return shadowRoot;
|
||||
};
|
||||
|
||||
const techdocsApiMock = {
|
||||
getEntityMetadata: jest.fn().mockResolvedValue(mockEntityMetadata),
|
||||
getTechDocsMetadata: jest.fn().mockResolvedValue(mockTechDocsMetadata),
|
||||
};
|
||||
|
||||
const wrapper = ({
|
||||
path = '',
|
||||
entityName = {
|
||||
namespace: mockEntity.metadata.namespace!!,
|
||||
kind: mockEntity.kind,
|
||||
name: mockEntity.metadata.name,
|
||||
kind: mockEntityMetadata.kind,
|
||||
name: mockEntityMetadata.metadata.name,
|
||||
namespace: mockEntityMetadata.metadata.namespace!!,
|
||||
},
|
||||
children,
|
||||
}: {
|
||||
entityName: CompoundEntityRef;
|
||||
path?: string;
|
||||
entityName?: CompoundEntityRef;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<TechDocsMetadataProvider
|
||||
asyncValue={{
|
||||
loading: false,
|
||||
error: undefined,
|
||||
value: mockTechDocsMetadata,
|
||||
}}
|
||||
>
|
||||
<TechDocsEntityProvider
|
||||
asyncValue={{
|
||||
loading: false,
|
||||
error: undefined,
|
||||
value: mockEntity,
|
||||
}}
|
||||
>
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techdocsApiRef, techdocsApiMock]]}>
|
||||
<TechDocsMetadataProvider entityName={entityName}>
|
||||
<TechDocsEntityProvider entityName={entityName}>
|
||||
<TechDocsReaderPageProvider path={path} entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
</TestApiProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
describe('context', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('useEntityMetadata', () => {
|
||||
it('should return loading state', async () => {
|
||||
const { result } = renderHook(() => useEntityMetadata());
|
||||
@@ -87,11 +103,16 @@ describe('context', () => {
|
||||
});
|
||||
|
||||
it('should return expected entity values', async () => {
|
||||
const { result } = renderHook(() => useEntityMetadata(), { wrapper });
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => useEntityMetadata(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.value).toBeDefined();
|
||||
expect(result.current.error).toBeUndefined();
|
||||
expect(result.current.value).toMatchObject(mockEntity);
|
||||
expect(result.current.value).toMatchObject(mockEntityMetadata);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -103,7 +124,12 @@ describe('context', () => {
|
||||
});
|
||||
|
||||
it('should return expected techdocs metadata values', async () => {
|
||||
const { result } = renderHook(() => useTechDocsMetadata(), { wrapper });
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => useTechDocsMetadata(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.value).toBeDefined();
|
||||
expect(result.current.error).toBeUndefined();
|
||||
@@ -112,32 +138,49 @@ describe('context', () => {
|
||||
});
|
||||
|
||||
describe('useTechDocsReaderPage', () => {
|
||||
it('should set title', () => {
|
||||
const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper });
|
||||
it('should set title', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => useTechDocsReaderPage(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
expect(result.current.title).toBe('');
|
||||
|
||||
act(() => result.current.setTitle('test site title'));
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.title).toBe('test site title');
|
||||
});
|
||||
|
||||
it('should set subtitle', () => {
|
||||
const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper });
|
||||
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 } = renderHook(() => useTechDocsReaderPage(), { wrapper });
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => useTechDocsReaderPage(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
// mock shadowroot
|
||||
const shadowRoot = mockShadowRoot();
|
||||
|
||||
act(() => result.current.setShadowRoot(shadowRoot));
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.shadowRoot?.innerHTML).toBe(
|
||||
'<h1>Shadow DOM Mock</h1>',
|
||||
);
|
||||
|
||||
@@ -31,9 +31,8 @@ import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { techdocsApiRef } from '../../../api';
|
||||
import { TechDocsEntityMetadata, TechDocsMetadata } from '../../../types';
|
||||
|
||||
type PropsWithEntityName<T = {}> = PropsWithChildren<
|
||||
T & { entityName: CompoundEntityRef }
|
||||
>;
|
||||
type PropsWithEntityName<T = {}> = T &
|
||||
PropsWithChildren<{ entityName: CompoundEntityRef }>;
|
||||
|
||||
const initialContextValue = {
|
||||
loading: true,
|
||||
@@ -129,16 +128,16 @@ export const useTechDocsReaderPage = () => {
|
||||
};
|
||||
|
||||
type TechDocsReaderPageProviderProps = PropsWithEntityName<{
|
||||
path: string;
|
||||
path?: string;
|
||||
}>;
|
||||
|
||||
export const TechDocsReaderPageProvider = ({
|
||||
path,
|
||||
path = '',
|
||||
entityName,
|
||||
children,
|
||||
}: TechDocsReaderPageProviderProps) => {
|
||||
const metadata = useTechDocsMetadata();
|
||||
const entityMetadata = useEntityMetadata();
|
||||
const { value: entityMetadataValue } = useEntityMetadata();
|
||||
const { value: techdocsMetadataValue } = useTechDocsMetadata();
|
||||
|
||||
const [title, setTitle] = useState(defaultTechDocsReaderPageValue.title);
|
||||
const [subtitle, setSubtitle] = useState(
|
||||
@@ -165,8 +164,8 @@ export const TechDocsReaderPageProvider = ({
|
||||
{children instanceof Function
|
||||
? children({
|
||||
entityRef: entityName,
|
||||
techdocsMetadataValue: metadata.value,
|
||||
entityMetadataValue: entityMetadata.value,
|
||||
entityMetadataValue,
|
||||
techdocsMetadataValue,
|
||||
})
|
||||
: children}
|
||||
</Page>
|
||||
|
||||
@@ -25,7 +25,8 @@ import React, {
|
||||
} from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useTheme, Theme, lighten, alpha } from '@material-ui/core';
|
||||
import { useTheme, Theme } from '@material-ui/core';
|
||||
import { lighten, alpha } from '@material-ui/core/styles';
|
||||
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
+97
-51
@@ -14,41 +14,91 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { TechDocsReaderPageHeader } from './TechDocsReaderPageHeader';
|
||||
import { act } from '@testing-library/react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { act, waitFor } from '@testing-library/react';
|
||||
|
||||
import { ThemeProvider } from '@material-ui/core';
|
||||
|
||||
import { lightTheme } from '@backstage/theme';
|
||||
import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { entityRouteRef } from '@backstage/plugin-catalog-react';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
import { techdocsApiRef } from '../../../api';
|
||||
import { rootRouteRef } from '../../../routes';
|
||||
|
||||
import {
|
||||
TechDocsEntityProvider,
|
||||
TechDocsMetadataProvider,
|
||||
TechDocsReaderPageProvider,
|
||||
} from '../TechDocsReaderPage';
|
||||
|
||||
import { TechDocsReaderPageHeader } from './TechDocsReaderPageHeader';
|
||||
|
||||
const mockEntityMetadata = {
|
||||
locationMetadata: {
|
||||
type: 'github',
|
||||
target: 'https://example.com/',
|
||||
},
|
||||
apiVersion: 'v1',
|
||||
kind: 'test',
|
||||
metadata: {
|
||||
name: 'test-name',
|
||||
namespace: 'test-namespace',
|
||||
},
|
||||
spec: {
|
||||
owner: 'test',
|
||||
},
|
||||
};
|
||||
|
||||
const mockTechDocsMetadata = {
|
||||
site_name: 'test-site-name',
|
||||
site_description: 'test-site-desc',
|
||||
};
|
||||
|
||||
const getEntityMetadata = jest.fn();
|
||||
const getTechDocsMetadata = jest.fn();
|
||||
|
||||
const techdocsApiMock = {
|
||||
getEntityMetadata,
|
||||
getTechDocsMetadata,
|
||||
};
|
||||
|
||||
const Wrapper = ({
|
||||
path = '',
|
||||
entityName = {
|
||||
kind: mockEntityMetadata.kind,
|
||||
name: mockEntityMetadata.metadata.name,
|
||||
namespace: mockEntityMetadata.metadata.namespace!!,
|
||||
},
|
||||
children,
|
||||
}: {
|
||||
path?: string;
|
||||
entityName?: CompoundEntityRef;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techdocsApiRef, techdocsApiMock]]}>
|
||||
<TechDocsMetadataProvider entityName={entityName}>
|
||||
<TechDocsEntityProvider entityName={entityName}>
|
||||
<TechDocsReaderPageProvider path={path} entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
</TestApiProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
describe('<TechDocsReaderPageHeader />', () => {
|
||||
it('should render a techdocs page header', async () => {
|
||||
getEntityMetadata.mockResolvedValue(mockEntityMetadata);
|
||||
getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata);
|
||||
|
||||
await act(async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<TechDocsReaderPageHeader
|
||||
entityRef={{
|
||||
kind: 'test',
|
||||
name: 'test-name',
|
||||
namespace: 'test-namespace',
|
||||
}}
|
||||
entityMetadata={{
|
||||
locationMetadata: {
|
||||
type: 'github',
|
||||
target: 'https://example.com/',
|
||||
},
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
},
|
||||
spec: {
|
||||
owner: 'test',
|
||||
},
|
||||
}}
|
||||
techDocsMetadata={{
|
||||
site_name: 'test-site-name',
|
||||
site_description: 'test-site-desc',
|
||||
}}
|
||||
/>,
|
||||
<Wrapper>
|
||||
<TechDocsReaderPageHeader />
|
||||
</Wrapper>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
|
||||
@@ -58,7 +108,11 @@ describe('<TechDocsReaderPageHeader />', () => {
|
||||
);
|
||||
|
||||
expect(rendered.container.innerHTML).toContain('header');
|
||||
expect(rendered.getAllByText('test-site-name')).toHaveLength(2);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(rendered.getAllByText('test-site-name')).toHaveLength(2);
|
||||
});
|
||||
|
||||
expect(rendered.getByText('test-site-desc')).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -66,13 +120,9 @@ describe('<TechDocsReaderPageHeader />', () => {
|
||||
it('should render a techdocs page header even if metadata is missing', async () => {
|
||||
await act(async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<TechDocsReaderPageHeader
|
||||
entityRef={{
|
||||
kind: 'test',
|
||||
name: 'test-name',
|
||||
namespace: 'test-namespace',
|
||||
}}
|
||||
/>,
|
||||
<Wrapper>
|
||||
<TechDocsReaderPageHeader />
|
||||
</Wrapper>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
|
||||
@@ -86,19 +136,13 @@ describe('<TechDocsReaderPageHeader />', () => {
|
||||
});
|
||||
|
||||
it('should render a link back to the component page', async () => {
|
||||
getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata);
|
||||
|
||||
await act(async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<TechDocsReaderPageHeader
|
||||
entityRef={{
|
||||
kind: 'test',
|
||||
name: 'test-name',
|
||||
namespace: 'test-namespace',
|
||||
}}
|
||||
techDocsMetadata={{
|
||||
site_name: 'test-site-name',
|
||||
site_description: 'test-site-desc',
|
||||
}}
|
||||
/>,
|
||||
<Wrapper>
|
||||
<TechDocsReaderPageHeader />
|
||||
</Wrapper>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
|
||||
@@ -107,9 +151,11 @@ describe('<TechDocsReaderPageHeader />', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(rendered.container.innerHTML).toContain(
|
||||
'/catalog/test-namespace/test/test-name',
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
rendered.getByRole('link', { name: 'test:test-namespace/test-name' }),
|
||||
).toHaveAttribute('href', '/catalog/test-namespace/test/test-name');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+13
-8
@@ -43,13 +43,12 @@ import { rootRouteRef } from '../../../routes';
|
||||
|
||||
const skeleton = <Skeleton animation="wave" variant="text" height={40} />;
|
||||
|
||||
export const TechDocsReaderPageHeader: FC = props => {
|
||||
const { children } = props;
|
||||
export const TechDocsReaderPageHeader: FC = ({ children }) => {
|
||||
const addons = useTechDocsAddons();
|
||||
const configApi = useApi(configApiRef);
|
||||
|
||||
const { value: techDocsMetadata } = useTechDocsMetadata();
|
||||
const { value: entityMetadata } = useEntityMetadata();
|
||||
const { value: techDocsMetadata } = useTechDocsMetadata();
|
||||
|
||||
const {
|
||||
title,
|
||||
@@ -61,11 +60,17 @@ export const TechDocsReaderPageHeader: FC = props => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!techDocsMetadata) return;
|
||||
setTitle(prevTitle => prevTitle || techDocsMetadata.site_name);
|
||||
setSubtitle(
|
||||
prevSubtitle =>
|
||||
prevSubtitle || techDocsMetadata.site_description || 'Home',
|
||||
);
|
||||
setTitle(prevTitle => {
|
||||
const { site_name } = techDocsMetadata;
|
||||
return prevTitle || site_name;
|
||||
});
|
||||
setSubtitle(prevSubtitle => {
|
||||
let { site_description } = techDocsMetadata;
|
||||
if (site_description === 'None') {
|
||||
site_description = 'Home';
|
||||
}
|
||||
return prevSubtitle || site_description;
|
||||
});
|
||||
}, [techDocsMetadata, setTitle, setSubtitle]);
|
||||
|
||||
const appTitle = configApi.getOptional('app.title') || 'Backstage';
|
||||
|
||||
@@ -19,12 +19,13 @@ export type {
|
||||
TechDocsReaderLayoutProps,
|
||||
} from './TechDocsReaderPage';
|
||||
export {
|
||||
TechDocsReaderLayout,
|
||||
useTechDocsMetadata,
|
||||
useEntityMetadata,
|
||||
useTechDocsReaderPage,
|
||||
useShadowRoot,
|
||||
useShadowRootElements,
|
||||
useEntityMetadata,
|
||||
useTechDocsMetadata,
|
||||
useTechDocsReaderPage,
|
||||
TechDocsReaderLayout,
|
||||
TechDocsReaderPageProvider,
|
||||
} from './TechDocsReaderPage';
|
||||
export * from './TechDocsReaderPageHeader';
|
||||
export * from './TechDocsReaderPageContent';
|
||||
|
||||
Reference in New Issue
Block a user