diff --git a/.changeset/shaky-parents-enter.md b/.changeset/shaky-parents-enter.md new file mode 100644 index 0000000000..5e81402bed --- /dev/null +++ b/.changeset/shaky-parents-enter.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': patch +--- + +allow arrays in the InMemoryCatalogClient to filter entities diff --git a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts index b77fcd0676..c5d1f3abc8 100644 --- a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts +++ b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts @@ -26,12 +26,12 @@ const entity1: Entity = { name: 'e1', uid: 'u1', }, - relations: [{ type: 'relatedTo', targetRef: 'customkind:default/e2' }], + relations: [{ type: 'relatedTo', targetRef: 'secondcustomkind:default/e2' }], }; const entity2: Entity = { apiVersion: 'v1', - kind: 'CustomKind', + kind: 'SecondCustomKind', metadata: { namespace: 'default', name: 'e2', @@ -67,9 +67,21 @@ describe('InMemoryCatalogClient', () => { await expect( client.getEntities({ - filter: { 'relations.relatedTo': 'customkind:default/e2' }, + filter: { 'relations.relatedTo': 'secondcustomkind:default/e2' }, }), ).resolves.toEqual({ items: [entity1] }); + + await expect( + client.getEntities({ + filter: { kind: ['not-existing', 'CustomKind'] }, + }), + ).resolves.toEqual({ items: [entity1] }); + + await expect( + client.getEntities({ + filter: { kind: ['SecondCustomKind', 'also-not-existing'] }, + }), + ).resolves.toEqual({ items: [entity2] }); }); it('getEntitiesByRefs', async () => { @@ -77,7 +89,7 @@ describe('InMemoryCatalogClient', () => { await expect( client.getEntitiesByRefs({ entityRefs: [ - 'customkind:default/e2', + 'secondcustomkind:default/e2', 'customkind:missing/missing', 'customkind:default/e1', ], @@ -86,7 +98,7 @@ describe('InMemoryCatalogClient', () => { await expect( client.getEntitiesByRefs({ entityRefs: [ - 'customkind:default/e2', + 'secondcustomkind:default/e2', 'customkind:missing/missing', 'customkind:default/e1', ], @@ -114,9 +126,9 @@ describe('InMemoryCatalogClient', () => { it('getEntityAncestors', async () => { const client = new InMemoryCatalogClient({ entities }); await expect( - client.getEntityAncestors({ entityRef: 'customkind:default/e2' }), + client.getEntityAncestors({ entityRef: 'secondcustomkind:default/e2' }), ).resolves.toEqual({ - rootEntityRef: 'customkind:default/e2', + rootEntityRef: 'secondcustomkind:default/e2', items: [{ entity: entity2, parentEntityRefs: [] }], }); }); @@ -124,7 +136,7 @@ describe('InMemoryCatalogClient', () => { it('getEntityByRef', async () => { const client = new InMemoryCatalogClient({ entities }); await expect( - client.getEntityByRef('customkind:default/e2'), + client.getEntityByRef('secondcustomkind:default/e2'), ).resolves.toEqual(entity2); await expect( client.getEntityByRef('customkind:missing/missing'), @@ -147,7 +159,7 @@ describe('InMemoryCatalogClient', () => { it('refreshEntity', async () => { const client = new InMemoryCatalogClient({ entities }); await expect( - client.refreshEntity('customkind:default/e2'), + client.refreshEntity('secondcustomkind:default/e2'), ).resolves.toBeUndefined(); }); }); diff --git a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts index a7dd333729..746871a1b3 100644 --- a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts +++ b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts @@ -106,6 +106,11 @@ function createFilter( if (expectedValue === CATALOG_FILTER_EXISTS) { continue; } + if (Array.isArray(expectedValue)) { + return expectedValue.some(value => + searchValues?.includes(String(value).toLocaleLowerCase('en-US')), + ); + } if ( !searchValues?.includes( String(expectedValue).toLocaleLowerCase('en-US'), diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index f5b01e918a..6ea0f0cbc9 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -14,10 +14,6 @@ * limitations under the License. */ -import { - GetEntitiesRequest, - GetEntitiesResponse, -} from '@backstage/catalog-client'; import { Entity, GroupEntity, UserEntity } from '@backstage/catalog-model'; import { catalogApiRef, EntityProvider } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; @@ -104,18 +100,6 @@ const items = [ }, ] as Entity[]; -const getEntitiesMock = ( - request?: GetEntitiesRequest, -): Promise => { - const filterKinds = - Array.isArray(request?.filter) && Array.isArray(request?.filter[0].kind) - ? request?.filter[0].kind ?? [] - : []; // we expect the request to be like { filter: [{ kind: ['API','System'], 'relations.ownedBy': [group:default/my-team], .... }]. If changed in OwnerShipCard, let's change in also here - return Promise.resolve({ - items: items.filter(item => filterKinds.find(k => k === item.kind)), - } as GetEntitiesResponse); -}; - describe('OwnershipCard', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -157,7 +141,8 @@ describe('OwnershipCard', () => { }; it('displays entity counts', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); + const mockedGetEntities = jest.spyOn(catalogApi, 'getEntities'); const { getByText } = await renderInTestApp( @@ -172,7 +157,7 @@ describe('OwnershipCard', () => { }, ); - expect(catalogApi.getEntities).toHaveBeenCalledWith({ + expect(mockedGetEntities).toHaveBeenCalledWith({ filter: [ { kind: ['Component', 'API', 'System'], @@ -207,7 +192,7 @@ describe('OwnershipCard', () => { }); it('applies CustomFilterDefinition', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByText } = await renderInTestApp( @@ -240,7 +225,7 @@ describe('OwnershipCard', () => { }); it('links to the catalog with the group filter', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByText } = await renderInTestApp( @@ -263,7 +248,7 @@ describe('OwnershipCard', () => { }); it('links to the catalog with the user and groups filters from an user profile', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByText } = await renderInTestApp( @@ -288,7 +273,7 @@ describe('OwnershipCard', () => { describe('OwnershipCard relations', () => { it('shows relations toggle', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByTitle } = await renderInTestApp( @@ -307,7 +292,7 @@ describe('OwnershipCard', () => { }); it('hides relations toggle', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const rendered = await renderInTestApp( @@ -326,7 +311,7 @@ describe('OwnershipCard', () => { }); it('overrides relation type', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByTitle } = await renderInTestApp( @@ -345,7 +330,7 @@ describe('OwnershipCard', () => { }); it('defaults to aggregated for User entity kind', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByLabelText } = await renderInTestApp( @@ -364,7 +349,7 @@ describe('OwnershipCard', () => { }); it('defaults to direct for all entity kinds except User', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByLabelText } = await renderInTestApp( @@ -383,7 +368,7 @@ describe('OwnershipCard', () => { }); it('defaults to provided relationsType', async () => { - const catalogApi = catalogApiMock.mock({ getEntities: getEntitiesMock }); + const catalogApi = catalogApiMock({ entities: items }); const { getByLabelText } = await renderInTestApp(