From b859092abf61e39f727e36323e266f2b146fb080 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Wed, 11 May 2022 11:59:46 +0200 Subject: [PATCH] Better document the TechDocsAddonTester Signed-off-by: Eric Peterson --- .../techdocs-addons-test-utils/api-report.md | 10 +--- .../src/test-utils.tsx | 55 +++++++++++++++++-- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/plugins/techdocs-addons-test-utils/api-report.md b/plugins/techdocs-addons-test-utils/api-report.md index 6374707b90..3808b65b84 100644 --- a/plugins/techdocs-addons-test-utils/api-report.md +++ b/plugins/techdocs-addons-test-utils/api-report.md @@ -10,31 +10,23 @@ import { screen as screen_2 } from 'testing-library__dom'; import { TechDocsEntityMetadata } from '@backstage/plugin-techdocs-react'; import { TechDocsMetadata } from '@backstage/plugin-techdocs-react'; -// @public (undocumented) +// @public export class TechDocsAddonTester { protected constructor(addons: ReactElement[]); - // (undocumented) atPath(path: string): this; - // (undocumented) build(): React_2.ReactElement< any, string | React_2.JSXElementConstructor >; - // (undocumented) static buildAddonsInTechDocs(addons: ReactElement[]): TechDocsAddonTester; - // (undocumented) renderWithEffects(): Promise< typeof screen_2 & { shadowRoot: ShadowRoot | null; } >; - // (undocumented) withApis(apis: TechdocsAddonTesterApis): this; - // (undocumented) withDom(dom: ReactElement): this; - // (undocumented) withEntity(entity: Partial): this; - // (undocumented) withMetadata(metadata: Partial): this; } ``` diff --git a/plugins/techdocs-addons-test-utils/src/test-utils.tsx b/plugins/techdocs-addons-test-utils/src/test-utils.tsx index 0bb46001f7..2c20199038 100644 --- a/plugins/techdocs-addons-test-utils/src/test-utils.tsx +++ b/plugins/techdocs-addons-test-utils/src/test-utils.tsx @@ -113,13 +113,27 @@ const defaultDom = ( ); /** + * Utility class for rendering TechDocs Addons end-to-end within the TechDocs + * reader page, with a set of givens (e.g. page DOM, metadata, etc). + * + * @example + * ```tsx + * const { getByText } = await TechDocsAddonTester.buildAddonsInTechDocs([]) + * .withDom(TEST_CONTENT) + * .renderWithEffects(); + * + * expect(getByText('TEST_CONTENT')).toBeInTheDocument(); + * ``` + * * @public */ - export class TechDocsAddonTester { private options: TechDocsAddonTesterOptions = defaultOptions; private addons: ReactElement[]; + /** + * Get a TechDocsAddonTester instance for a given set of Addons. + */ static buildAddonsInTechDocs(addons: ReactElement[]) { return new TechDocsAddonTester(addons); } @@ -129,6 +143,9 @@ export class TechDocsAddonTester { this.addons = addons; } + /** + * Provide mock API implementations if your Addon expects any. + */ withApis(apis: TechdocsAddonTesterApis) { const refs = apis.map(([ref]) => ref); this.options.apis = this.options.apis @@ -137,26 +154,44 @@ export class TechDocsAddonTester { return this; } + /** + * Provide mock HTML if your Addon expects it in the shadow DOM. + */ withDom(dom: ReactElement) { this.options.dom = dom; return this; } + /** + * Provide mock techdocs_metadata.json values if your Addon needs it. + */ withMetadata(metadata: Partial) { this.options.metadata = metadata; return this; } + /** + * Provide a mock entity if your Addon needs it. This also controls the base + * path at which the Addon is rendered. + */ withEntity(entity: Partial) { this.options.entity = entity; return this; } + /** + * Provide the TechDocs page path at which the Addon is rendered (e.g. the + * part of the path after the entity namespace/kind/name). + */ atPath(path: string) { this.options.path = path; return this; } + /** + * Return a fully configured and mocked TechDocs reader page within a test + * App instance, using the given Addon(s). + */ build() { const apis: TechdocsAddonTesterApis = [ [techdocsApiRef, techdocsApi], @@ -223,11 +258,19 @@ export class TechDocsAddonTester { }); } - // Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async - // act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit - // cleaner, since act doesn't return the result of the evaluated function. - // https://github.com/testing-library/react-testing-library/issues/281 - // https://github.com/facebook/react/pull/14853 + /** + * Render the Addon within a fully configured and mocked TechDocs reader. + * + * @remarks + * Components using useEffect to perform an asynchronous action (such as + * fetch) must be rendered within an async act call to properly get the final + * state, even with mocked responses. This utility method makes the signature + * a bit cleaner, since act doesn't return the result of the evaluated + * function. + * + * @see https://github.com/testing-library/react-testing-library/issues/281 + * @see https://github.com/facebook/react/pull/14853 + */ async renderWithEffects(): Promise< typeof screen & { shadowRoot: ShadowRoot | null } > {