or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

app-wrappers.mdindex.mdmock-apis.mdmsw-integration.mdtest-api-provider.mdtesting-utilities.md
tile.json

app-wrappers.mddocs/

App Testing Wrappers

Complete Backstage app context for testing components with routing, theming, and API providers configured automatically. These utilities provide consistent test setup across Backstage plugin and app testing scenarios.

Capabilities

Render in Test App

Renders a component within a complete Backstage app context with async effects handling.

/**
 * Renders component in test app with full Backstage context and waits for async effects
 * @param Component - React component or element to render
 * @param options - Test app configuration options including legacy root support
 * @returns Promise resolving to React Testing Library render result
 */
function renderInTestApp(
  Component: ComponentType | ReactNode,
  options?: TestAppOptions & LegacyRootOption
): Promise<RenderResult>;

interface LegacyRootOption {
  legacyRoot?: boolean;
}

Usage Examples:

import { renderInTestApp } from "@backstage/test-utils";

// Basic usage with component
const { getByText } = await renderInTestApp(<MyPluginPage />);
expect(getByText('Plugin Content')).toBeInTheDocument();

// With routing configuration
const { getByRole } = await renderInTestApp(<MyComponent />, {
  routeEntries: ['/catalog/entity/default/component/my-service'],
  mountedRoutes: {
    '/catalog': catalogRouteRef,
  }
});

// With custom components
await renderInTestApp(<MyComponent />, {
  components: {
    NotFoundErrorPage: CustomNotFoundPage,
  }
});

Wrap in Test App

Wraps a component in a complete Backstage test app context without rendering.

/**
 * Wraps component in test app context without rendering
 * @param Component - React component or element to wrap
 * @param options - Test app configuration options
 * @returns React element wrapped in test app context
 */
function wrapInTestApp(
  Component: ComponentType | ReactNode, 
  options?: TestAppOptions
): ReactElement;

Usage Examples:

import { wrapInTestApp } from "@backstage/test-utils";
import { render } from "@testing-library/react";

// Wrap component for custom rendering
const WrappedComponent = wrapInTestApp(<MyComponent />);
const { container } = render(WrappedComponent);

// Use with React Testing Library's render
const { getByTestId } = render(
  wrapInTestApp(<MyPluginComponent />, {
    routeEntries: ['/my-plugin']
  })
);

Create Test App Wrapper

Creates a reusable wrapper component for consistent test app setup across multiple tests.

/**
 * Creates reusable wrapper component for Backstage test app
 * @param options - Test app configuration options
 * @returns Component wrapper function for testing
 */
function createTestAppWrapper(options?: TestAppOptions): ComponentWrapper;

type ComponentWrapper = (props: { children?: ReactNode }) => JSX.Element;

Usage Examples:

import { createTestAppWrapper } from "@backstage/test-utils";
import { renderHook } from "@testing-library/react";

// Create wrapper for hook testing
const wrapper = createTestAppWrapper({
  routeEntries: ['/catalog'],
  mountedRoutes: {
    '/catalog': catalogRouteRef
  }
});

// Use with renderHook
const { result } = renderHook(() => useEntity(), { wrapper });
expect(result.current.entity).toBeDefined();

// Use with multiple tests
describe('MyComponent', () => {
  const Wrapper = createTestAppWrapper({
    components: { NotFoundErrorPage: MockNotFound }
  });

  test('renders correctly', () => {
    render(<MyComponent />, { wrapper: Wrapper });
  });
});

Text Content Matcher

Creates a testing-library matcher function for finding elements by text content.

/**
 * Creates testing-library matcher for text content matching
 * @param text - Text to match against element content
 * @returns MatcherFunction for use with testing-library queries
 */
function textContentMatcher(text: string): MatcherFunction;

type MatcherFunction = (content: string, element: Element | null) => boolean;

Usage Examples:

import { textContentMatcher, renderInTestApp } from "@backstage/test-utils";

const { getByText } = await renderInTestApp(<MyComponent />);

// Match text content across multiple elements
const matcher = textContentMatcher('Total: $123.45');
expect(getByText(matcher)).toBeInTheDocument();

// Use with more complex text matching
const complexMatcher = textContentMatcher('Processing 5 of 10 items');
expect(getByText(complexMatcher)).toBeInTheDocument();

Configuration Options

Test App Options

Configuration interface for customizing the test app environment.

interface TestAppOptions {
  /** Initial router entries for React Router */
  routeEntries?: string[];
  
  /** Route mappings for mounted routes */
  mountedRoutes?: { [path: string]: RouteRef | ExternalRouteRef };
  
  /** Custom app components to override defaults */
  components?: Partial<AppComponents>;
  
  /** Custom icons with optional additional icon mappings */
  icons?: Partial<AppIcons> & { [key: string]: IconComponent };
}

interface AppComponents {
  NotFoundErrorPage: ComponentType<{}>;
  BootErrorPage: ComponentType<{ step: string; error: Error }>;
  Progress: ComponentType<{}>;
  Router: ComponentType<{ children: ReactNode }>;
  ErrorBoundaryFallback: ComponentType<{ error: Error; resetErrorBoundary: () => void }>;
  ThemeProvider: ComponentType<{ children: ReactNode }>;
}

interface AppIcons {
  'kind:api': IconComponent;
  'kind:component': IconComponent;
  'kind:domain': IconComponent;
  'kind:group': IconComponent;
  'kind:location': IconComponent;
  'kind:system': IconComponent;
  'kind:user': IconComponent;
  brokenImage: IconComponent;
  catalog: IconComponent;
  scaffolder: IconComponent;
  techdocs: IconComponent;
  search: IconComponent;
  chat: IconComponent;
  dashboard: IconComponent;
  docs: IconComponent;
  email: IconComponent;
  github: IconComponent;
  group: IconComponent;
  help: IconComponent;
  user: IconComponent;
  warning: IconComponent;
}

type IconComponent = ComponentType<{ fontSize?: 'inherit' | 'default' | 'small' | 'large' }>;

Configuration Examples:

// Route configuration
const routeOptions = {
  routeEntries: [
    '/catalog/default/component/my-service',
    '/docs/default/component/my-service'
  ],
  mountedRoutes: {
    '/catalog': catalogRouteRef,
    '/docs': docsRouteRef,
    '/api-docs': apiDocsRouteRef
  }
};

// Component customization
const componentOptions = {
  components: {
    NotFoundErrorPage: () => <div>Custom 404 Page</div>,
    Progress: () => <div>Loading...</div>
  }
};

// Icon customization
const iconOptions = {
  icons: {
    'kind:api': ApiIcon,
    'custom:database': DatabaseIcon,
    dashboard: CustomDashboardIcon
  }
};

// Combined configuration
await renderInTestApp(<MyComponent />, {
  ...routeOptions,
  ...componentOptions,
  ...iconOptions
});

Types

type ReactNode = React.ReactNode;
type ComponentType<P = {}> = React.ComponentType<P>;
type ReactElement = React.ReactElement;

interface RenderResult {
  container: HTMLElement;
  baseElement: HTMLElement;
  debug: (baseElement?: HTMLElement | DocumentFragment) => void;
  rerender: (ui: React.ReactElement) => void;
  unmount: () => boolean;
  asFragment: () => DocumentFragment;
  getByLabelText: (text: string | RegExp) => HTMLElement;
  getByText: (text: string | RegExp) => HTMLElement;
  getByRole: (role: string) => HTMLElement;
  getByTestId: (testId: string) => HTMLElement;
  // ... other React Testing Library query methods
}