frontend-test-utils: adjust fetch mock + add createApiMock

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2026-02-09 17:21:24 +01:00
parent 3f19d5ec32
commit 7ee7f122a8
10 changed files with 255 additions and 224 deletions
@@ -17,3 +17,5 @@ renderInTestApp(<MyComponent />, {
apis: [mockApis.identity()],
});
```
This change also adds `createApiMock`, a public utility for creating mock API factories, intended for plugin authors to create their own `.mock()` variants.
@@ -124,28 +124,53 @@ renderTestApp({
});
```
### Creating your own mock APIs with `attachMockApiFactory`
### Creating your own mock APIs
If you maintain a plugin that exposes a utility API, you can use `attachMockApiFactory` to create mock instances that can be passed directly to test utilities:
If you maintain a plugin that exposes a utility API, you can provide mock utilities that follow the same function + `.mock()` pattern as the built-in `mockApis`.
Use `attachMockApiFactory` for fake instances with real behavior, and `createApiMock` for the jest-mocked `.mock()` variant where all methods are `jest.fn()`. The full pattern looks like this:
```ts
import { attachMockApiFactory } from '@backstage/frontend-test-utils';
import {
attachMockApiFactory,
createApiMock,
type ApiMock,
} from '@backstage/frontend-test-utils';
import { myApiRef, type MyApi } from '@internal/plugin-example-react';
// Fake instance with real behavior
export function myApiMock(options?: { greeting?: string }): MyApi {
const instance: MyApi = {
return attachMockApiFactory(myApiRef, {
greet: async () => options?.greeting ?? 'Hello!',
};
return attachMockApiFactory(myApiRef, instance);
});
}
// Jest mock variant where all methods are jest.fn()
export namespace myApiMock {
export const mock = createApiMock(myApiRef, () => ({
greet: jest.fn(),
}));
}
```
Consumers can then use it like the built-in mocks:
Consumers can then use it just like the core mocks:
```tsx
// Fake with real behavior
await renderInTestApp(<MyComponent />, {
apis: [myApiMock({ greeting: 'Hi there!' })],
});
// Jest mock for assertions
const api = myApiMock.mock({
greet: async () => 'mocked',
});
await renderInTestApp(<MyComponent />, {
apis: [api],
});
expect(api.greet).toHaveBeenCalledTimes(1);
```
## Available mock APIs
@@ -160,7 +185,7 @@ The table below lists all core APIs available through the `mockApis` namespace.
| `mockApis.discovery({ baseUrl })` | Inline | Returns `${baseUrl}/api/${pluginId}`, defaults to `http://example.com` |
| `mockApis.error(options?)` | `MockErrorApi` | Collects errors; has `getErrors()`, `waitForError()` |
| `mockApis.featureFlags(options?)` | `MockFeatureFlagsApi` | In-memory flag state; has `getState()`, `setState()`, `clearState()` |
| `mockApis.fetch(options?)` | `MockFetchApi` | Wraps `cross-fetch`; supports identity injection and plugin protocol |
| `mockApis.fetch(options?)` | `MockFetchApi` | Wraps native `fetch`; supports identity injection and plugin protocol |
| `mockApis.identity(options?)` | Inline | Configurable user ref, ownership, token, profile |
| `mockApis.permission(options?)` | `MockPermissionApi` | Defaults to `ALLOW`; accepts a handler function |
| `mockApis.storage({ data })` | `MockStorageApi` | In-memory storage with bucket support |
@@ -43,7 +43,6 @@
"@backstage/test-utils": "workspace:^",
"@backstage/types": "workspace:^",
"@backstage/version-bridge": "workspace:^",
"cross-fetch": "^4.0.0",
"i18next": "^22.4.15",
"zen-observable": "^0.10.0",
"zod": "^3.25.76"
+30 -150
View File
@@ -15,7 +15,6 @@ import { AuthorizeResult } from '@backstage/plugin-permission-common';
import { Config } from '@backstage/config';
import { ConfigApi } from '@backstage/core-plugin-api';
import { ConfigApi as ConfigApi_2 } from '@backstage/frontend-plugin-api';
import crossFetch from 'cross-fetch';
import { DiscoveryApi } from '@backstage/frontend-plugin-api';
import { DiscoveryApi as DiscoveryApi_2 } from '@backstage/core-plugin-api';
import { ErrorApi } from '@backstage/core-plugin-api';
@@ -55,7 +54,6 @@ import { withLogCollector } from '@backstage/test-utils';
// @public
export type ApiMock<TApi> = {
factory: ApiFactory<TApi, TApi, {}>;
[mockApiFactorySymbol]: ApiFactory<TApi, TApi, {}>;
} & {
[Key in keyof TApi]: TApi[Key] extends (...args: infer Args) => infer Return
@@ -71,6 +69,12 @@ export function attachMockApiFactory<TApi, TImpl extends TApi = TApi>(
[mockApiFactorySymbol]: ApiFactory<TApi, TApi, {}>;
};
// @public
export function createApiMock<TApi>(
apiRef: ApiRef<TApi>,
mockFactory: () => jest.Mocked<TApi>,
): (partialImpl?: Partial<TApi>) => ApiMock<TApi>;
// @public (undocumented)
export function createExtensionTester<
T extends ExtensionDefinitionParameters,
@@ -170,75 +174,23 @@ export namespace mockApis {
export function alert(): MockWithApiFactory<MockAlertApi>;
export namespace alert {
const mock: (
partialImpl?:
| Partial<{
post: jest.Mock<any, any, any>;
alert$: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
post: jest.Mock<any, any, any>;
alert$: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<AlertApi> | undefined,
) => ApiMock<AlertApi>;
}
export function analytics(): MockAnalyticsApi &
MockWithApiFactory<AnalyticsApi>;
export namespace analytics {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
captureEvent: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
captureEvent: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<AnalyticsApi> | undefined,
) => ApiMock<AnalyticsApi>;
}
export function config(options?: {
data?: JsonObject;
}): MockConfigApi & MockWithApiFactory<ConfigApi_2>;
export namespace config {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
has: jest.Mock<any, any, any>;
keys: jest.Mock<any, any, any>;
get: jest.Mock<any, any, any>;
getOptional: jest.Mock<any, any, any>;
getConfig: jest.Mock<any, any, any>;
getOptionalConfig: jest.Mock<any, any, any>;
getConfigArray: jest.Mock<any, any, any>;
getOptionalConfigArray: jest.Mock<any, any, any>;
getNumber: jest.Mock<any, any, any>;
getOptionalNumber: jest.Mock<any, any, any>;
getBoolean: jest.Mock<any, any, any>;
getOptionalBoolean: jest.Mock<any, any, any>;
getString: jest.Mock<any, any, any>;
getOptionalString: jest.Mock<any, any, any>;
getStringArray: jest.Mock<any, any, any>;
getOptionalStringArray: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
has: jest.Mock<any, any, any>;
keys: jest.Mock<any, any, any>;
get: jest.Mock<any, any, any>;
getOptional: jest.Mock<any, any, any>;
getConfig: jest.Mock<any, any, any>;
getOptionalConfig: jest.Mock<any, any, any>;
getConfigArray: jest.Mock<any, any, any>;
getOptionalConfigArray: jest.Mock<any, any, any>;
getNumber: jest.Mock<any, any, any>;
getOptionalNumber: jest.Mock<any, any, any>;
getBoolean: jest.Mock<any, any, any>;
getOptionalBoolean: jest.Mock<any, any, any>;
getString: jest.Mock<any, any, any>;
getOptionalString: jest.Mock<any, any, any>;
getStringArray: jest.Mock<any, any, any>;
getOptionalStringArray: jest.Mock<any, any, any>;
}>;
mock: (partialImpl?: Partial<Config> | undefined) => ApiMock<Config>;
}
export function discovery(options?: {
baseUrl?: string;
@@ -246,14 +198,8 @@ export namespace mockApis {
export namespace discovery {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
getBaseUrl: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
getBaseUrl: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<DiscoveryApi> | undefined,
) => ApiMock<DiscoveryApi>;
}
export function error(
options?: MockErrorApiOptions,
@@ -261,36 +207,16 @@ export namespace mockApis {
export namespace error {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
post: jest.Mock<any, any, any>;
error$: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
post: jest.Mock<any, any, any>;
error$: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<ErrorApi_2> | undefined,
) => ApiMock<ErrorApi_2>;
}
export function featureFlags(
options?: MockFeatureFlagsApiOptions,
): MockWithApiFactory<MockFeatureFlagsApi>;
export namespace featureFlags {
const mock: (
partialImpl?:
| Partial<{
registerFlag: jest.Mock<any, any, any>;
getRegisteredFlags: jest.Mock<any, any, any>;
isActive: jest.Mock<any, any, any>;
save: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
registerFlag: jest.Mock<any, any, any>;
getRegisteredFlags: jest.Mock<any, any, any>;
isActive: jest.Mock<any, any, any>;
save: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<FeatureFlagsApi> | undefined,
) => ApiMock<FeatureFlagsApi>;
}
export function fetch(
options?: MockFetchApiOptions,
@@ -298,14 +224,8 @@ export namespace mockApis {
export namespace fetch {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
fetch: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
fetch: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<FetchApi_2> | undefined,
) => ApiMock<FetchApi_2>;
}
export function identity(options?: {
userEntityRef?: string;
@@ -318,20 +238,8 @@ export namespace mockApis {
export namespace identity {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
getBackstageIdentity: jest.Mock<any, any, any>;
getCredentials: jest.Mock<any, any, any>;
getProfileInfo: jest.Mock<any, any, any>;
signOut: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
getBackstageIdentity: jest.Mock<any, any, any>;
getCredentials: jest.Mock<any, any, any>;
getProfileInfo: jest.Mock<any, any, any>;
signOut: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<IdentityApi> | undefined,
) => ApiMock<IdentityApi>;
}
export function permission(options?: {
authorize?:
@@ -344,14 +252,8 @@ export namespace mockApis {
export namespace permission {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
authorize: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
authorize: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<PermissionApi> | undefined,
) => ApiMock<PermissionApi>;
}
export function storage(options?: {
data?: JsonObject;
@@ -359,43 +261,21 @@ export namespace mockApis {
export namespace storage {
const // (undocumented)
mock: (
partialImpl?:
| Partial<{
forBucket: jest.Mock<any, any, any>;
snapshot: jest.Mock<any, any, any>;
set: jest.Mock<any, any, any>;
remove: jest.Mock<any, any, any>;
observe$: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
forBucket: jest.Mock<any, any, any>;
snapshot: jest.Mock<any, any, any>;
set: jest.Mock<any, any, any>;
remove: jest.Mock<any, any, any>;
observe$: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<StorageApi_2> | undefined,
) => ApiMock<StorageApi_2>;
}
export function translation(): MockTranslationApi &
MockWithApiFactory<TranslationApi_2>;
export namespace translation {
const mock: (
partialImpl?:
| Partial<{
getTranslation: jest.Mock<any, any, any>;
translation$: jest.Mock<any, any, any>;
}>
| undefined,
) => ApiMock<{
getTranslation: jest.Mock<any, any, any>;
translation$: jest.Mock<any, any, any>;
}>;
partialImpl?: Partial<TranslationApi_2> | undefined,
) => ApiMock<TranslationApi_2>;
}
}
// @public
export class MockConfigApi implements ConfigApi {
constructor(data: JsonObject);
constructor({ data }: { data: JsonObject });
get<T = JsonValue>(key?: string): T;
getBoolean(key: string): boolean;
getConfig(key: string): Config;
@@ -459,12 +339,12 @@ export interface MockFeatureFlagsApiOptions {
// @public
export class MockFetchApi implements FetchApi {
constructor(options?: MockFetchApiOptions);
get fetch(): typeof crossFetch;
get fetch(): typeof fetch;
}
// @public
export interface MockFetchApiOptions {
baseImplementation?: undefined | 'none' | typeof crossFetch;
baseImplementation?: undefined | 'none' | typeof fetch;
injectIdentityAuth?:
| undefined
| {
@@ -24,8 +24,6 @@ import {
FetchApi,
IdentityApi,
} from '@backstage/core-plugin-api';
import crossFetch, { Response } from 'cross-fetch';
/**
* The options given when constructing a {@link MockFetchApi}.
*
@@ -47,7 +45,7 @@ export interface MockFetchApiOptions {
* `jest.fn()`, if you want to use a custom implementation or to just track
* and assert on calls.
*/
baseImplementation?: undefined | 'none' | typeof crossFetch;
baseImplementation?: undefined | 'none' | typeof fetch;
/**
* Add translation from `plugin://` URLs to concrete http(s) URLs, basically
@@ -103,7 +101,7 @@ export class MockFetchApi implements FetchApi {
}
/** {@inheritdoc @backstage/core-plugin-api#FetchApi.fetch} */
get fetch(): typeof crossFetch {
get fetch(): typeof fetch {
return this.implementation.fetch;
}
}
@@ -124,7 +122,7 @@ function build(options?: MockFetchApiOptions): FetchApi {
function baseImplementation(
options: MockFetchApiOptions | undefined,
): typeof crossFetch {
): typeof fetch {
const implementation = options?.baseImplementation;
if (!implementation) {
// Return a wrapper that evaluates global.fetch at call time, not construction time.
@@ -0,0 +1,86 @@
/*
* Copyright 2025 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 { createApiRef } from '@backstage/frontend-plugin-api';
import { createApiMock } from './createApiMock';
import { getMockApiFactory } from './MockWithApiFactory';
describe('createApiMock', () => {
type TestApi = {
greet(name: string): string;
count: number;
};
const testApiRef = createApiRef<TestApi>({ id: 'test.create-mock' });
it('returns a factory function that produces jest mocks', () => {
const mock = createApiMock(testApiRef, () => ({
greet: jest.fn(),
count: 0 as any,
}));
const api = mock();
api.greet('world');
expect(api.greet).toHaveBeenCalledTimes(1);
expect(api.greet).toHaveBeenCalledWith('world');
});
it('applies partial implementations via mockImplementation', () => {
const mock = createApiMock(testApiRef, () => ({
greet: jest.fn(),
count: 0 as any,
}));
const api = mock({ greet: (name: string) => `Hello ${name}!` });
expect(api.greet('world')).toBe('Hello world!');
expect(api.greet).toHaveBeenCalledTimes(1);
});
it('preserves non-function partial values', () => {
const mock = createApiMock(testApiRef, () => ({
greet: jest.fn(),
count: 0 as any,
}));
const api = mock({ count: 42 });
expect(api.count).toBe(42);
});
it('attaches a mock API factory via the symbol', () => {
const mock = createApiMock(testApiRef, () => ({
greet: jest.fn(),
count: 0 as any,
}));
const api = mock();
const factory = getMockApiFactory(api);
expect(factory).toBeDefined();
expect(factory!.api).toBe(testApiRef);
});
it('creates fresh mocks on each call', () => {
const mock = createApiMock(testApiRef, () => ({
greet: jest.fn(),
count: 0 as any,
}));
const api1 = mock();
const api2 = mock();
api1.greet('a');
expect(api1.greet).toHaveBeenCalledTimes(1);
expect(api2.greet).toHaveBeenCalledTimes(0);
});
});
@@ -0,0 +1,87 @@
/*
* Copyright 2026 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 { ApiFactory, type ApiRef } from '@backstage/frontend-plugin-api';
import { mockApiFactorySymbol } from './MockWithApiFactory';
/**
* Represents a mocked version of an API, where you automatically have access to
* the mocked versions of all of its methods along with a factory that returns
* that same mock.
*
* @public
*/
export type ApiMock<TApi> = {
[mockApiFactorySymbol]: ApiFactory<TApi, TApi, {}>;
} & {
[Key in keyof TApi]: TApi[Key] extends (...args: infer Args) => infer Return
? TApi[Key] & jest.MockInstance<Return, Args>
: TApi[Key];
};
/**
* Creates a standardized Backstage Utility API mockfactory function for
* producing mock API instances.
*
* @remarks
*
* Each method in the mock factory is a `jest.fn()`, and you can optionally pass
* partial implementations when calling the returned function. No type
* parameters should be provided to this function, they will be inferred from
* the provided API reference.
*
* @public
* @example
* ```ts
* import { createApiMock } from '@backstage/frontend-test-utils';
* import { myApiRef } from '../apis';
*
* // Set up the mock factory
* const mock = createApiMock(myApiRef, () => ({
* greet: jest.fn(),
* }));
*
* // Create a mock with default behavior
* const api = mock();
*
* // Or with a partial implementation
* const api = mock({ greet: async () => 'Hello!' });
* expect(api.greet).toHaveBeenCalledTimes(1);
* ```
*/
export function createApiMock<TApi>(
apiRef: ApiRef<TApi>,
mockFactory: () => jest.Mocked<TApi>,
): (partialImpl?: Partial<TApi>) => ApiMock<TApi> {
return partialImpl => {
const mock = mockFactory();
if (partialImpl) {
for (const [key, impl] of Object.entries(partialImpl)) {
if (typeof impl === 'function') {
(mock as any)[key].mockImplementation(impl);
} else {
(mock as any)[key] = impl;
}
}
}
(mock as any)[mockApiFactorySymbol] = {
api: apiRef,
deps: {},
factory: () => mock,
};
return mock as unknown as ApiMock<TApi>;
};
}
@@ -14,7 +14,8 @@
* limitations under the License.
*/
export { type ApiMock, mockApis } from './mockApis';
export { mockApis } from './mockApis';
export { createApiMock, type ApiMock } from './createApiMock';
export {
type MockApiFactorySymbol,
type MockWithApiFactory,
@@ -18,7 +18,6 @@ import {
alertApiRef,
analyticsApiRef,
configApiRef,
createApiFactory,
discoveryApiRef,
errorApiRef,
fetchApiRef,
@@ -34,7 +33,6 @@ import {
type IdentityApi,
type StorageApi,
type TranslationApi,
ApiFactory,
} from '@backstage/frontend-plugin-api';
import {
permissionApiRef,
@@ -59,53 +57,9 @@ import { MockPermissionApi } from './PermissionApi';
import { MockTranslationApi } from './TranslationApi';
import {
mockWithApiFactory,
mockApiFactorySymbol,
type MockWithApiFactory,
} from './MockWithApiFactory';
/**
* Represents a mocked version of an API, where you automatically have access to
* the mocked versions of all of its methods along with a factory that returns
* that same mock.
*
* @public
*/
export type ApiMock<TApi> = {
factory: ApiFactory<TApi, TApi, {}>;
[mockApiFactorySymbol]: ApiFactory<TApi, TApi, {}>;
} & {
[Key in keyof TApi]: TApi[Key] extends (...args: infer Args) => infer Return
? TApi[Key] & jest.MockInstance<Return, Args>
: TApi[Key];
};
/** @internal */
function simpleMock<TApi>(
ref: any,
mockFactory: () => jest.Mocked<TApi>,
): (partialImpl?: Partial<TApi>) => ApiMock<TApi> {
return partialImpl => {
const mock = mockFactory();
if (partialImpl) {
for (const [key, impl] of Object.entries(partialImpl)) {
if (typeof impl === 'function') {
(mock as any)[key].mockImplementation(impl);
} else {
(mock as any)[key] = impl;
}
}
}
const factory = createApiFactory({
api: ref,
deps: {},
factory: () => mock,
});
const apiMock = Object.assign(mock, { factory }) as ApiMock<TApi>;
// Set the mock API symbol to the same factory
(apiMock as any)[mockApiFactorySymbol] = factory;
return apiMock;
};
}
import { createApiMock } from './createApiMock';
/**
* Mock implementations of the core utility APIs, to be used in tests.
@@ -172,7 +126,7 @@ export namespace mockApis {
*
* @public
*/
export const mock = simpleMock(alertApiRef, () => ({
export const mock = createApiMock(alertApiRef, () => ({
post: jest.fn(),
alert$: jest.fn(),
}));
@@ -215,7 +169,7 @@ export namespace mockApis {
*
* @public
*/
export const mock = simpleMock(featureFlagsApiRef, () => ({
export const mock = createApiMock(featureFlagsApiRef, () => ({
registerFlag: jest.fn(),
getRegisteredFlags: jest.fn(),
isActive: jest.fn(),
@@ -241,7 +195,7 @@ export namespace mockApis {
* @public
*/
export namespace analytics {
export const mock = simpleMock(analyticsApiRef, () => ({
export const mock = createApiMock(analyticsApiRef, () => ({
captureEvent: jest.fn(),
}));
}
@@ -273,7 +227,7 @@ export namespace mockApis {
*
* @public
*/
export const mock = simpleMock(translationApiRef, () => ({
export const mock = createApiMock(translationApiRef, () => ({
getTranslation: jest.fn(),
translation$: jest.fn(),
}));
@@ -298,7 +252,7 @@ export namespace mockApis {
* @public
*/
export namespace config {
export const mock = simpleMock(configApiRef, () => ({
export const mock = createApiMock(configApiRef, () => ({
has: jest.fn(),
keys: jest.fn(),
get: jest.fn(),
@@ -342,7 +296,7 @@ export namespace mockApis {
* @public
*/
export namespace discovery {
export const mock = simpleMock(discoveryApiRef, () => ({
export const mock = createApiMock(discoveryApiRef, () => ({
getBaseUrl: jest.fn(),
}));
}
@@ -390,7 +344,7 @@ export namespace mockApis {
* @public
*/
export namespace identity {
export const mock = simpleMock(identityApiRef, () => ({
export const mock = createApiMock(identityApiRef, () => ({
getBackstageIdentity: jest.fn(),
getCredentials: jest.fn(),
getProfileInfo: jest.fn(),
@@ -427,7 +381,7 @@ export namespace mockApis {
* @public
*/
export namespace permission {
export const mock = simpleMock(permissionApiRef, () => ({
export const mock = createApiMock(permissionApiRef, () => ({
authorize: jest.fn(),
}));
}
@@ -451,7 +405,7 @@ export namespace mockApis {
* @public
*/
export namespace storage {
export const mock = simpleMock(storageApiRef, () => ({
export const mock = createApiMock(storageApiRef, () => ({
forBucket: jest.fn(),
snapshot: jest.fn(),
set: jest.fn(),
@@ -479,7 +433,7 @@ export namespace mockApis {
* @public
*/
export namespace error {
export const mock = simpleMock(errorApiRef, () => ({
export const mock = createApiMock(errorApiRef, () => ({
post: jest.fn(),
error$: jest.fn(),
}));
@@ -504,7 +458,7 @@ export namespace mockApis {
* @public
*/
export namespace fetch {
export const mock = simpleMock(fetchApiRef, () => ({
export const mock = createApiMock(fetchApiRef, () => ({
fetch: jest.fn(),
}));
}
-1
View File
@@ -3966,7 +3966,6 @@ __metadata:
"@testing-library/jest-dom": "npm:^6.0.0"
"@types/react": "npm:^18.0.0"
"@types/zen-observable": "npm:^0.8.0"
cross-fetch: "npm:^4.0.0"
i18next: "npm:^22.4.15"
msw: "npm:^2.0.0"
react: "npm:^18.0.2"