frontend-test-utils: shorthand mocks everywhere
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -49,7 +49,6 @@ import { RouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { StorageApi } from '@backstage/core-plugin-api';
|
||||
import { StorageApi as StorageApi_2 } from '@backstage/frontend-plugin-api';
|
||||
import { StorageValueSnapshot } from '@backstage/core-plugin-api';
|
||||
import { testingLibraryDomTypesQueries } from '@testing-library/dom/types/queries';
|
||||
import { TranslationApi } from '@backstage/core-plugin-api/alpha';
|
||||
import { TranslationApi as TranslationApi_2 } from '@backstage/frontend-plugin-api';
|
||||
import { TranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
@@ -551,8 +550,8 @@ export function renderInTestApp<TApiPairs extends any[] = any[]>(
|
||||
|
||||
// @public
|
||||
export function renderTestApp<TApiPairs extends any[] = any[]>(
|
||||
options: RenderTestAppOptions<TApiPairs>,
|
||||
): RenderResult<testingLibraryDomTypesQueries, HTMLElement, HTMLElement>;
|
||||
options?: RenderTestAppOptions<TApiPairs>,
|
||||
): RenderResult;
|
||||
|
||||
// @public
|
||||
export type RenderTestAppOptions<TApiPairs extends any[] = any[]> = {
|
||||
@@ -563,7 +562,9 @@ export type RenderTestAppOptions<TApiPairs extends any[] = any[]> = {
|
||||
mountedRoutes?: {
|
||||
[path: string]: RouteRef;
|
||||
};
|
||||
apis?: readonly [...TestApiPairs<TApiPairs>];
|
||||
apis?: readonly [
|
||||
...(TestApiProviderPropsApiPairs<TApiPairs> | MockWithApiFactory<any>[]),
|
||||
];
|
||||
};
|
||||
|
||||
// @public
|
||||
@@ -588,13 +589,8 @@ export type TestApiProviderProps<TApiPairs extends any[]> = {
|
||||
};
|
||||
|
||||
// @public
|
||||
export type TestApiProviderPropsApiPair<TApi> = TApi extends readonly [
|
||||
infer _Ref,
|
||||
infer _Impl,
|
||||
]
|
||||
? TApi
|
||||
: TApi extends infer TImpl
|
||||
? readonly [ApiRef<TApi>, Partial<TImpl>] | MockWithApiFactory<TApi>
|
||||
export type TestApiProviderPropsApiPair<TApi> = TApi extends infer TImpl
|
||||
? readonly [ApiRef<TApi>, Partial<TImpl>]
|
||||
: never;
|
||||
|
||||
// @public
|
||||
@@ -616,7 +612,9 @@ export type TestAppOptions<TApiPairs extends any[] = any[]> = {
|
||||
config?: JsonObject;
|
||||
features?: FrontendFeature[];
|
||||
initialRouteEntries?: string[];
|
||||
apis?: readonly [...TestApiPairs<TApiPairs>];
|
||||
apis?: readonly [
|
||||
...(TestApiProviderPropsApiPairs<TApiPairs> | MockWithApiFactory<any>[]),
|
||||
];
|
||||
};
|
||||
|
||||
export { withLogCollector };
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw';
|
||||
import { registerMswTestHooks } from '@backstage/test-utils';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { registerMswTestHooks } from '../../..';
|
||||
import { MockFetchApi } from './MockFetchApi';
|
||||
|
||||
describe('MockFetchApi', () => {
|
||||
@@ -25,8 +25,8 @@ describe('MockFetchApi', () => {
|
||||
|
||||
it('works with default constructor', async () => {
|
||||
worker.use(
|
||||
rest.get('http://example.com/data.json', (_, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json({ a: 'foo' })),
|
||||
http.get('http://example.com/data.json', () =>
|
||||
HttpResponse.json({ a: 'foo' }, { status: 200 }),
|
||||
),
|
||||
);
|
||||
const m = new MockFetchApi();
|
||||
|
||||
@@ -173,11 +173,11 @@ describe('createExtensionTester', () => {
|
||||
});
|
||||
|
||||
const tester = createExtensionTester(extension, {
|
||||
apis: [[analyticsApiRef, analyticsApiMock]],
|
||||
apis: [[analyticsApiRef, analyticsApiMock] as const],
|
||||
});
|
||||
|
||||
renderInTestApp(tester.reactElement(), {
|
||||
apis: [[analyticsApiRef, analyticsApiMock]],
|
||||
apis: [[analyticsApiRef, analyticsApiMock] as const],
|
||||
});
|
||||
|
||||
expect(screen.getByText('Test')).toBeInTheDocument();
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { screen, fireEvent } from '@testing-library/react';
|
||||
import {
|
||||
MockAnalyticsApi,
|
||||
TestApiProvider,
|
||||
} from '@backstage/frontend-test-utils';
|
||||
import { analyticsApiRef, useAnalytics } from '@backstage/frontend-plugin-api';
|
||||
import { mockApis, TestApiProvider } from '@backstage/frontend-test-utils';
|
||||
import { useAnalytics } from '@backstage/frontend-plugin-api';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import { renderInTestApp } from './renderInTestApp';
|
||||
|
||||
@@ -47,10 +44,10 @@ describe('renderInTestApp', () => {
|
||||
);
|
||||
};
|
||||
|
||||
const analyticsApiMock = new MockAnalyticsApi();
|
||||
const analyticsApiMock = mockApis.analytics();
|
||||
|
||||
renderInTestApp(
|
||||
<TestApiProvider apis={[[analyticsApiRef, analyticsApiMock]]}>
|
||||
<TestApiProvider apis={[analyticsApiMock]}>
|
||||
<IndexPage />
|
||||
</TestApiProvider>,
|
||||
);
|
||||
@@ -94,10 +91,10 @@ describe('renderInTestApp', () => {
|
||||
);
|
||||
};
|
||||
|
||||
const analyticsApiMock = new MockAnalyticsApi();
|
||||
const analyticsApiMock = mockApis.analytics();
|
||||
|
||||
renderInTestApp(<IndexPage />, {
|
||||
apis: [[analyticsApiRef, analyticsApiMock]],
|
||||
apis: [analyticsApiMock],
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Click me' }));
|
||||
|
||||
@@ -32,10 +32,12 @@ import {
|
||||
FrontendFeature,
|
||||
createFrontendModule,
|
||||
createApiFactory,
|
||||
type ApiRef,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { RouterBlueprint } from '@backstage/plugin-app-react';
|
||||
import appPlugin from '@backstage/plugin-app';
|
||||
import { type TestApiPairs } from '../utils';
|
||||
import { type TestApiProviderPropsApiPairs } from '../utils';
|
||||
import { getMockApiFactory, type MockWithApiFactory } from '../apis/utils';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import type { CreateSpecializedAppInternalOptions } from '../../../frontend-app-api/src/wiring/createSpecializedApp';
|
||||
|
||||
@@ -88,15 +90,16 @@ export type TestAppOptions<TApiPairs extends any[] = any[]> = {
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { identityApiRef } from '@backstage/frontend-plugin-api';
|
||||
* import { mockApis } from '@backstage/frontend-test-utils';
|
||||
*
|
||||
* renderInTestApp(<MyComponent />, {
|
||||
* apis: [[identityApiRef, mockApis.identity({ userEntityRef: 'user:default/guest' })]],
|
||||
* apis: [mockApis.identity({ userEntityRef: 'user:default/guest' })],
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
apis?: readonly [...TestApiPairs<TApiPairs>];
|
||||
apis?: readonly [
|
||||
...(TestApiProviderPropsApiPairs<TApiPairs> | MockWithApiFactory<any>[]),
|
||||
];
|
||||
};
|
||||
|
||||
const NavItem = (props: {
|
||||
@@ -241,9 +244,14 @@ export function renderInTestApp<TApiPairs extends any[] = any[]>(
|
||||
},
|
||||
]),
|
||||
__internal: options?.apis && {
|
||||
apiFactoryOverrides: options.apis.map(([apiRef, implementation]) =>
|
||||
createApiFactory(apiRef, implementation),
|
||||
),
|
||||
apiFactoryOverrides: options.apis.map(entry => {
|
||||
const mockFactory = getMockApiFactory(entry);
|
||||
if (mockFactory) {
|
||||
return mockFactory;
|
||||
}
|
||||
const [apiRef, implementation] = entry as readonly [ApiRef<any>, any];
|
||||
return createApiFactory(apiRef, implementation);
|
||||
}),
|
||||
},
|
||||
} as CreateSpecializedAppInternalOptions);
|
||||
|
||||
|
||||
@@ -25,14 +25,16 @@ import {
|
||||
ExtensionDefinition,
|
||||
FrontendFeature,
|
||||
RouteRef,
|
||||
type ApiRef,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, type RenderResult } from '@testing-library/react';
|
||||
import appPlugin from '@backstage/plugin-app';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RouterBlueprint } from '@backstage/plugin-app-react';
|
||||
import { type TestApiPairs } from '../utils';
|
||||
import { type TestApiProviderPropsApiPairs } from '../utils';
|
||||
import { getMockApiFactory, type MockWithApiFactory } from '../apis/utils';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import type { CreateSpecializedAppInternalOptions } from '../../../frontend-app-api/src/wiring/createSpecializedApp';
|
||||
|
||||
@@ -89,16 +91,17 @@ export type RenderTestAppOptions<TApiPairs extends any[] = any[]> = {
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { identityApiRef } from '@backstage/frontend-plugin-api';
|
||||
* import { mockApis } from '@backstage/frontend-test-utils';
|
||||
*
|
||||
* renderTestApp({
|
||||
* apis: [[identityApiRef, mockApis.identity({ userEntityRef: 'user:default/guest' })]],
|
||||
* apis: [mockApis.identity({ userEntityRef: 'user:default/guest' })],
|
||||
* extensions: [...],
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
apis?: readonly [...TestApiPairs<TApiPairs>];
|
||||
apis?: readonly [
|
||||
...(TestApiProviderPropsApiPairs<TApiPairs> | MockWithApiFactory<any>[]),
|
||||
];
|
||||
};
|
||||
|
||||
const appPluginOverride = appPlugin.withOverrides({
|
||||
@@ -116,11 +119,11 @@ const appPluginOverride = appPlugin.withOverrides({
|
||||
* @public
|
||||
*/
|
||||
export function renderTestApp<TApiPairs extends any[] = any[]>(
|
||||
options: RenderTestAppOptions<TApiPairs>,
|
||||
) {
|
||||
const extensions = [...(options.extensions ?? [])];
|
||||
options?: RenderTestAppOptions<TApiPairs>,
|
||||
): RenderResult {
|
||||
const extensions = [...(options?.extensions ?? [])];
|
||||
|
||||
if (options.mountedRoutes) {
|
||||
if (options?.mountedRoutes) {
|
||||
for (const [path, routeRef] of Object.entries(options.mountedRoutes)) {
|
||||
extensions.push(
|
||||
createExtension({
|
||||
@@ -150,7 +153,7 @@ export function renderTestApp<TApiPairs extends any[] = any[]>(
|
||||
params: {
|
||||
component: ({ children }) => (
|
||||
<MemoryRouter
|
||||
initialEntries={options.initialRouteEntries}
|
||||
initialEntries={options?.initialRouteEntries}
|
||||
future={{
|
||||
v7_relativeSplatPath: true,
|
||||
v7_startTransition: true,
|
||||
@@ -170,7 +173,7 @@ export function renderTestApp<TApiPairs extends any[] = any[]>(
|
||||
appPluginOverride,
|
||||
];
|
||||
|
||||
if (options.features) {
|
||||
if (options?.features) {
|
||||
features.push(...options.features);
|
||||
}
|
||||
|
||||
@@ -183,9 +186,14 @@ export function renderTestApp<TApiPairs extends any[] = any[]>(
|
||||
},
|
||||
]),
|
||||
__internal: options?.apis && {
|
||||
apiFactoryOverrides: options.apis.map(([apiRef, implementation]) =>
|
||||
createApiFactory(apiRef, implementation),
|
||||
),
|
||||
apiFactoryOverrides: options.apis.map(entry => {
|
||||
const mockFactory = getMockApiFactory(entry);
|
||||
if (mockFactory) {
|
||||
return mockFactory;
|
||||
}
|
||||
const [apiRef, implementation] = entry as readonly [ApiRef<any>, any];
|
||||
return createApiFactory(apiRef, implementation);
|
||||
}),
|
||||
},
|
||||
} as CreateSpecializedAppInternalOptions);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ export type TestApiPairs<TApiPairs> = TestApiProviderPropsApiPairs<TApiPairs>;
|
||||
/**
|
||||
* Type for entries that can be passed to TestApiProvider/TestApiRegistry.
|
||||
* Can be either a traditional [apiRef, implementation] tuple or a mock API instance
|
||||
* marked with the MockApiSymbol.
|
||||
* marked with the mockApiFactorySymbol.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user