diff --git a/packages/core/src/api-wrappers/createApp.test.tsx b/packages/core/src/api-wrappers/createApp.test.tsx index 31f584b68c..7eaec32b86 100644 --- a/packages/core/src/api-wrappers/createApp.test.tsx +++ b/packages/core/src/api-wrappers/createApp.test.tsx @@ -14,7 +14,10 @@ * limitations under the License. */ -import { defaultConfigLoader } from './createApp'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router'; +import { defaultConfigLoader, OptionallyWrapInRouter } from './createApp'; (process as any).env = { NODE_ENV: 'test' }; const anyEnv = process.env as any; @@ -92,3 +95,23 @@ describe('defaultConfigLoader', () => { ]); }); }); + +describe('OptionallyWrapInRouter', () => { + it('should wrap with router if not yet inside a router', async () => { + const { getByText } = render( + Test, + ); + + expect(getByText('Test')).toBeInTheDocument(); + }); + + it('should not wrap with router if already inside a router', async () => { + const { getByText } = render( + + Test + , + ); + + expect(getByText('Test')).toBeInTheDocument(); + }); +}); diff --git a/packages/core/src/api-wrappers/createApp.tsx b/packages/core/src/api-wrappers/createApp.tsx index b071c2d014..e79cdf509f 100644 --- a/packages/core/src/api-wrappers/createApp.tsx +++ b/packages/core/src/api-wrappers/createApp.tsx @@ -14,14 +14,18 @@ * limitations under the License. */ -import React from 'react'; +import React, { PropsWithChildren } from 'react'; import privateExports, { AppOptions, defaultSystemIcons, BootErrorPageProps, AppConfigLoader, } from '@backstage/core-api'; -import { BrowserRouter, MemoryRouter } from 'react-router-dom'; +import { + BrowserRouter, + MemoryRouter, + useInRouterContext, +} from 'react-router-dom'; import LightIcon from '@material-ui/icons/WbSunny'; import DarkIcon from '@material-ui/icons/Brightness2'; import { ErrorPage } from '../layout/ErrorPage'; @@ -89,6 +93,13 @@ export const defaultConfigLoader: AppConfigLoader = async ( // The actual implementation of the app class still lives in core-api, // as it needs to be used by dev- and test-utils. +export function OptionallyWrapInRouter({ children }: PropsWithChildren<{}>) { + if (useInRouterContext()) { + return <>{children}; + } + return {children}; +} + /** * Creates a new Backstage App. */ @@ -97,32 +108,18 @@ export function createApp(options?: AppOptions) { ); const DefaultBootErrorPage = ({ step, error }: BootErrorPageProps) => { - switch (step) { - case 'load-config': - // TODO: figure out a nicer way to handle routing on the error page, when it can be done. - return ( - - - - ); - case 'load-chunk': - return ( - - ); - default: - // TODO: figure out a nicer way to handle routing on the error page, when it can be done. - return ( - - - - ); + let message = ''; + if (step === 'load-config') { + message = `The configuration failed to load, someone should have a look at this error: ${error.message}`; + } else if (step === 'load-chunk') { + message = `Lazy loaded chunk failed to load, try to reload the page: ${error.message}`; } + // TODO: figure out a nicer way to handle routing on the error page, when it can be done. + return ( + + + + ); }; const apis = options?.apis ?? [];