diff --git a/.changeset/render-test-app-mounted-routes.md b/.changeset/render-test-app-mounted-routes.md
new file mode 100644
index 0000000000..bffaff3c83
--- /dev/null
+++ b/.changeset/render-test-app-mounted-routes.md
@@ -0,0 +1,14 @@
+---
+'@backstage/frontend-test-utils': patch
+---
+
+Added `mountedRoutes` option to `renderTestApp` for binding route refs to paths, matching the existing option in `renderInTestApp`:
+
+```typescript
+renderTestApp({
+ extensions: [...],
+ mountedRoutes: {
+ '/my-path': myRouteRef,
+ },
+});
+```
diff --git a/docs/frontend-system/building-plugins/02-testing.md b/docs/frontend-system/building-plugins/02-testing.md
index 550434f373..941744c13e 100644
--- a/docs/frontend-system/building-plugins/02-testing.md
+++ b/docs/frontend-system/building-plugins/02-testing.md
@@ -202,6 +202,47 @@ describe('Index page', () => {
That's all for testing features!
+## Mounting routes
+
+If your component or extension uses `useRouteRef` to generate links to other routes, you need to mount those routes in the test environment. Both `renderInTestApp` and `renderTestApp` support the `mountedRoutes` option for this purpose.
+
+For example, given a component that uses `useRouteRef` to create a link:
+
+```tsx
+import { useRouteRef } from '@backstage/frontend-plugin-api';
+import { detailsRouteRef } from './routes';
+
+export const MyComponent = () => {
+ const detailsLink = useRouteRef(detailsRouteRef);
+
+ return View details;
+};
+```
+
+You can test it by mounting the route ref to a path using the `mountedRoutes` option:
+
+```tsx
+import { screen } from '@testing-library/react';
+import { renderInTestApp } from '@backstage/frontend-test-utils';
+import { detailsRouteRef } from './routes';
+import { MyComponent } from './MyComponent';
+
+describe('MyComponent', () => {
+ it('should render a link to the plugin page', async () => {
+ await renderInTestApp(, {
+ mountedRoutes: {
+ '/my-plugin/details': detailsRouteRef,
+ },
+ });
+
+ expect(await screen.findByText('View details')).toHaveAttribute(
+ 'href',
+ '/my-plugin/details',
+ );
+ });
+});
+```
+
## Missing something?
If there's anything else you think needs to be covered in the docs or that you think isn't covered by the test utilities, please create an issue in the Backstage repository. You are always welcome to contribute as well!
diff --git a/packages/frontend-test-utils/report.api.md b/packages/frontend-test-utils/report.api.md
index fa57b76e82..fce8c61d68 100644
--- a/packages/frontend-test-utils/report.api.md
+++ b/packages/frontend-test-utils/report.api.md
@@ -136,6 +136,9 @@ export type RenderTestAppOptions = {
extensions?: ExtensionDefinition[];
features?: FrontendFeature[];
initialRouteEntries?: string[];
+ mountedRoutes?: {
+ [path: string]: RouteRef;
+ };
apis?: readonly [...TestApiPairs];
};
diff --git a/packages/frontend-test-utils/src/app/renderTestApp.tsx b/packages/frontend-test-utils/src/app/renderTestApp.tsx
index 30ee6ff761..b83ae7832a 100644
--- a/packages/frontend-test-utils/src/app/renderTestApp.tsx
+++ b/packages/frontend-test-utils/src/app/renderTestApp.tsx
@@ -14,14 +14,17 @@
* limitations under the License.
*/
+import { Fragment } from 'react';
import { createSpecializedApp } from '@backstage/frontend-app-api';
import {
coreExtensionData,
createApiFactory,
+ createExtension,
createFrontendModule,
createFrontendPlugin,
ExtensionDefinition,
FrontendFeature,
+ RouteRef,
} from '@backstage/frontend-plugin-api';
import { render } from '@testing-library/react';
import appPlugin from '@backstage/plugin-app';
@@ -63,6 +66,23 @@ export type RenderTestAppOptions = {
*/
initialRouteEntries?: string[];
+ /**
+ * An object of paths to mount route refs on, with the key being the path and
+ * the value being the RouteRef that the path will be bound to. This allows
+ * the route refs to be used by `useRouteRef` in the rendered elements.
+ *
+ * @example
+ * ```ts
+ * renderTestApp({
+ * mountedRoutes: {
+ * '/my-path': myRouteRef,
+ * },
+ * extensions: [...],
+ * })
+ * ```
+ */
+ mountedRoutes?: { [path: string]: RouteRef };
+
/**
* API overrides to provide to the test app. Use `mockApis` helpers
* from `@backstage/frontend-test-utils` to create mock implementations.
@@ -100,6 +120,28 @@ export function renderTestApp(
) {
const extensions = [...(options.extensions ?? [])];
+ if (options.mountedRoutes) {
+ for (const [path, routeRef] of Object.entries(options.mountedRoutes)) {
+ extensions.push(
+ createExtension({
+ kind: 'test-route',
+ name: path,
+ attachTo: { id: 'app/routes', input: 'routes' },
+ output: [
+ coreExtensionData.reactElement,
+ coreExtensionData.routePath,
+ coreExtensionData.routeRef,
+ ],
+ factory: () => [
+ coreExtensionData.reactElement(),
+ coreExtensionData.routePath(path),
+ coreExtensionData.routeRef(routeRef),
+ ],
+ }),
+ );
+ }
+ }
+
const features: FrontendFeature[] = [
createFrontendModule({
pluginId: 'app',