From 03ec06bf7f62daa648c34eea70080881d0b00eef Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 18 Feb 2022 17:05:28 +0100 Subject: [PATCH 1/3] catalog-react: refactor and fixes for DefaultStarredEntitiesApi Signed-off-by: Patrik Oldsberg --- .changeset/silver-boxes-flash.md | 7 + plugins/catalog-react/api-report.md | 2 - .../DefaultStarredEntitiesApi.test.ts | 120 ++++++++---------- .../DefaultStarredEntitiesApi.ts | 8 +- 4 files changed, 65 insertions(+), 72 deletions(-) create mode 100644 .changeset/silver-boxes-flash.md diff --git a/.changeset/silver-boxes-flash.md b/.changeset/silver-boxes-flash.md new file mode 100644 index 0000000000..4d3d70259a --- /dev/null +++ b/.changeset/silver-boxes-flash.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fixed a risky behavior where `DefaultStarredEntitiesApi` forwarded values to observers that were later mutated. + +Removed the `isStarred` method from `DefaultStarredEntitiesApi`, as it is not part of the `StarredEntitiesApi`. diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index e78ec75daa..add76a7c1c 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -142,8 +142,6 @@ export type DefaultEntityFilters = { export class DefaultStarredEntitiesApi implements StarredEntitiesApi { constructor(opts: { storageApi: StorageApi }); // (undocumented) - isStarred(entityRef: string): boolean; - // (undocumented) starredEntitie$(): Observable>; // (undocumented) toggleStarred(entityRef: string): Promise; diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts b/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts index 55b992fadf..2a3c4d83ed 100644 --- a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts +++ b/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts @@ -14,33 +14,27 @@ * limitations under the License. */ -import { stringifyEntityRef } from '@backstage/catalog-model'; -import { StorageApi } from '@backstage/core-plugin-api'; import { MockStorageApi } from '@backstage/test-utils'; import { DefaultStarredEntitiesApi } from './DefaultStarredEntitiesApi'; import { performMigrationToTheNewBucket } from './migration'; jest.mock('./migration'); -describe('DefaultStarredEntitiesApi', () => { - let mockStorage: StorageApi; - let starredEntitiesApi: DefaultStarredEntitiesApi; - - const mockEntityRef = stringifyEntityRef({ - apiVersion: '1', - kind: 'Component', - metadata: { - name: 'mock', - }, +function getStarred(api: DefaultStarredEntitiesApi) { + return new Promise((resolve, reject) => { + const subscription = api.starredEntitie$().subscribe({ + next(starred) { + resolve(starred); + subscription.unsubscribe(); + }, + error: reject, + }); }); +} +describe('DefaultStarredEntitiesApi', () => { beforeEach(() => { (performMigrationToTheNewBucket as jest.Mock).mockResolvedValue(undefined); - - mockStorage = MockStorageApi.create(); - starredEntitiesApi = new DefaultStarredEntitiesApi({ - storageApi: mockStorage, - }); }); afterEach(() => { @@ -49,55 +43,53 @@ describe('DefaultStarredEntitiesApi', () => { describe('constructor', () => { it('should call migration', () => { - expect(performMigrationToTheNewBucket).toBeCalledTimes(1); - }); - }); - - describe('toggleStarred', () => { - it('should star unstarred entity', async () => { - expect(starredEntitiesApi.isStarred(mockEntityRef)).toBe(false); - - await starredEntitiesApi.toggleStarred(mockEntityRef); - - expect(starredEntitiesApi.isStarred(mockEntityRef)).toBe(true); - }); - - it('should unstar starred entity', async () => { - const bucket = mockStorage.forBucket('starredEntities'); - await bucket.set('entityRefs', ['component:default/mock']); - - expect(starredEntitiesApi.isStarred(mockEntityRef)).toBe(true); - - await starredEntitiesApi.toggleStarred(mockEntityRef); - - expect(starredEntitiesApi.isStarred(mockEntityRef)).toBe(false); - }); - }); - - describe('starredEntities$', () => { - const handler = jest.fn(); - - beforeEach(async () => { - await new Promise(resolve => { - starredEntitiesApi.starredEntitie$().subscribe({ - next: (...args) => { - handler(...args); - - if (handler.mock.calls.length >= 2) { - resolve(); - } - }, - }); - - const bucket = mockStorage.forBucket('starredEntities'); - bucket.set('entityRefs', ['component:default/mock']).then(); + const api = new DefaultStarredEntitiesApi({ + storageApi: MockStorageApi.create(), }); + expect(performMigrationToTheNewBucket).toBeCalledTimes(1); + expect(api).toBeDefined(); + }); + }); + + it('should notify and toggle starred entities', async () => { + const entityRef = 'component:default/mock'; + + const storageApi = MockStorageApi.create(); + const storageBucket = storageApi.forBucket('starredEntities'); + const api = new DefaultStarredEntitiesApi({ storageApi }); + + const values = new Array>(); + api.starredEntitie$().subscribe({ + next: value => { + values.push(value); + }, }); - it('should receive updates', async () => { - expect(handler).toBeCalledTimes(2); - expect(handler).toBeCalledWith(new Set()); - expect(handler).toBeCalledWith(new Set(['component:default/mock'])); - }); + await expect(getStarred(api)).resolves.toEqual(new Set()); + + await api.toggleStarred(entityRef); + await expect(getStarred(api)).resolves.toEqual(new Set([entityRef])); + expect(storageBucket.snapshot('entityRefs')).toEqual( + expect.objectContaining({ presence: 'present', value: [entityRef] }), + ); + + await api.toggleStarred(entityRef); + await expect(getStarred(api)).resolves.toEqual(new Set()); + expect(storageBucket.snapshot('entityRefs')).toEqual( + expect.objectContaining({ presence: 'present', value: [] }), + ); + + expect(values).toEqual([new Set(), new Set([entityRef]), new Set()]); + }); + + it('should read starred entities from storage', async () => { + const entityRef = 'component:default/mock'; + + const storageApi = MockStorageApi.create(); + const storageBucket = storageApi.forBucket('starredEntities'); + storageBucket.set('entityRefs', [entityRef]); + const api = new DefaultStarredEntitiesApi({ storageApi }); + + await expect(getStarred(api)).resolves.toEqual(new Set([entityRef])); }); }); diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts b/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts index 46a8e63084..c411c5a81f 100644 --- a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts +++ b/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts @@ -64,17 +64,13 @@ export class DefaultStarredEntitiesApi implements StarredEntitiesApi { return this.observable; } - isStarred(entityRef: string): boolean { - return this.starredEntities.has(entityRef); - } - private readonly subscribers = new Set< ZenObservable.SubscriptionObserver> >(); private readonly observable = new ObservableImpl>(subscriber => { // forward the the latest value - subscriber.next(this.starredEntities); + subscriber.next(new Set(this.starredEntities)); this.subscribers.add(subscriber); return () => { @@ -84,7 +80,7 @@ export class DefaultStarredEntitiesApi implements StarredEntitiesApi { private notifyChanges() { for (const subscription of this.subscribers) { - subscription.next(this.starredEntities); + subscription.next(new Set(this.starredEntities)); } } } From c077b432b8cf1f76ea95881b84df9d2949cba2be Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 18 Feb 2022 17:42:18 +0100 Subject: [PATCH 2/3] catalog-react: moved DefaultStarredEntitiesApi implementation to catalog plugin Signed-off-by: Patrik Oldsberg --- .changeset/silver-boxes-flash.md | 2 ++ .../src/components/catalog/EntityPage.test.tsx | 4 +++- .../DefaultApiExplorerPage.test.tsx | 6 ++++-- plugins/catalog-react/api-report.md | 10 ---------- .../src/apis/StarredEntitiesApi/index.ts | 1 - .../src/hooks/useEntityListProvider.test.tsx | 3 ++- .../src/hooks/useStarredEntities.test.tsx | 3 ++- plugins/catalog/api-report.md | 12 ++++++++++++ plugins/catalog/package.json | 4 +++- .../DefaultStarredEntitiesApi.test.ts | 0 .../DefaultStarredEntitiesApi.ts | 2 +- .../src/apis/StarredEntitiesApi/index.ts | 17 +++++++++++++++++ .../apis/StarredEntitiesApi/migration.test.ts | 0 .../src/apis/StarredEntitiesApi/migration.ts | 0 plugins/catalog/src/apis/index.ts | 17 +++++++++++++++++ .../CatalogPage/DefaultCatalogPage.test.tsx | 2 +- .../CatalogTable/CatalogTable.test.tsx | 2 +- .../EntityLayout/EntityLayout.test.tsx | 2 +- plugins/catalog/src/index.ts | 2 ++ plugins/catalog/src/plugin.ts | 2 +- .../StarredEntities/Content.test.tsx | 2 +- .../StarredEntities/StarredEntities.stories.tsx | 2 +- .../src/templates/DefaultTemplate.stories.tsx | 3 +-- plugins/scaffolder/dev/index.tsx | 6 ++++-- .../components/DefaultTechDocsHome.test.tsx | 2 +- 25 files changed, 77 insertions(+), 29 deletions(-) rename plugins/{catalog-react => catalog}/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts (100%) rename plugins/{catalog-react => catalog}/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts (97%) create mode 100644 plugins/catalog/src/apis/StarredEntitiesApi/index.ts rename plugins/{catalog-react => catalog}/src/apis/StarredEntitiesApi/migration.test.ts (100%) rename plugins/{catalog-react => catalog}/src/apis/StarredEntitiesApi/migration.ts (100%) create mode 100644 plugins/catalog/src/apis/index.ts diff --git a/.changeset/silver-boxes-flash.md b/.changeset/silver-boxes-flash.md index 4d3d70259a..3b860a06d6 100644 --- a/.changeset/silver-boxes-flash.md +++ b/.changeset/silver-boxes-flash.md @@ -2,6 +2,8 @@ '@backstage/plugin-catalog-react': patch --- +**BREAKING**: Moved **DefaultStarredEntitiesApi** to `@backstage/plugin-catalog`. If you were using this in tests, you can add `@backstage/plugin-catalog` your packages `devDependencies` instead. + Fixed a risky behavior where `DefaultStarredEntitiesApi` forwarded values to observers that were later mutated. Removed the `isStarred` method from `DefaultStarredEntitiesApi`, as it is not part of the `StarredEntitiesApi`. diff --git a/packages/app/src/components/catalog/EntityPage.test.tsx b/packages/app/src/components/catalog/EntityPage.test.tsx index b68b9e9895..4608dc7533 100644 --- a/packages/app/src/components/catalog/EntityPage.test.tsx +++ b/packages/app/src/components/catalog/EntityPage.test.tsx @@ -14,9 +14,11 @@ * limitations under the License. */ -import { EntityLayout } from '@backstage/plugin-catalog'; import { + EntityLayout, DefaultStarredEntitiesApi, +} from '@backstage/plugin-catalog'; +import { EntityProvider, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx index 16b335b0a7..5924af3ef3 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx @@ -22,11 +22,13 @@ import { configApiRef, storageApiRef, } from '@backstage/core-plugin-api'; -import { CatalogTableRow } from '@backstage/plugin-catalog'; +import { + CatalogTableRow, + DefaultStarredEntitiesApi, +} from '@backstage/plugin-catalog'; import { CatalogApi, catalogApiRef, - DefaultStarredEntitiesApi, entityRouteRef, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index add76a7c1c..b8f0fa5538 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -24,7 +24,6 @@ import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { StorageApi } from '@backstage/core-plugin-api'; import { StyleRules } from '@material-ui/core/styles/withStyles'; import { SystemEntity } from '@backstage/catalog-model'; import { TableColumn } from '@backstage/core-components'; @@ -138,15 +137,6 @@ export type DefaultEntityFilters = { text?: EntityTextFilter; }; -// @public -export class DefaultStarredEntitiesApi implements StarredEntitiesApi { - constructor(opts: { storageApi: StorageApi }); - // (undocumented) - starredEntitie$(): Observable>; - // (undocumented) - toggleStarred(entityRef: string): Promise; -} - // @public (undocumented) export type EntityFilter = { getCatalogFilters?: () => Record< diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts b/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts index e9f9c8923a..94a221b36f 100644 --- a/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts +++ b/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts @@ -14,6 +14,5 @@ * limitations under the License. */ -export { DefaultStarredEntitiesApi } from './DefaultStarredEntitiesApi'; export { starredEntitiesApiRef } from './StarredEntitiesApi'; export type { StarredEntitiesApi } from './StarredEntitiesApi'; diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index c8ca29b07f..5db9e2be9c 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -23,13 +23,14 @@ import { identityApiRef, storageApiRef, } from '@backstage/core-plugin-api'; +import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; import { act, renderHook } from '@testing-library/react-hooks'; import qs from 'qs'; import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router'; import { catalogApiRef } from '../api'; -import { DefaultStarredEntitiesApi, starredEntitiesApiRef } from '../apis'; +import { starredEntitiesApiRef } from '../apis'; import { EntityKindPicker, UserListPicker } from '../components'; import { EntityKindFilter, EntityTypeFilter, UserListFilter } from '../filters'; import { UserListFilterKind } from '../types'; diff --git a/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx b/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx index aef876a1b2..949ac6515b 100644 --- a/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx +++ b/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx @@ -16,10 +16,11 @@ import { Entity } from '@backstage/catalog-model'; import { StorageApi } from '@backstage/core-plugin-api'; +import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; import { act, renderHook } from '@testing-library/react-hooks'; import React, { PropsWithChildren } from 'react'; -import { DefaultStarredEntitiesApi, starredEntitiesApiRef } from '../apis'; +import { starredEntitiesApiRef } from '../apis'; import { useStarredEntities } from './useStarredEntities'; describe('useStarredEntities', () => { diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index bd5edcbfa6..f314932b9a 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -13,10 +13,13 @@ import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; import { IndexableDocument } from '@backstage/search-common'; import { InfoCardVariants } from '@backstage/core-components'; +import { Observable } from '@backstage/types'; import { Overrides } from '@material-ui/core/styles/overrides'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; +import { StarredEntitiesApi } from '@backstage/plugin-catalog-react'; +import { StorageApi } from '@backstage/core-plugin-api'; import { StyleRules } from '@material-ui/core/styles/withStyles'; import { TableColumn } from '@backstage/core-components'; import { TableProps } from '@backstage/core-components'; @@ -170,6 +173,15 @@ export interface DefaultCatalogPageProps { initiallySelectedFilter?: UserListFilterKind; } +// @public +export class DefaultStarredEntitiesApi implements StarredEntitiesApi { + constructor(opts: { storageApi: StorageApi }); + // (undocumented) + starredEntitie$(): Observable>; + // (undocumented) + toggleStarred(entityRef: string): Promise; +} + // @public (undocumented) export interface DependencyOfComponentsCardProps { // (undocumented) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index f7800af139..6179cf6c44 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -44,6 +44,7 @@ "@backstage/plugin-catalog-react": "^0.7.0", "@backstage/search-common": "^0.2.4", "@backstage/theme": "^0.2.15", + "@backstage/types": "^0.1.2", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -51,7 +52,8 @@ "lodash": "^4.17.21", "react-helmet": "6.1.0", "react-router": "6.0.0-beta.0", - "react-use": "^17.2.4" + "react-use": "^17.2.4", + "zen-observable": "^0.8.15" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts similarity index 100% rename from plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts rename to plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.test.ts diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts similarity index 97% rename from plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts rename to plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts index c411c5a81f..e9cf84f11b 100644 --- a/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts +++ b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts @@ -15,10 +15,10 @@ */ import { StorageApi } from '@backstage/core-plugin-api'; +import { StarredEntitiesApi } from '@backstage/plugin-catalog-react'; import { Observable } from '@backstage/types'; import ObservableImpl from 'zen-observable'; import { performMigrationToTheNewBucket } from './migration'; -import { StarredEntitiesApi } from './StarredEntitiesApi'; /** * Default implementation of the StarredEntitiesApi that is backed by the StorageApi. diff --git a/plugins/catalog/src/apis/StarredEntitiesApi/index.ts b/plugins/catalog/src/apis/StarredEntitiesApi/index.ts new file mode 100644 index 0000000000..42dc977fb6 --- /dev/null +++ b/plugins/catalog/src/apis/StarredEntitiesApi/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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. + */ + +export { DefaultStarredEntitiesApi } from './DefaultStarredEntitiesApi'; diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/migration.test.ts b/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts similarity index 100% rename from plugins/catalog-react/src/apis/StarredEntitiesApi/migration.test.ts rename to plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/migration.ts b/plugins/catalog/src/apis/StarredEntitiesApi/migration.ts similarity index 100% rename from plugins/catalog-react/src/apis/StarredEntitiesApi/migration.ts rename to plugins/catalog/src/apis/StarredEntitiesApi/migration.ts diff --git a/plugins/catalog/src/apis/index.ts b/plugins/catalog/src/apis/index.ts new file mode 100644 index 0000000000..5c7e980890 --- /dev/null +++ b/plugins/catalog/src/apis/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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. + */ + +export * from './StarredEntitiesApi'; diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index dcf819f976..e36c1e9338 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -29,7 +29,6 @@ import { } from '@backstage/core-plugin-api'; import { catalogApiRef, - DefaultStarredEntitiesApi, entityRouteRef, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; @@ -43,6 +42,7 @@ import { import DashboardIcon from '@material-ui/icons/Dashboard'; import { fireEvent, screen } from '@testing-library/react'; import React from 'react'; +import { DefaultStarredEntitiesApi } from '../../apis'; import { createComponentRouteRef } from '../../routes'; import { CatalogTableRow } from '../CatalogTable'; import { DefaultCatalogPage } from './DefaultCatalogPage'; diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index db9835e3a3..1d49638eed 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -22,7 +22,6 @@ import { import { ApiProvider } from '@backstage/core-app-api'; import { entityRouteRef, - DefaultStarredEntitiesApi, MockEntityListContextProvider, starredEntitiesApiRef, UserListFilter, @@ -34,6 +33,7 @@ import { } from '@backstage/test-utils'; import { act, fireEvent } from '@testing-library/react'; import * as React from 'react'; +import { DefaultStarredEntitiesApi } from '../../apis'; import { CatalogTable } from './CatalogTable'; const entities: Entity[] = [ diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index 78dcf855e8..b29261c28b 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -21,7 +21,6 @@ import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; import { AsyncEntityProvider, catalogApiRef, - DefaultStarredEntitiesApi, EntityProvider, entityRouteRef, starredEntitiesApiRef, @@ -36,6 +35,7 @@ import { import { act, fireEvent } from '@testing-library/react'; import React from 'react'; import { Route, Routes } from 'react-router'; +import { DefaultStarredEntitiesApi } from '../../apis'; import { EntityLayout } from './EntityLayout'; const mockEntity = { diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index fef420d6d3..662a920f8b 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -20,6 +20,8 @@ * @packageDocumentation */ +export * from './apis'; + export * from './components/AboutCard'; export * from './components/CatalogKindHeader'; export * from './components/CatalogSearchResultListItem'; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index b4d1a61bc1..520656e921 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -19,7 +19,6 @@ import { Entity } from '@backstage/catalog-model'; import { catalogApiRef, catalogRouteRef, - DefaultStarredEntitiesApi, entityRouteRef, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; @@ -33,6 +32,7 @@ import { fetchApiRef, storageApiRef, } from '@backstage/core-plugin-api'; +import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; import { DefaultCatalogPageProps } from './components/CatalogPage'; import { DependencyOfComponentsCardProps } from './components/DependencyOfComponentsCard'; diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx index ccc36f6964..ae4a84473f 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx @@ -21,8 +21,8 @@ import { import { starredEntitiesApiRef, entityRouteRef, - DefaultStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; +import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import React from 'react'; import { Content } from './Content'; diff --git a/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx b/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx index 2e63762369..55486a5dcd 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx @@ -23,8 +23,8 @@ import { import { starredEntitiesApiRef, entityRouteRef, - DefaultStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; +import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { Grid } from '@material-ui/core'; import React, { ComponentType } from 'react'; diff --git a/plugins/home/src/templates/DefaultTemplate.stories.tsx b/plugins/home/src/templates/DefaultTemplate.stories.tsx index ba5e1f33fd..86d1b60022 100644 --- a/plugins/home/src/templates/DefaultTemplate.stories.tsx +++ b/plugins/home/src/templates/DefaultTemplate.stories.tsx @@ -26,8 +26,8 @@ import { Content, Page, InfoCard } from '@backstage/core-components'; import { starredEntitiesApiRef, entityRouteRef, - DefaultStarredEntitiesApi } from '@backstage/plugin-catalog-react'; +import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { HomePageSearchBar, SearchContextProvider, @@ -153,4 +153,3 @@ export const DefaultTemplate = () => { ); }; - diff --git a/plugins/scaffolder/dev/index.tsx b/plugins/scaffolder/dev/index.tsx index 78e6254e09..6ecc1a4564 100644 --- a/plugins/scaffolder/dev/index.tsx +++ b/plugins/scaffolder/dev/index.tsx @@ -20,7 +20,6 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { catalogApiRef, starredEntitiesApiRef, - DefaultStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { scaffolderApiRef, ScaffolderClient } from '../src'; @@ -30,7 +29,10 @@ import { fetchApiRef, storageApiRef, } from '@backstage/core-plugin-api'; -import { CatalogEntityPage } from '@backstage/plugin-catalog'; +import { + CatalogEntityPage, + DefaultStarredEntitiesApi, +} from '@backstage/plugin-catalog'; createDevApp() .addPage({ diff --git a/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx b/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx index 8618c4432f..678c737547 100644 --- a/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx +++ b/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx @@ -20,10 +20,10 @@ import { configApiRef, storageApiRef, } from '@backstage/core-plugin-api'; +import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { CatalogApi, catalogApiRef, - DefaultStarredEntitiesApi, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; import { From 303063a655cc5dad3b59c45aa221bffecc41a83c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 28 Feb 2022 14:29:23 +0100 Subject: [PATCH 3/3] catalog-react: added MockStarredEntitiesApi + usage Signed-off-by: Patrik Oldsberg --- .changeset/silver-boxes-flash.md | 2 +- .../components/catalog/EntityPage.test.tsx | 14 +---- plugins/catalog-react/api-report.md | 8 +++ .../MockStarredEntitiesApi.test.ts | 61 +++++++++++++++++++ .../MockStarredEntitiesApi.ts | 54 ++++++++++++++++ .../src/apis/StarredEntitiesApi/index.ts | 1 + .../src/hooks/useEntityListProvider.test.tsx | 10 +-- .../src/hooks/useStarredEntities.test.tsx | 32 +++++----- .../CatalogPage/DefaultCatalogPage.test.tsx | 7 +-- .../CatalogTable/CatalogTable.test.tsx | 10 +-- .../EntityLayout/EntityLayout.test.tsx | 8 +-- .../StarredEntities/Content.test.tsx | 29 ++------- .../StarredEntities.stories.tsx | 11 +--- .../src/templates/DefaultTemplate.stories.tsx | 6 +- plugins/scaffolder/dev/index.tsx | 16 ++--- .../components/DefaultTechDocsHome.test.tsx | 4 +- 16 files changed, 168 insertions(+), 105 deletions(-) create mode 100644 plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.test.ts create mode 100644 plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.ts diff --git a/.changeset/silver-boxes-flash.md b/.changeset/silver-boxes-flash.md index 3b860a06d6..9f30c1a34b 100644 --- a/.changeset/silver-boxes-flash.md +++ b/.changeset/silver-boxes-flash.md @@ -2,7 +2,7 @@ '@backstage/plugin-catalog-react': patch --- -**BREAKING**: Moved **DefaultStarredEntitiesApi** to `@backstage/plugin-catalog`. If you were using this in tests, you can add `@backstage/plugin-catalog` your packages `devDependencies` instead. +**BREAKING**: Moved **DefaultStarredEntitiesApi** to `@backstage/plugin-catalog`. If you were using this in tests, you can use the new `MockStarredEntitiesApi` from `@backstage/plugin-catalog-react` instead. Fixed a risky behavior where `DefaultStarredEntitiesApi` forwarded values to observers that were later mutated. diff --git a/packages/app/src/components/catalog/EntityPage.test.tsx b/packages/app/src/components/catalog/EntityPage.test.tsx index 4608dc7533..68ce5fb497 100644 --- a/packages/app/src/components/catalog/EntityPage.test.tsx +++ b/packages/app/src/components/catalog/EntityPage.test.tsx @@ -14,19 +14,16 @@ * limitations under the License. */ -import { - EntityLayout, - DefaultStarredEntitiesApi, -} from '@backstage/plugin-catalog'; +import { EntityLayout } from '@backstage/plugin-catalog'; import { EntityProvider, starredEntitiesApiRef, + MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import { githubActionsApiRef } from '@backstage/plugin-github-actions'; import { permissionApiRef } from '@backstage/plugin-permission-react'; import { MockPermissionApi, - MockStorageApi, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; @@ -61,12 +58,7 @@ describe('EntityPage Test', () => { diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index b8f0fa5538..3e1136313f 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -476,6 +476,14 @@ export const MockEntityListContextProvider: ({ value?: Partial> | undefined; }>) => JSX.Element; +// @public +export class MockStarredEntitiesApi implements StarredEntitiesApi { + // (undocumented) + starredEntitie$(): Observable>; + // (undocumented) + toggleStarred(entityRef: string): Promise; +} + // @public @deprecated (undocumented) export function reduceCatalogFilters( filters: EntityFilter[], diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.test.ts b/plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.test.ts new file mode 100644 index 0000000000..aadecefe98 --- /dev/null +++ b/plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.test.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { MockStarredEntitiesApi } from './MockStarredEntitiesApi'; + +describe('MockStarredEntitiesApi', () => { + it('should toggle starred entities', async () => { + const api = new MockStarredEntitiesApi(); + + const updates1 = new Array>(); + const sub1 = api + .starredEntitie$() + .subscribe(entities => updates1.push(entities)); + + api.toggleStarred('k:ns/e1'); + api.toggleStarred('k:ns/e2'); + + await Promise.resolve(); + expect(updates1).toEqual([ + new Set(), + new Set(['k:ns/e1']), + new Set(['k:ns/e1', 'k:ns/e2']), + ]); + + const updates2 = new Array>(); + const sub2 = api + .starredEntitie$() + .subscribe(entities => updates2.push(entities)); + + api.toggleStarred('k:ns/e2'); + sub1.unsubscribe(); + api.toggleStarred('k:ns/e2'); + + await Promise.resolve(); + expect(updates1).toEqual([ + new Set(), + new Set(['k:ns/e1']), + new Set(['k:ns/e1', 'k:ns/e2']), + new Set(['k:ns/e1']), + ]); + expect(updates2).toEqual([ + new Set(['k:ns/e1', 'k:ns/e2']), + new Set(['k:ns/e1']), + new Set(['k:ns/e1', 'k:ns/e2']), + ]); + sub2.unsubscribe(); + }); +}); diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.ts b/plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.ts new file mode 100644 index 0000000000..9467153dd9 --- /dev/null +++ b/plugins/catalog-react/src/apis/StarredEntitiesApi/MockStarredEntitiesApi.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { Observable } from '@backstage/types'; +import ObservableImpl from 'zen-observable'; +import { StarredEntitiesApi } from './StarredEntitiesApi'; + +/** + * An in-memory mock implementation of the StarredEntitiesApi. + * + * @public + */ +export class MockStarredEntitiesApi implements StarredEntitiesApi { + private readonly starredEntities = new Set(); + private readonly subscribers = new Set< + ZenObservable.SubscriptionObserver> + >(); + + private readonly observable = new ObservableImpl>(subscriber => { + subscriber.next(new Set(this.starredEntities)); + + this.subscribers.add(subscriber); + return () => { + this.subscribers.delete(subscriber); + }; + }); + + async toggleStarred(entityRef: string): Promise { + if (!this.starredEntities.delete(entityRef)) { + this.starredEntities.add(entityRef); + } + + for (const subscription of this.subscribers) { + subscription.next(new Set(this.starredEntities)); + } + } + + starredEntitie$(): Observable> { + return this.observable; + } +} diff --git a/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts b/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts index 94a221b36f..ba44c38e1d 100644 --- a/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts +++ b/plugins/catalog-react/src/apis/StarredEntitiesApi/index.ts @@ -16,3 +16,4 @@ export { starredEntitiesApiRef } from './StarredEntitiesApi'; export type { StarredEntitiesApi } from './StarredEntitiesApi'; +export { MockStarredEntitiesApi } from './MockStarredEntitiesApi'; diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index 5db9e2be9c..27fde81cc7 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -23,14 +23,13 @@ import { identityApiRef, storageApiRef, } from '@backstage/core-plugin-api'; -import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; import { act, renderHook } from '@testing-library/react-hooks'; import qs from 'qs'; import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router'; import { catalogApiRef } from '../api'; -import { starredEntitiesApiRef } from '../apis'; +import { starredEntitiesApiRef, MockStarredEntitiesApi } from '../apis'; import { EntityKindPicker, UserListPicker } from '../components'; import { EntityKindFilter, EntityTypeFilter, UserListFilter } from '../filters'; import { UserListFilterKind } from '../types'; @@ -96,12 +95,7 @@ const wrapper = ({ [catalogApiRef, mockCatalogApi], [identityApiRef, mockIdentityApi], [storageApiRef, MockStorageApi.create()], - [ - starredEntitiesApiRef, - new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), - }), - ], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], ]} > diff --git a/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx b/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx index 949ac6515b..16fa19a1cd 100644 --- a/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx +++ b/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx @@ -15,16 +15,18 @@ */ import { Entity } from '@backstage/catalog-model'; -import { StorageApi } from '@backstage/core-plugin-api'; -import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; -import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; +import { TestApiProvider } from '@backstage/test-utils'; import { act, renderHook } from '@testing-library/react-hooks'; import React, { PropsWithChildren } from 'react'; -import { starredEntitiesApiRef } from '../apis'; +import { + starredEntitiesApiRef, + StarredEntitiesApi, + MockStarredEntitiesApi, +} from '../apis'; import { useStarredEntities } from './useStarredEntities'; describe('useStarredEntities', () => { - let mockStorage: StorageApi; + let mockApi: StarredEntitiesApi; let wrapper: React.ComponentType; const mockEntity: Entity = { @@ -45,22 +47,15 @@ describe('useStarredEntities', () => { }; beforeEach(() => { - mockStorage = MockStorageApi.create(); + mockApi = new MockStarredEntitiesApi(); wrapper = ({ children }: PropsWithChildren<{}>) => ( - + {children} ); }); - it('should return an empty set for when there is no items in storage', async () => { + it('should return an empty set', async () => { const { result, waitForNextUpdate } = renderHook( () => useStarredEntities(), { wrapper }, @@ -71,10 +66,11 @@ describe('useStarredEntities', () => { expect(result.current.starredEntities.size).toBe(0); }); - it('should return a set with the current items when there are items in storage', async () => { + it('should return a set with the current items', async () => { const expectedIds = ['i', 'am', 'some', 'test', 'ids']; - const store = mockStorage?.forBucket('starredEntities'); - await store?.set('entityRefs', expectedIds); + for (const id of expectedIds) { + mockApi.toggleStarred(id); + } const { result, waitForNextUpdate } = renderHook( () => useStarredEntities(), diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index e36c1e9338..cf2eedb14c 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -31,6 +31,7 @@ import { catalogApiRef, entityRouteRef, starredEntitiesApiRef, + MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import { mockBreakpoint, @@ -42,7 +43,6 @@ import { import DashboardIcon from '@material-ui/icons/Dashboard'; import { fireEvent, screen } from '@testing-library/react'; import React from 'react'; -import { DefaultStarredEntitiesApi } from '../../apis'; import { createComponentRouteRef } from '../../routes'; import { CatalogTableRow } from '../CatalogTable'; import { DefaultCatalogPage } from './DefaultCatalogPage'; @@ -141,10 +141,7 @@ describe('DefaultCatalogPage', () => { [catalogApiRef, catalogApi], [identityApiRef, identityApi], [storageApiRef, storageApi], - [ - starredEntitiesApiRef, - new DefaultStarredEntitiesApi({ storageApi }), - ], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], ]} > {children} diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index 1d49638eed..cc05bbe2ae 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -25,15 +25,11 @@ import { MockEntityListContextProvider, starredEntitiesApiRef, UserListFilter, + MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; -import { - MockStorageApi, - renderInTestApp, - TestApiRegistry, -} from '@backstage/test-utils'; +import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { act, fireEvent } from '@testing-library/react'; import * as React from 'react'; -import { DefaultStarredEntitiesApi } from '../../apis'; import { CatalogTable } from './CatalogTable'; const entities: Entity[] = [ @@ -57,7 +53,7 @@ const entities: Entity[] = [ describe('CatalogTable component', () => { const mockApis = TestApiRegistry.from([ starredEntitiesApiRef, - new DefaultStarredEntitiesApi({ storageApi: MockStorageApi.create() }), + new MockStarredEntitiesApi(), ]); beforeEach(() => { diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index b29261c28b..c1deaf4b74 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -24,18 +24,17 @@ import { EntityProvider, entityRouteRef, starredEntitiesApiRef, + MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import { permissionApiRef } from '@backstage/plugin-permission-react'; import { MockPermissionApi, - MockStorageApi, renderInTestApp, TestApiRegistry, } from '@backstage/test-utils'; import { act, fireEvent } from '@testing-library/react'; import React from 'react'; import { Route, Routes } from 'react-router'; -import { DefaultStarredEntitiesApi } from '../../apis'; import { EntityLayout } from './EntityLayout'; const mockEntity = { @@ -48,10 +47,7 @@ const mockEntity = { const mockApis = TestApiRegistry.from( [catalogApiRef, {} as CatalogApi], [alertApiRef, {} as AlertApi], - [ - starredEntitiesApiRef, - new DefaultStarredEntitiesApi({ storageApi: MockStorageApi.create() }), - ], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], [permissionApiRef, new MockPermissionApi()], ); diff --git a/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx b/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx index ae4a84473f..9087ed3605 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/Content.test.tsx @@ -13,40 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - renderInTestApp, - TestApiProvider, - MockStorageApi, -} from '@backstage/test-utils'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { starredEntitiesApiRef, + MockStarredEntitiesApi, entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import React from 'react'; import { Content } from './Content'; describe('StarredEntitiesContent', () => { it('should render list of tools', async () => { - const mockStorageApi = MockStorageApi.create(); - await mockStorageApi - .forBucket('starredEntities') - .set('entityRefs', [ - 'component:default/mock-starred-entity', - 'component:default/mock-starred-entity-2', - ]); + const mockedApi = new MockStarredEntitiesApi(); + mockedApi.toggleStarred('component:default/mock-starred-entity'); + mockedApi.toggleStarred('component:default/mock-starred-entity-2'); const { getByText } = await renderInTestApp( - + , { diff --git a/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx b/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx index 55486a5dcd..315c0d0d16 100644 --- a/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx +++ b/plugins/home/src/homePageComponents/StarredEntities/StarredEntities.stories.tsx @@ -22,9 +22,9 @@ import { } from '@backstage/test-utils'; import { starredEntitiesApiRef, + MockStarredEntitiesApi, entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { Grid } from '@material-ui/core'; import React, { ComponentType } from 'react'; @@ -44,14 +44,7 @@ export default { (Story: ComponentType<{}>) => wrapInTestApp( , diff --git a/plugins/home/src/templates/DefaultTemplate.stories.tsx b/plugins/home/src/templates/DefaultTemplate.stories.tsx index 86d1b60022..5dc4ff61a0 100644 --- a/plugins/home/src/templates/DefaultTemplate.stories.tsx +++ b/plugins/home/src/templates/DefaultTemplate.stories.tsx @@ -25,9 +25,9 @@ import { wrapInTestApp, TestApiProvider, MockStorageApi} from '@backstage/test-u import { Content, Page, InfoCard } from '@backstage/core-components'; import { starredEntitiesApiRef, + MockStarredEntitiesApi, entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { HomePageSearchBar, SearchContextProvider, @@ -57,9 +57,7 @@ export default { apis={[ [ starredEntitiesApiRef, - new DefaultStarredEntitiesApi({ - storageApi: mockStorageApi, - }), + new MockStarredEntitiesApi(), ], [searchApiRef, { query: () => Promise.resolve({ results: [] }) }], ]} diff --git a/plugins/scaffolder/dev/index.tsx b/plugins/scaffolder/dev/index.tsx index 6ecc1a4564..03632f434d 100644 --- a/plugins/scaffolder/dev/index.tsx +++ b/plugins/scaffolder/dev/index.tsx @@ -20,19 +20,13 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { catalogApiRef, starredEntitiesApiRef, + MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { scaffolderApiRef, ScaffolderClient } from '../src'; import { ScaffolderPage } from '../src/plugin'; -import { - discoveryApiRef, - fetchApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; -import { - CatalogEntityPage, - DefaultStarredEntitiesApi, -} from '@backstage/plugin-catalog'; +import { discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api'; +import { CatalogEntityPage } from '@backstage/plugin-catalog'; createDevApp() .addPage({ @@ -46,8 +40,8 @@ createDevApp() }) .registerApi({ api: starredEntitiesApiRef, - deps: { storageApi: storageApiRef }, - factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), + deps: {}, + factory: () => new MockStarredEntitiesApi(), }) .registerApi({ api: scaffolderApiRef, diff --git a/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx b/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx index 678c737547..33f5e0a08a 100644 --- a/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx +++ b/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx @@ -20,11 +20,11 @@ import { configApiRef, storageApiRef, } from '@backstage/core-plugin-api'; -import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { CatalogApi, catalogApiRef, starredEntitiesApiRef, + MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import { MockStorageApi, @@ -73,7 +73,7 @@ describe('TechDocs Home', () => { [catalogApiRef, mockCatalogApi], [configApiRef, configApi], [storageApiRef, storageApi], - [starredEntitiesApiRef, new DefaultStarredEntitiesApi({ storageApi })], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], ); it('should render a TechDocs home page', async () => {