EntityTypePicker test

Signed-off-by: Tim Hansen <timbonicus@gmail.com>
This commit is contained in:
Tim Hansen
2021-05-13 11:50:31 -06:00
parent 5666efa9da
commit 00838c02db
7 changed files with 143 additions and 5 deletions
@@ -0,0 +1,137 @@
/*
* Copyright 2021 Spotify AB
*
* 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 React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { capitalize } from 'lodash';
import {
AlertApi,
alertApiRef,
ApiProvider,
ApiRegistry,
} from '@backstage/core';
import { CatalogApi } from '@backstage/catalog-client';
import { Entity } from '@backstage/catalog-model';
import { EntityTypePicker } from './EntityTypePicker';
import { MockEntityListContextProvider } from '../../testUtils/providers';
import { catalogApiRef } from '../../api';
import { EntityKindFilter, EntityTypeFilter } from '../../types';
const entities: Entity[] = [
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'component-1',
},
spec: {
type: 'service',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'component-2',
},
spec: {
type: 'website',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'component-3',
},
spec: {
type: 'library',
},
},
];
const apis = ApiRegistry.from([
[
catalogApiRef,
({
getEntities: jest
.fn()
.mockImplementation(() => Promise.resolve({ items: entities })),
} as unknown) as CatalogApi,
],
[
alertApiRef,
({
post: jest.fn(),
} as unknown) as AlertApi,
],
]);
describe('<EntityTypePicker/>', () => {
it('renders available entity types', async () => {
const rendered = render(
<ApiProvider apis={apis}>
<MockEntityListContextProvider
value={{ filters: { kind: new EntityKindFilter('component') } }}
>
<EntityTypePicker />
</MockEntityListContextProvider>
</ApiProvider>,
);
expect(rendered.getByText('Type')).toBeInTheDocument();
const input = await rendered.getByTestId('select');
fireEvent.click(input);
await waitFor(() => rendered.getByText('Service'));
entities.forEach(entity => {
expect(
rendered.getByText(capitalize(entity.spec!.type as string)),
).toBeInTheDocument();
});
});
it('sets the selected type filter', async () => {
const updateFilters = jest.fn();
const rendered = render(
<ApiProvider apis={apis}>
<MockEntityListContextProvider
value={{
filters: { kind: new EntityKindFilter('component') },
updateFilters,
}}
>
<EntityTypePicker />
</MockEntityListContextProvider>
</ApiProvider>,
);
const input = await rendered.getByTestId('select');
fireEvent.click(input);
await waitFor(() => rendered.getByText('Service'));
fireEvent.click(rendered.getByText('Service'));
expect(updateFilters).toHaveBeenLastCalledWith({
type: new EntityTypeFilter('service'),
});
fireEvent.click(input);
fireEvent.click(rendered.getByText('All'));
expect(updateFilters).toHaveBeenLastCalledWith({ type: undefined });
});
});
@@ -18,7 +18,7 @@ import React from 'react';
import { capitalize } from 'lodash';
import { Box } from '@material-ui/core';
import { alertApiRef, Select, useApi } from '@backstage/core';
import { useEntityTypeFilter } from '@backstage/plugin-catalog-react';
import { useEntityTypeFilter } from '../../hooks/useEntityTypeFilter';
export const EntityTypePicker = () => {
const alertApi = useApi(alertApiRef);
@@ -17,4 +17,5 @@ export * from './EntityProvider';
export * from './EntityRefLink';
export * from './EntityTable';
export * from './EntityTagPicker';
export * from './EntityTypePicker';
export * from './UserListPicker';
@@ -98,7 +98,8 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>({
const { value: user } = useOwnUser();
const { isStarredEntity } = useStarredEntities();
// TODO(timbonicus): should query params be registered as initialFilters when present?
// TODO(timbonicus): is it possible to register initial filters from query params? e.g. if the
// query key matches the generic definition, call a constructor with the value
const [filters, setFilters] = useState<EntityFilters>(
initialFilters ?? ({} as EntityFilters),
);
@@ -28,6 +28,7 @@ import {
EntityKindFilter,
EntityListProvider,
EntityTagPicker,
EntityTypePicker,
UserListFilter,
UserListFilterKind,
UserListPicker,
@@ -37,7 +38,6 @@ import { createComponentRouteRef } from '../../routes';
import { CatalogTable } from '../CatalogTable';
import { EntityRow } from '../CatalogTable/types';
import CatalogLayout from './CatalogLayout';
import { EntityTypePicker } from '../EntityTypePicker';
const useStyles = makeStyles(theme => ({
contentWrapper: {
@@ -58,11 +58,10 @@ type CatalogTableProps = {
export const CatalogTable = ({ columns }: CatalogTableProps) => {
const { isStarredEntity, toggleStarredEntity } = useStarredEntities();
// TODO(timbonicus): should the component loading entities register which fields it's interested in?
const { loading, error, entities, filters } = useEntityListProvider();
const showTypeColumn = filters.type !== undefined;
// TODO(timbonicus): this makes less sense with more complex filters, should we show filter chips instead?
// TODO(timbonicus): we should show filter chips for all filters instead
const titlePreamble = capitalize(filters.user?.value ?? 'all');
if (error) {