test-utils: add TestApiRegistry
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -36,7 +36,7 @@ class ApiRegistryBuilder {
|
||||
* A registry for utility APIs.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Will be removed, use {@link @backstage/test-utils#TestApiProvider} instead.
|
||||
* @deprecated Will be removed, use {@link @backstage/test-utils#TestApiProvider} or {@link @backstage/test-utils#TestApiRegistry} instead.
|
||||
*/
|
||||
export class ApiRegistry implements ApiHolder {
|
||||
static builder() {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
```ts
|
||||
import { AnalyticsApi } from '@backstage/core-plugin-api';
|
||||
import { AnalyticsEvent } from '@backstage/core-plugin-api';
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { ErrorApi } from '@backstage/core-plugin-api';
|
||||
@@ -184,10 +185,19 @@ export const TestApiProvider: <T extends any[]>({
|
||||
|
||||
// @public
|
||||
export type TestApiProviderProps<TApiPairs extends any[]> = {
|
||||
apis: [...TestApiProviderPropsApiPairs<TApiPairs>];
|
||||
apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>];
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
// @public
|
||||
export class TestApiRegistry implements ApiHolder {
|
||||
// (undocumented)
|
||||
get<T>(api: ApiRef<T>): T | undefined;
|
||||
static with<TApiPairs extends any[]>(
|
||||
...apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>]
|
||||
): TestApiRegistry;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type TestAppOptions = {
|
||||
routeEntries?: string[];
|
||||
|
||||
@@ -18,8 +18,9 @@ import React, { ReactNode } from 'react';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { ApiRef, ApiHolder } from '@backstage/core-plugin-api';
|
||||
|
||||
/** @ignore */
|
||||
type TestApiProviderPropsApiPair<TApi> = TApi extends infer TImpl
|
||||
? [ApiRef<TApi>, Partial<TImpl>]
|
||||
? readonly [ApiRef<TApi>, Partial<TImpl>]
|
||||
: never;
|
||||
|
||||
/** @ignore */
|
||||
@@ -33,22 +34,58 @@ type TestApiProviderPropsApiPairs<TApiPairs> = {
|
||||
* @public
|
||||
*/
|
||||
export type TestApiProviderProps<TApiPairs extends any[]> = {
|
||||
apis: [...TestApiProviderPropsApiPairs<TApiPairs>];
|
||||
apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>];
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
class TestApiRegistry implements ApiHolder {
|
||||
constructor(private readonly apis: Map<string, unknown>) {}
|
||||
/**
|
||||
* The `TestApiRegistry` is an {@link @backstage/core-plugin-api#ApiHolder} implementation
|
||||
* that is particularly well suited for development and test environments such as
|
||||
* unit tests, storybooks, and isolated plugin development setups.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class TestApiRegistry implements ApiHolder {
|
||||
/**
|
||||
* Creates a new {@link TestApiRegistry} with a list of API implementation pairs.
|
||||
*
|
||||
* Similar to the {@link TestApiProvider}, there is no need to provide a full
|
||||
* implementation of each API, it's enough to implement the methods that are tested.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const apis = TestApiRegistry.with(
|
||||
* [configApiRef, new ConfigReader({})],
|
||||
* [identityApiRef, { getUserId: () => 'tester' }],
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
* @param apis - A list of pairs mapping an ApiRef to its respective implementation.
|
||||
*/
|
||||
static with<TApiPairs extends any[]>(
|
||||
...apis: readonly [...TestApiProviderPropsApiPairs<TApiPairs>]
|
||||
) {
|
||||
return new TestApiRegistry(
|
||||
new Map(apis.map(([api, impl]) => [api.id, impl])),
|
||||
);
|
||||
}
|
||||
|
||||
private constructor(private readonly apis: Map<string, unknown>) {}
|
||||
|
||||
/** {@inheritdoc @backstage/core-plugin-api#ApiHolder.get} */
|
||||
get<T>(api: ApiRef<T>): T | undefined {
|
||||
return this.apis.get(api.id) as T | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An API provider that lets you provide any number of API implementations in
|
||||
* a test, without necessarily having to implement the full APIs.
|
||||
* The `TestApiProvider` is a Utility API context provider that is particularly
|
||||
* well suited for development and test environments such as unit tests, storybooks,
|
||||
* and isolated plugin development setups.
|
||||
*
|
||||
* It lets you provide any number of API implementations, without necessarily
|
||||
* having to fully implement each of the APIs.
|
||||
*
|
||||
* A migration from `ApiRegistry` and `ApiProvider` might look like this, from:
|
||||
*
|
||||
@@ -84,11 +121,6 @@ export const TestApiProvider = <T extends any[]>({
|
||||
children,
|
||||
}: TestApiProviderProps<T>) => {
|
||||
return (
|
||||
<ApiProvider
|
||||
apis={
|
||||
new TestApiRegistry(new Map(apis.map(([api, impl]) => [api.id, impl])))
|
||||
}
|
||||
children={children}
|
||||
/>
|
||||
<ApiProvider apis={TestApiRegistry.with(...apis)} children={children} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -22,5 +22,5 @@ export * from './msw';
|
||||
export * from './Keyboard';
|
||||
export * from './logCollector';
|
||||
export * from './testingLibrary';
|
||||
export { TestApiProvider } from './TestApiProvider';
|
||||
export { TestApiProvider, TestApiRegistry } from './TestApiProvider';
|
||||
export type { TestApiProviderProps } from './TestApiProvider';
|
||||
|
||||
Reference in New Issue
Block a user