diff --git a/plugins/catalog-node/report-testUtils.api.md b/plugins/catalog-node/report-testUtils.api.md index c1dfb0bd7a..ec50d835be 100644 --- a/plugins/catalog-node/report-testUtils.api.md +++ b/plugins/catalog-node/report-testUtils.api.md @@ -22,6 +22,4 @@ export namespace catalogServiceMock { partialImpl?: Partial | undefined, ) => ServiceMock; } - -// (No @packageDocumentation comment for this package) ``` diff --git a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx index f0da550d0b..a3230a0cc4 100644 --- a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx +++ b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx @@ -14,13 +14,14 @@ * limitations under the License. */ -import { CatalogApi, Location } from '@backstage/catalog-client'; +import { Location } from '@backstage/catalog-client'; import { Entity, ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model'; import { catalogApiRef } from '../../api'; import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; import { useUnregisterEntityDialogState } from './useUnregisterEntityDialogState'; import { TestApiProvider } from '@backstage/test-utils'; +import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; function defer(): { promise: Promise; resolve: (value: T) => void } { let resolve: (value: T) => void = () => {}; @@ -31,13 +32,7 @@ function defer(): { promise: Promise; resolve: (value: T) => void } { } describe('useUnregisterEntityDialogState', () => { - const catalogApiMock = { - getLocationByRef: jest.fn(), - getEntities: jest.fn(), - removeLocationById: jest.fn(), - removeEntityByUid: jest.fn(), - }; - const catalogApi = catalogApiMock as Partial as CatalogApi; + const catalogApi = catalogApiMock.mock(); const Wrapper = (props: { children?: React.ReactNode }) => ( @@ -58,8 +53,8 @@ describe('useUnregisterEntityDialogState', () => { resolveLocation = deferredLocation.resolve; resolveColocatedEntities = deferredColocatedEntities.resolve; - catalogApiMock.getLocationByRef.mockReturnValue(deferredLocation.promise); - catalogApiMock.getEntities.mockReturnValue( + catalogApi.getLocationByRef.mockReturnValue(deferredLocation.promise); + catalogApi.getEntities.mockReturnValue( deferredColocatedEntities.promise.then(items => ({ items })), ); diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts index 65a8dec226..b7331479ef 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; import { useGetEntities } from './useGetEntities'; -import { CatalogApi } from '@backstage/catalog-client'; import { renderHook, waitFor } from '@testing-library/react'; -import { getEntityRelations } from '@backstage/plugin-catalog-react'; +import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; const givenParentGroup = 'team.squad1'; const givenLeafGroup = 'team.squad2'; @@ -31,15 +31,14 @@ const givenUserEntity = { }, } as Partial as Entity; -const getEntitiesByRefsMock = jest.fn(); -const catalogApiMock: Pick = { +const catalogApi = catalogApiMock.mock({ getEntities: jest.fn(async () => Promise.resolve({ items: [] })), - getEntitiesByRefs: getEntitiesByRefsMock, -}; +}); -jest.mock('@backstage/core-plugin-api', () => ({ - useApi: jest.fn(() => catalogApiMock), -})); +jest.mock('@backstage/core-plugin-api', () => { + const actual = jest.requireActual('@backstage/core-plugin-api'); + return { ...actual, useApi: jest.fn(() => catalogApi) }; +}); const getEntityRelationsMock: jest.Mock< CompoundEntityRef[], @@ -50,7 +49,7 @@ jest.mock('@backstage/plugin-catalog-react', () => { catalogApiRef: {}, getEntityRelations: jest.fn(entity => { return getEntityRelationsMock(entity); - }) as typeof getEntityRelations, + }) as any, }; }); @@ -77,16 +76,17 @@ describe('useGetEntities', () => { }; beforeEach(() => { - getEntitiesByRefsMock.mockImplementation(async ({ entityRefs: [ref] }) => - ref.includes(givenParentGroup) - ? { items: [givenParentGroupEntity] } - : { items: [givenLeafGroupEntity] }, + catalogApi.getEntitiesByRefs.mockImplementation( + async ({ entityRefs: [ref] }) => + ref.includes(givenParentGroup) + ? { items: [givenParentGroupEntity] } + : { items: [givenLeafGroupEntity] }, ); }); afterEach(() => { getEntityRelationsMock.mockRestore(); - getEntitiesByRefsMock.mockRestore(); + catalogApi.getEntitiesByRefs.mockRestore(); }); describe('when given entity is a group', () => { @@ -98,7 +98,7 @@ describe('useGetEntities', () => { it('should aggregate child ownership', async () => { await whenHookIsCalledWith(givenParentGroupEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + expect(catalogApi.getEntities).toHaveBeenCalledWith( ownersFilter( `group:default/${givenParentGroup}`, `group:default/${givenLeafGroup}`, @@ -108,7 +108,7 @@ describe('useGetEntities', () => { it('should retrieve child with their relations', async () => { await whenHookIsCalledWith(givenParentGroupEntity); - expect(catalogApiMock.getEntitiesByRefs).toHaveBeenCalledWith({ + expect(catalogApi.getEntitiesByRefs).toHaveBeenCalledWith({ entityRefs: [`group:default/${givenLeafGroup}`], fields: ['kind', 'metadata.namespace', 'metadata.name', 'relations'], }); @@ -121,8 +121,8 @@ describe('useGetEntities', () => { ); beforeEach(() => { - getEntitiesByRefsMock.mockRestore(); - getEntitiesByRefsMock.mockImplementation( + catalogApi.getEntitiesByRefs.mockRestore(); + catalogApi.getEntitiesByRefs.mockImplementation( async ({ entityRefs: [ref] }) => { if (ref.includes(givenParentGroup)) { return { items: [givenParentGroupEntity] }; @@ -152,7 +152,7 @@ describe('useGetEntities', () => { }); await whenHookIsCalledWith(givenParentGroupEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + expect(catalogApi.getEntities).toHaveBeenCalledWith( ownersFilter( `group:default/${givenParentGroup}`, `group:default/${givenIntermediateGroup}`, @@ -177,7 +177,7 @@ describe('useGetEntities', () => { }); await whenHookIsCalledWith(givenParentGroupEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + expect(catalogApi.getEntities).toHaveBeenCalledWith( ownersFilter( `group:default/${givenParentGroup}`, `group:default/${givenIntermediateGroup}`, @@ -195,7 +195,7 @@ describe('useGetEntities', () => { ]); await whenHookIsCalledWith(givenUserEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + expect(catalogApi.getEntities).toHaveBeenCalledWith( ownersFilter( `group:default/${givenLeafGroup}`, `user:default/${givenUser}`, @@ -219,14 +219,14 @@ describe('useGetEntities', () => { it('given group entity should return directly owned entities', async () => { await whenHookIsCalledWith(givenLeafGroupEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + expect(catalogApi.getEntities).toHaveBeenCalledWith( ownersFilter(`group:default/${givenLeafGroup}`), ); }); it('given user entity should return directly owned entities', async () => { await whenHookIsCalledWith(givenUserEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + expect(catalogApi.getEntities).toHaveBeenCalledWith( ownersFilter(`user:default/${givenUser}`), ); }); @@ -255,7 +255,7 @@ describe('useGetEntities', () => { ? manyGroups.map(group => createGroupRefFromName(group.metadata.name)) : [], ); - (catalogApiMock.getEntities as jest.Mock).mockClear(); + catalogApi.getEntities.mockClear(); }); it('should handle 500+ relations without exceeding URL length limits', async () => { @@ -270,14 +270,13 @@ describe('useGetEntities', () => { timeout: 5000, }); - const callArgs = (catalogApiMock.getEntities as jest.Mock).mock - .calls[0][0]; + const callArgs = catalogApi.getEntities.mock.calls[0][0]; expect( - callArgs.filter[0]['relations.ownedBy'].length, + (callArgs!.filter as any)[0]['relations.ownedBy'].length, ).toBeLessThanOrEqual(100); - const owners = callArgs.filter[0]['relations.ownedBy']; + const owners = (callArgs!.filter as any)[0]['relations.ownedBy']; expect(Array.isArray(owners)).toBeTruthy(); expect(owners.length).toBeLessThanOrEqual(100); @@ -309,7 +308,7 @@ describe('useGetEntities', () => { ) : [], ); - (catalogApiMock.getEntities as jest.Mock).mockClear(); + catalogApi.getEntities.mockClear(); }); it('should batch the request to avoid exceeding header size limits', async () => { @@ -323,8 +322,7 @@ describe('useGetEntities', () => { await waitFor(() => expect(result.current.loading).toBe(false), { timeout: 5000, }); - const callArgs = (catalogApiMock.getEntities as jest.Mock).mock - .calls[0][0]; + const callArgs = catalogApi.getEntities.mock.calls[0][0]; const url = new URL( `http://localhost/api/catalog/entities?${new URLSearchParams( @@ -334,7 +332,7 @@ describe('useGetEntities', () => { const headerSize = url.href.length; expect(headerSize).toBeLessThanOrEqual(16384); - const owners = callArgs.filter[0]['relations.ownedBy']; + const owners = (callArgs!.filter as any)[0]['relations.ownedBy']; expect(Array.isArray(owners)).toBeTruthy(); expect(owners.length).toBeLessThanOrEqual(100); }); diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx index 3a2aa1469f..49f5c1feb0 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx @@ -25,7 +25,8 @@ import React from 'react'; import { Workflow } from './Workflow'; import { analyticsApiRef } from '@backstage/core-plugin-api'; import { ScaffolderApi, scaffolderApiRef } from '../../../api'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; const scaffolderApiMock: jest.Mocked = { cancelTask: jest.fn(), @@ -38,14 +39,13 @@ const scaffolderApiMock: jest.Mocked = { listTasks: jest.fn(), autocomplete: jest.fn(), }; -const catalogApiMock: jest.Mocked = { - getEntityByRef: jest.fn(), -} as any; + +const catalogApi = catalogApiMock.mock(); const analyticsMock = new MockAnalyticsApi(); const apis = TestApiRegistry.from( [scaffolderApiRef, scaffolderApiMock], - [catalogApiRef, catalogApiMock], + [catalogApiRef, catalogApi], [analyticsApiRef, analyticsMock], ); diff --git a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx index 689a96b95d..750efd70d0 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { ApiProvider } from '@backstage/core-app-api'; import { analyticsApiRef } from '@backstage/core-plugin-api'; import { @@ -30,8 +31,8 @@ import { import { TemplateWizardPage } from './TemplateWizardPage'; import { rootRouteRef } from '../../../routes'; import { ANNOTATION_EDIT_URL } from '@backstage/catalog-model'; -import { CatalogApi } from '@backstage/catalog-client'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; jest.mock('react-router-dom', () => { return { @@ -54,16 +55,14 @@ const scaffolderApiMock: jest.Mocked = { autocomplete: jest.fn(), }; -const catalogApiMock: jest.Mocked = { - getEntityByRef: jest.fn(), -} as any; +const catalogApi = catalogApiMock.mock(); const analyticsMock = new MockAnalyticsApi(); const apis = TestApiRegistry.from( [scaffolderApiRef, scaffolderApiMock], - [catalogApiRef, catalogApiMock], + [catalogApiRef, catalogApi], [analyticsApiRef, analyticsMock], - [catalogApiRef, catalogApiMock], + [catalogApiRef, catalogApi], ); const entityRefResponse = { @@ -100,7 +99,7 @@ describe('TemplateWizardPage', () => { ], title: 'React JSON Schema Form Test', }); - catalogApiMock.getEntityByRef.mockResolvedValue(entityRefResponse); + catalogApi.getEntityByRef.mockResolvedValue(entityRefResponse); const { findByRole, getByRole } = await renderInTestApp( @@ -147,7 +146,7 @@ describe('TemplateWizardPage', () => { }); describe('scaffolder page context menu', () => { it('should render if editUrl is set to url', async () => { - catalogApiMock.getEntityByRef.mockResolvedValue({ + catalogApi.getEntityByRef.mockResolvedValue({ apiVersion: 'v1', kind: 'service', metadata: { @@ -177,7 +176,7 @@ describe('TemplateWizardPage', () => { expect(queryByTestId('menu-button')).toBeInTheDocument(); }); it('should not render if editUrl is undefined', async () => { - catalogApiMock.getEntityByRef.mockResolvedValue({ + catalogApi.getEntityByRef.mockResolvedValue({ apiVersion: 'v1', kind: 'service', metadata: {