From 7d06a4391679890f7ce7117f00a6735ccb77d723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 9 Oct 2024 13:53:08 +0200 Subject: [PATCH] implement storage too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/thin-chairs-ring.md | 1 + .../DismissableBanner.test.tsx | 22 +- packages/test-utils/report.api.md | 43 ++- .../apis/StorageApi/MockStorageApi.test.ts | 1 + .../apis/StorageApi/MockStorageApi.ts | 18 +- .../src/testUtils/apis/mockApis.test.tsx | 284 ++++++++++++++++++ .../test-utils/src/testUtils/apis/mockApis.ts | 22 ++ .../DefaultApiExplorerPage.test.tsx | 10 +- .../CookieAuthRefreshProvider.test.tsx | 11 +- .../FavoriteEntity/FavoriteEntity.test.tsx | 8 +- .../UserListPicker/UserListPicker.test.tsx | 11 +- .../src/hooks/useEntityListProvider.test.tsx | 12 +- .../DefaultStarredEntitiesApi.test.ts | 8 +- .../apis/StarredEntitiesApi/migration.test.ts | 6 +- .../CatalogPage/DefaultCatalogPage.test.tsx | 5 +- plugins/home/src/api/VisitsStorageApi.test.ts | 12 +- .../TemplateCard/CardHeader.test.tsx | 11 +- .../TemplateCard/TemplateCard.test.tsx | 23 +- .../TemplateListPage.test.tsx | 15 +- .../components/DefaultTechDocsHome.test.tsx | 24 +- .../Grids/EntityListDocsGrid.test.tsx | 22 +- 21 files changed, 437 insertions(+), 132 deletions(-) diff --git a/.changeset/thin-chairs-ring.md b/.changeset/thin-chairs-ring.md index dc3c7a0a25..5561b6f551 100644 --- a/.changeset/thin-chairs-ring.md +++ b/.changeset/thin-chairs-ring.md @@ -8,3 +8,4 @@ Added a `mockApis` export, which will replace the `MockX` API implementation cla - Deprecated `MockAnalyticsApi`, please use `mockApis.analytics` instead. - Deprecated `MockConfigApi`, please use `mockApis.config` instead. - Deprecated `MockPermissionApi`, please use `mockApis.permission` instead. +- Deprecated `MockStorageApi`, please use `mockApis.storage` instead. diff --git a/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx b/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx index 8d93186ccc..6f6da1231f 100644 --- a/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx +++ b/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx @@ -16,24 +16,18 @@ import React from 'react'; import { fireEvent } from '@testing-library/react'; -import { TestApiRegistry, renderInTestApp } from '@backstage/test-utils'; +import { + TestApiRegistry, + renderInTestApp, + mockApis, +} from '@backstage/test-utils'; import { DismissableBanner } from './DismissableBanner'; -import { ApiProvider, WebStorage } from '@backstage/core-app-api'; -import { storageApiRef, StorageApi } from '@backstage/core-plugin-api'; +import { ApiProvider } from '@backstage/core-app-api'; +import { storageApiRef } from '@backstage/core-plugin-api'; import { screen } from '@testing-library/react'; describe('', () => { - let apis: TestApiRegistry; - const mockErrorApi = { post: jest.fn(), error$: jest.fn() }; - const createWebStorage = (): StorageApi => { - return WebStorage.create({ - errorApi: mockErrorApi, - }); - }; - - beforeEach(() => { - apis = TestApiRegistry.from([storageApiRef, createWebStorage()]); - }); + const apis = TestApiRegistry.from([storageApiRef, mockApis.storage()]); it('renders the message and the popover', async () => { await renderInTestApp( diff --git a/packages/test-utils/report.api.md b/packages/test-utils/report.api.md index 4f29b2cdc1..0845218a33 100644 --- a/packages/test-utils/report.api.md +++ b/packages/test-utils/report.api.md @@ -174,6 +174,25 @@ export namespace mockApis { partialImpl?: Partial | undefined, ) => ApiMock; } + // (undocumented) + export function storage(options?: { + data?: JsonObject; + }): jest.Mocked; + // (undocumented) + export namespace storage { + const // (undocumented) + factory: ( + options?: + | { + data?: JsonObject | undefined; + } + | undefined, + ) => ApiFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ApiMock; + } } // @public @deprecated @@ -260,7 +279,9 @@ export class MockPermissionApi implements PermissionApi { ): Promise; } -// @public +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The reference is ambiguous because "storage" has more than one declaration; you need to add a TSDoc member reference selector +// +// @public @deprecated export class MockStorageApi implements StorageApi { // (undocumented) static create(data?: MockStorageBucket): MockStorageApi; @@ -278,7 +299,9 @@ export class MockStorageApi implements StorageApi { snapshot(key: string): StorageValueSnapshot; } -// @public +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The reference is ambiguous because "storage" has more than one declaration; you need to add a TSDoc member reference selector +// +// @public @deprecated export type MockStorageBucket = { [key: string]: any; }; @@ -384,12 +407,12 @@ export function wrapInTestApp( // src/testUtils/apis/ErrorApi/MockErrorApi.d.ts:33:5 - (ae-undocumented) Missing documentation for "getErrors". // src/testUtils/apis/ErrorApi/MockErrorApi.d.ts:34:5 - (ae-undocumented) Missing documentation for "waitForError". // src/testUtils/apis/PermissionApi/MockPermissionApi.d.ts:14:5 - (ae-undocumented) Missing documentation for "authorize". -// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:19:5 - (ae-undocumented) Missing documentation for "create". -// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:20:5 - (ae-undocumented) Missing documentation for "forBucket". -// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:21:5 - (ae-undocumented) Missing documentation for "snapshot". -// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:22:5 - (ae-undocumented) Missing documentation for "set". -// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:23:5 - (ae-undocumented) Missing documentation for "remove". -// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:24:5 - (ae-undocumented) Missing documentation for "observe$". +// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:21:5 - (ae-undocumented) Missing documentation for "create". +// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:22:5 - (ae-undocumented) Missing documentation for "forBucket". +// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:23:5 - (ae-undocumented) Missing documentation for "snapshot". +// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:24:5 - (ae-undocumented) Missing documentation for "set". +// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:25:5 - (ae-undocumented) Missing documentation for "remove". +// src/testUtils/apis/StorageApi/MockStorageApi.d.ts:26:5 - (ae-undocumented) Missing documentation for "observe$". // src/testUtils/apis/mockApis.d.ts:46:5 - (ae-undocumented) Missing documentation for "analytics". // src/testUtils/apis/mockApis.d.ts:47:5 - (ae-undocumented) Missing documentation for "analytics". // src/testUtils/apis/mockApis.d.ts:48:15 - (ae-undocumented) Missing documentation for "factory". @@ -402,4 +425,8 @@ export function wrapInTestApp( // src/testUtils/apis/mockApis.d.ts:122:5 - (ae-undocumented) Missing documentation for "permission". // src/testUtils/apis/mockApis.d.ts:123:15 - (ae-undocumented) Missing documentation for "factory". // src/testUtils/apis/mockApis.d.ts:126:15 - (ae-undocumented) Missing documentation for "mock". +// src/testUtils/apis/mockApis.d.ts:128:5 - (ae-undocumented) Missing documentation for "storage". +// src/testUtils/apis/mockApis.d.ts:131:5 - (ae-undocumented) Missing documentation for "storage". +// src/testUtils/apis/mockApis.d.ts:132:15 - (ae-undocumented) Missing documentation for "factory". +// src/testUtils/apis/mockApis.d.ts:135:15 - (ae-undocumented) Missing documentation for "mock". ``` diff --git a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts index 63aa4235e1..cdae96d5e4 100644 --- a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts +++ b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { StorageApi } from '@backstage/core-plugin-api'; import { MockStorageApi } from './MockStorageApi'; diff --git a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts index 30d523aed2..5ef3846bfa 100644 --- a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts +++ b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts @@ -20,12 +20,14 @@ import ObservableImpl from 'zen-observable'; /** * Type for map holding data in {@link MockStorageApi} + * @deprecated Use {@link mockApis.storage} instead * @public */ export type MockStorageBucket = { [key: string]: any }; /** * Mock implementation of the {@link core-plugin-api#StorageApi} to be used in tests + * @deprecated Use {@link mockApis.storage} instead * @public */ export class MockStorageApi implements StorageApi { @@ -44,7 +46,21 @@ export class MockStorageApi implements StorageApi { } static create(data?: MockStorageBucket) { - return new MockStorageApi('', new Map(), data); + // Translate a nested data object structure into a flat object with keys + // like `/a/b` with their corresponding leaf values + const keyValues: { [key: string]: any } = {}; + function put(value: { [key: string]: any }, namespace: string) { + for (const [key, val] of Object.entries(value)) { + if (typeof val === 'object' && val !== null) { + put(val, `${namespace}/${key}`); + } else { + const namespacedKey = `${namespace}/${key.replace(/^\//, '')}`; + keyValues[namespacedKey] = val; + } + } + } + put(data ?? {}, ''); + return new MockStorageApi('', new Map(), keyValues); } forBucket(name: string): StorageApi { diff --git a/packages/test-utils/src/testUtils/apis/mockApis.test.tsx b/packages/test-utils/src/testUtils/apis/mockApis.test.tsx index f64aae9901..87b9472377 100644 --- a/packages/test-utils/src/testUtils/apis/mockApis.test.tsx +++ b/packages/test-utils/src/testUtils/apis/mockApis.test.tsx @@ -255,4 +255,288 @@ describe('mockApis', () => { expect(notEmpty.authorize).toHaveBeenCalledTimes(2); }); }); + + describe('storage', () => { + describe('instance deep tests', () => { + it('should return undefined for values which are unset', async () => { + const storage = mockApis.storage(); + + expect(storage.snapshot('myfakekey').value).toBeUndefined(); + expect(storage.snapshot('myfakekey')).toEqual({ + key: 'myfakekey', + presence: 'absent', + value: undefined, + newValue: undefined, + }); + }); + + it('should allow the setting and snapshotting of the simple data structures', async () => { + const storage = mockApis.storage(); + + await storage.set('myfakekey', 'helloimastring'); + await storage.set('mysecondfakekey', 1234); + await storage.set('mythirdfakekey', true); + expect(storage.snapshot('myfakekey').value).toBe('helloimastring'); + expect(storage.snapshot('mysecondfakekey').value).toBe(1234); + expect(storage.snapshot('mythirdfakekey').value).toBe(true); + expect(storage.snapshot('myfakekey')).toEqual({ + key: 'myfakekey', + presence: 'present', + value: 'helloimastring', + }); + expect(storage.snapshot('mysecondfakekey')).toEqual({ + key: 'mysecondfakekey', + presence: 'present', + value: 1234, + }); + expect(storage.snapshot('mythirdfakekey')).toEqual({ + key: 'mythirdfakekey', + presence: 'present', + value: true, + }); + }); + + it('should allow setting of complex datastructures', async () => { + const storage = mockApis.storage(); + + const mockData = { + something: 'here', + is: [{ super: { complex: [{ but: 'something', why: true }] } }], + }; + + await storage.set('myfakekey', mockData); + + expect(storage.snapshot('myfakekey').value).toEqual(mockData); + expect(storage.snapshot('myfakekey')).toEqual({ + key: 'myfakekey', + presence: 'present', + value: mockData, + }); + }); + + it('should subscribe to key changes when setting a new value', async () => { + const storage = mockApis.storage(); + + const wrongKeyNextHandler = jest.fn(); + const selectedKeyNextHandler = jest.fn(); + const mockData = { hello: 'im a great new value' }; + + await new Promise(resolve => { + storage.observe$('correctKey').subscribe({ + next: (...args) => { + selectedKeyNextHandler(...args); + resolve(); + }, + }); + + storage.observe$('wrongKey').subscribe({ next: wrongKeyNextHandler }); + + storage.set('correctKey', mockData); + }); + + expect(wrongKeyNextHandler).not.toHaveBeenCalled(); + expect(selectedKeyNextHandler).toHaveBeenCalledTimes(1); + expect(selectedKeyNextHandler).toHaveBeenCalledWith({ + key: 'correctKey', + presence: 'present', + value: mockData, + }); + }); + + it('should subscribe to key changes when deleting a value', async () => { + const storage = mockApis.storage(); + + const wrongKeyNextHandler = jest.fn(); + const selectedKeyNextHandler = jest.fn(); + const mockData = { hello: 'im a great new value' }; + + storage.set('correctKey', mockData); + + await new Promise(resolve => { + storage.observe$('correctKey').subscribe({ + next: (...args) => { + selectedKeyNextHandler(...args); + resolve(); + }, + }); + + storage.observe$('wrongKey').subscribe({ next: wrongKeyNextHandler }); + + storage.remove('correctKey'); + }); + + expect(wrongKeyNextHandler).not.toHaveBeenCalled(); + expect(selectedKeyNextHandler).toHaveBeenCalledTimes(1); + expect(selectedKeyNextHandler).toHaveBeenCalledWith({ + key: 'correctKey', + presence: 'absent', + value: undefined, + newValue: undefined, + }); + }); + + it('should be able to create different buckets for different uses', async () => { + const rootStorage = mockApis.storage(); + + const firstStorage = rootStorage.forBucket('userSettings'); + const secondStorage = rootStorage.forBucket('profileSettings'); + const keyName = 'blobby'; + + await firstStorage.set(keyName, 'boop'); + await secondStorage.set(keyName, 'deerp'); + + expect(firstStorage.snapshot(keyName)).not.toBe( + secondStorage.snapshot(keyName), + ); + expect(firstStorage.snapshot(keyName).value).toBe('boop'); + expect(secondStorage.snapshot(keyName).value).toBe('deerp'); + expect(firstStorage.snapshot(keyName)).not.toEqual( + secondStorage.snapshot(keyName), + ); + expect(firstStorage.snapshot(keyName)).toEqual({ + key: keyName, + presence: 'present', + value: 'boop', + }); + expect(secondStorage.snapshot(keyName)).toEqual({ + key: keyName, + presence: 'present', + value: 'deerp', + }); + }); + + it('should not clash with other namespaces when creating buckets', async () => { + const rootStorage = mockApis.storage(); + + // when getting key test2 it will translate to /profile/something/deep/test2 + const firstStorage = rootStorage + .forBucket('profile') + .forBucket('something') + .forBucket('deep'); + // when getting key deep/test2 it will translate to /profile/something/deep/test2 + const secondStorage = rootStorage.forBucket('profile/something'); + + await firstStorage.set('test2', { error: true }); + + expect(secondStorage.snapshot('deep/test2').value).toBe(undefined); + expect(secondStorage.snapshot('deep/test2')).toMatchObject({ + presence: 'absent', + }); + }); + + it('should not reuse storage instances between different rootStorages', async () => { + const rootStorage1 = mockApis.storage(); + const rootStorage2 = mockApis.storage(); + + const firstStorage = rootStorage1.forBucket('something'); + const secondStorage = rootStorage2.forBucket('something'); + + await firstStorage.set('test2', true); + + expect(firstStorage.snapshot('test2').value).toBe(true); + expect(secondStorage.snapshot('test2').value).toBe(undefined); + expect(firstStorage.snapshot('test2')).toEqual({ + key: 'test2', + presence: 'present', + value: true, + }); + expect(secondStorage.snapshot('test2')).toEqual({ + key: 'test2', + presence: 'absent', + value: undefined, + }); + }); + + it('should freeze the snapshot value', async () => { + const storage = mockApis.storage(); + + const data = { foo: 'bar', baz: [{ foo: 'bar' }] }; + storage.set('foo', data); + + const snapshot = storage.snapshot('foo'); + expect(snapshot.value).not.toBe(data); + + if (snapshot.presence !== 'present') { + throw new Error('Invalid presence'); + } + + expect(() => { + snapshot.value.foo = 'buzz'; + }).toThrow(/Cannot assign to read only property/); + expect(() => { + snapshot.value.baz[0].foo = 'buzz'; + }).toThrow(/Cannot assign to read only property/); + expect(() => { + snapshot.value.baz.push({ foo: 'buzz' }); + }).toThrow(/Cannot add property 1, object is not extensible/); + }); + + it('should freeze observed values', async () => { + const storage = mockApis.storage(); + + const snapshotPromise = new Promise(resolve => { + storage.observe$('test').subscribe({ + next: resolve, + }); + }); + + storage.set('test', { + foo: { + bar: 'baz', + }, + }); + + const snapshot = await snapshotPromise; + expect(snapshot.presence).toBe('present'); + expect(() => { + snapshot.value!.foo.bar = 'qux'; + }).toThrow(/Cannot assign to read only property 'bar' of object/); + }); + + it('should JSON serialize stored values', async () => { + const storage = mockApis.storage(); + + storage.set('test', { + foo: { + toJSON() { + return { + bar: 'baz', + }; + }, + }, + }); + + expect(storage.snapshot('test')).toMatchObject({ + presence: 'present', + value: { + foo: { + bar: 'baz', + }, + }, + }); + }); + }); + + it('can create an instance and make assertions on it', () => { + const empty = mockApis.storage(); + expect(empty.snapshot('a')).toEqual({ key: 'a', presence: 'absent' }); + expect(empty.snapshot).toHaveBeenCalledTimes(1); + + const notEmpty = mockApis.storage({ data: { a: 1, b: { c: 2 } } }); + expect(notEmpty.snapshot('a')).toEqual({ + key: 'a', + presence: 'present', + value: 1, + }); + expect(notEmpty.forBucket('b').snapshot('c')).toEqual({ + key: 'c', + presence: 'present', + value: 2, + }); + expect(notEmpty.snapshot).toHaveBeenCalledTimes(1); // "inner" (forBucket returned) instances aren't mocked + expect(notEmpty.forBucket).toHaveBeenCalledTimes(1); + }); + + it('can create a mock and make assertions on it', () => {}); + }); }); diff --git a/packages/test-utils/src/testUtils/apis/mockApis.ts b/packages/test-utils/src/testUtils/apis/mockApis.ts index 7ed886d577..7a334c69b6 100644 --- a/packages/test-utils/src/testUtils/apis/mockApis.ts +++ b/packages/test-utils/src/testUtils/apis/mockApis.ts @@ -21,10 +21,12 @@ import { ApiRef, ConfigApi, IdentityApi, + StorageApi, analyticsApiRef, configApiRef, createApiFactory, identityApiRef, + storageApiRef, } from '@backstage/core-plugin-api'; import { AuthorizeResult, @@ -37,6 +39,7 @@ import { import { JsonObject } from '@backstage/types'; import { ApiMock } from './ApiMock'; import { MockPermissionApi } from './PermissionApi'; +import { MockStorageApi } from './StorageApi'; /** @internal */ function simpleFactory( @@ -268,4 +271,23 @@ export namespace mockApis { export const factory = simpleFactory(permissionApiRef, permission); export const mock = simpleMock(permissionApiRef, permissionMockSkeleton); } + + const storageMockSkeleton = (): jest.Mocked => ({ + forBucket: jest.fn(), + set: jest.fn(), + remove: jest.fn(), + observe$: jest.fn(), + snapshot: jest.fn(), + }); + export function storage(options?: { data?: JsonObject }) { + return simpleInstance( + storageApiRef, + MockStorageApi.create(options?.data), + storageMockSkeleton, + ); + } + export namespace storage { + export const factory = simpleFactory(storageApiRef, storage); + export const mock = simpleMock(storageApiRef, storageMockSkeleton); + } } diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx index 7847ac8336..34706e8136 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/core-app-api'; import { TableColumn, TableProps } from '@backstage/core-components'; import { configApiRef, storageApiRef } from '@backstage/core-plugin-api'; import { @@ -29,7 +28,6 @@ import { import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; import { mockApis, - MockStorageApi, TestApiProvider, renderInTestApp, } from '@backstage/test-utils'; @@ -72,17 +70,15 @@ describe('DefaultApiExplorerPage', () => { }), }); - const configApi = new ConfigReader({ - organization: { - name: 'My Company', - }, + const configApi = mockApis.config({ + data: { organization: { name: 'My Company' } }, }); const apiDocsConfig = { getApiDefinitionWidget: () => undefined, }; - const storageApi = MockStorageApi.create(); + const storageApi = mockApis.storage(); const renderWrapped = (children: React.ReactNode) => renderInTestApp( diff --git a/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx b/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx index bba876e6be..6ff9d8a1c5 100644 --- a/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx +++ b/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx @@ -19,7 +19,7 @@ import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { CookieAuthRefreshProvider } from './CookieAuthRefreshProvider'; import { - MockStorageApi, + mockApis, TestApiProvider, renderInTestApp, } from '@backstage/test-utils'; @@ -30,7 +30,6 @@ import { } from '@backstage/core-plugin-api'; describe('CookieAuthRefreshProvider', () => { - const storageApiMock = MockStorageApi.create(); const discoveryApiMock = { getBaseUrl: jest .fn() @@ -51,7 +50,7 @@ describe('CookieAuthRefreshProvider', () => { @@ -76,7 +75,7 @@ describe('CookieAuthRefreshProvider', () => { @@ -107,7 +106,7 @@ describe('CookieAuthRefreshProvider', () => { @@ -153,7 +152,7 @@ describe('CookieAuthRefreshProvider', () => { diff --git a/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.test.tsx b/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.test.tsx index d36700452a..ac06b3a34d 100644 --- a/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.test.tsx +++ b/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.test.tsx @@ -21,7 +21,7 @@ import { MockStarredEntitiesApi, starredEntitiesApiRef } from '../../apis'; import { FavoriteEntity } from './FavoriteEntity'; import { ComponentEntity } from '@backstage/catalog-model'; import { - MockStorageApi, + mockApis, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; @@ -41,14 +41,12 @@ const entity: ComponentEntity = { }, }; -const mockStorage = MockStorageApi.create(); - describe('', () => { it('should add to favorites', async () => { await renderInTestApp( @@ -79,7 +77,7 @@ describe('', () => { await renderInTestApp( diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx index 3f7c2034a0..7ff30dbf5f 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx @@ -34,7 +34,6 @@ import { } from '@backstage/catalog-client'; import { catalogApiRef } from '../../api'; import { - MockStorageApi, TestApiRegistry, mockApis, renderInTestApp, @@ -79,7 +78,7 @@ const apis = TestApiRegistry.from( [configApiRef, mockConfigApi], [catalogApiRef, mockCatalogApi], [identityApiRef, mockIdentityApi], - [storageApiRef, MockStorageApi.create()], + [storageApiRef, mockApis.storage()], [starredEntitiesApiRef, mockStarredEntitiesApi], ); @@ -134,19 +133,13 @@ describe('', () => { beforeEach(() => { mockCatalogApi.getEntityByRef?.mockResolvedValue(mockUser); - mockIdentityApi.getBackstageIdentity?.mockResolvedValue({ - ownershipEntityRefs, - type: 'user', - userEntityRef: 'user:default/testuser', - }); - mockCatalogApi.queryEntities?.mockImplementation( mockQueryEntitiesImplementation, ); }); afterEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); }); it('renders filter groups', async () => { diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index 067ca33fa3..4ef6b175ae 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -23,11 +23,7 @@ import { identityApiRef, storageApiRef, } from '@backstage/core-plugin-api'; -import { - MockStorageApi, - TestApiProvider, - mockApis, -} from '@backstage/test-utils'; +import { TestApiProvider, mockApis } from '@backstage/test-utils'; import { act, renderHook, waitFor } from '@testing-library/react'; import qs from 'qs'; import React, { PropsWithChildren } from 'react'; @@ -69,8 +65,6 @@ const entities: Entity[] = [ }, ]; -const mockConfigApi = mockApis.config(); - const ownershipEntityRefs = ['user:default/guest']; const mockIdentityApi = mockApis.identity({ @@ -104,10 +98,10 @@ const createWrapper = { describe('constructor', () => { it('should call migration', () => { const api = new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }); expect(performMigrationToTheNewBucket).toHaveBeenCalledTimes(1); expect(api).toBeDefined(); @@ -54,7 +54,7 @@ describe('DefaultStarredEntitiesApi', () => { it('should notify and toggle starred entities', async () => { const entityRef = 'component:default/mock'; - const storageApi = MockStorageApi.create(); + const storageApi = mockApis.storage(); const storageBucket = storageApi.forBucket('starredEntities'); const api = new DefaultStarredEntitiesApi({ storageApi }); @@ -85,7 +85,7 @@ describe('DefaultStarredEntitiesApi', () => { it('should read starred entities from storage', async () => { const entityRef = 'component:default/mock'; - const storageApi = MockStorageApi.create(); + const storageApi = mockApis.storage(); const storageBucket = storageApi.forBucket('starredEntities'); storageBucket.set('entityRefs', [entityRef]); const api = new DefaultStarredEntitiesApi({ storageApi }); diff --git a/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts b/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts index c9083969ee..9f99c6e2dd 100644 --- a/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts +++ b/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts @@ -15,18 +15,18 @@ */ import { StorageApi } from '@backstage/core-plugin-api'; -import { MockStorageApi } from '@backstage/test-utils'; +import { mockApis } from '@backstage/test-utils'; import { performMigrationToTheNewBucket } from './migration'; describe('performMigrationToTheNewBucket', () => { let mockStorage: StorageApi; beforeEach(() => { - mockStorage = MockStorageApi.create(); + mockStorage = mockApis.storage(); }); afterEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); }); it('should migrate', async () => { diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index 38310bbbf5..07cf98359e 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -26,7 +26,6 @@ import { } from '@backstage/plugin-catalog-react'; import { mockBreakpoint } from '@backstage/core-components/testUtils'; import { - MockStorageApi, TestApiProvider, mockApis, renderInTestApp, @@ -49,7 +48,6 @@ describe('DefaultCatalogPage', () => { }); afterEach(() => { window.history.replaceState = origReplaceState; - jest.clearAllMocks(); }); @@ -166,7 +164,6 @@ describe('DefaultCatalogPage', () => { ownershipEntityRefs: ['user:default/guest', 'group:default/tools'], displayName: 'Display Name', }); - const storageApi = MockStorageApi.create(); const renderWrapped = (children: React.ReactNode) => renderInTestApp( @@ -174,7 +171,7 @@ describe('DefaultCatalogPage', () => { apis={[ [catalogApiRef, catalogApi], [identityApiRef, identityApi], - [storageApiRef, storageApi], + [storageApiRef, mockApis.storage()], [starredEntitiesApiRef, new MockStarredEntitiesApi()], [permissionApiRef, mockApis.permission()], ]} diff --git a/plugins/home/src/api/VisitsStorageApi.test.ts b/plugins/home/src/api/VisitsStorageApi.test.ts index 206cf42689..55cf623149 100644 --- a/plugins/home/src/api/VisitsStorageApi.test.ts +++ b/plugins/home/src/api/VisitsStorageApi.test.ts @@ -15,7 +15,7 @@ */ import { VisitsStorageApi } from './VisitsStorageApi'; -import { MockStorageApi, mockApis } from '@backstage/test-utils'; +import { mockApis } from '@backstage/test-utils'; import { Visit, VisitsApi } from './VisitsApi'; describe('VisitsStorageApi.create', () => { @@ -42,7 +42,7 @@ describe('VisitsStorageApi.create', () => { it('instantiates', () => { const api = VisitsStorageApi.create({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), identityApi: mockIdentityApi, }); expect(api).toBeTruthy(); @@ -51,7 +51,7 @@ describe('VisitsStorageApi.create', () => { describe('.save()', () => { it('saves a visit', async () => { const api = VisitsStorageApi.create({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), identityApi: mockIdentityApi, }); const visit = { @@ -68,7 +68,7 @@ describe('VisitsStorageApi.create', () => { it('can control the number of stored entities', async () => { const api = VisitsStorageApi.create({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), identityApi: mockIdentityApi, limit: 2, }); @@ -102,7 +102,7 @@ describe('VisitsStorageApi.create', () => { it('correctly bumps the hits from a previous visit', async () => { const api = VisitsStorageApi.create({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), identityApi: mockIdentityApi, }); const visit = { @@ -144,7 +144,7 @@ describe('VisitsStorageApi.create', () => { beforeEach(() => { api = VisitsStorageApi.create({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), identityApi: mockIdentityApi, }); diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx index 58033b718c..9ae2a507dd 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React from 'react'; import { fireEvent } from '@testing-library/react'; import { CardHeader } from './CardHeader'; import { ThemeProvider } from '@material-ui/core/styles'; import { lightTheme } from '@backstage/theme'; import { - MockStorageApi, + mockApis, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; @@ -44,7 +45,7 @@ describe('CardHeader', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], ]} @@ -75,7 +76,7 @@ describe('CardHeader', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], ]} @@ -135,7 +136,7 @@ describe('CardHeader', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], ]} @@ -164,7 +165,7 @@ describe('CardHeader', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], ]} diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx index 5b2324b222..673f1e4a9e 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx @@ -21,7 +21,6 @@ import { } from '@backstage/plugin-catalog-react'; import { mockApis, - MockStorageApi, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; @@ -52,7 +51,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -82,7 +81,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -114,7 +113,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -144,7 +143,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -180,7 +179,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -220,7 +219,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -265,7 +264,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -314,7 +313,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -357,7 +356,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -397,7 +396,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -437,7 +436,7 @@ describe('TemplateCard', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [ diff --git a/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx index a02c90f687..01274cf6a6 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx @@ -22,7 +22,6 @@ import { import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; import { permissionApiRef } from '@backstage/plugin-permission-react'; import { - MockStorageApi, renderInTestApp, TestApiProvider, mockApis, @@ -53,7 +52,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -75,7 +74,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -98,7 +97,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -120,7 +119,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -143,7 +142,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -165,7 +164,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], @@ -186,7 +185,7 @@ describe('TemplateListPage', () => { [ starredEntitiesApiRef, new DefaultStarredEntitiesApi({ - storageApi: MockStorageApi.create(), + storageApi: mockApis.storage(), }), ], [permissionApiRef, mockApis.permission()], diff --git a/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx b/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx index 513a56265c..4c3be25325 100644 --- a/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx +++ b/plugins/techdocs/src/home/components/DefaultTechDocsHome.test.tsx @@ -14,22 +14,18 @@ * limitations under the License. */ -import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; -import { - ConfigApi, - configApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; +import { ApiProvider } from '@backstage/core-app-api'; +import { configApiRef, storageApiRef } from '@backstage/core-plugin-api'; import { + MockStarredEntitiesApi, catalogApiRef, starredEntitiesApiRef, - MockStarredEntitiesApi, } from '@backstage/plugin-catalog-react'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; import { - MockStorageApi, - renderInTestApp, TestApiRegistry, + mockApis, + renderInTestApp, } from '@backstage/test-utils'; import { screen } from '@testing-library/react'; import React from 'react'; @@ -50,18 +46,14 @@ const mockCatalogApi = catalogApiMock({ }); describe('TechDocs Home', () => { - const configApi: ConfigApi = new ConfigReader({ - organization: { - name: 'My Company', - }, + const configApi = mockApis.config({ + data: { organization: { name: 'My Company' } }, }); - const storageApi = MockStorageApi.create(); - const apiRegistry = TestApiRegistry.from( [catalogApiRef, mockCatalogApi], [configApiRef, configApi], - [storageApiRef, storageApi], + [storageApiRef, mockApis.storage()], [starredEntitiesApiRef, new MockStarredEntitiesApi()], ); diff --git a/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx b/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx index 947c81ae85..25471d0769 100644 --- a/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx +++ b/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx @@ -14,12 +14,8 @@ * limitations under the License. */ -import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; -import { - ConfigApi, - configApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; +import { ApiProvider } from '@backstage/core-app-api'; +import { configApiRef, storageApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef, starredEntitiesApiRef, @@ -30,9 +26,9 @@ import { catalogApiMock, } from '@backstage/plugin-catalog-react/testUtils'; import { - MockStorageApi, renderInTestApp, TestApiRegistry, + mockApis, } from '@backstage/test-utils'; import { screen } from '@testing-library/react'; import React from 'react'; @@ -68,21 +64,17 @@ const mockCatalogApi = catalogApiMock({ entities }); describe('Entity List Docs Grid', () => { beforeEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); }); - const configApi: ConfigApi = new ConfigReader({ - organization: { - name: 'My Company', - }, + const configApi = mockApis.config({ + data: { organization: { name: 'My Company' } }, }); - const storageApi = MockStorageApi.create(); - const apiRegistry = TestApiRegistry.from( [catalogApiRef, mockCatalogApi], [configApiRef, configApi], - [storageApiRef, storageApi], + [storageApiRef, mockApis.storage()], [starredEntitiesApiRef, new MockStarredEntitiesApi()], );