From 59fabd510671b17017867ff16c4e850698a17fb6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 15 Nov 2023 12:24:01 +0100 Subject: [PATCH] frontend-test-utils: add createExtensionTester MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vincenzo Scamporlino Co-authored-by: Camila Belo Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- .changeset/angry-eagles-end.md | 5 + .changeset/bright-eyes-film.md | 5 + packages/frontend-test-utils/package.json | 9 +- .../src/app/createExtensionTester.ts | 117 ++++++++++++++++++ packages/frontend-test-utils/src/app/index.ts | 17 +++ packages/frontend-test-utils/src/index.ts | 2 +- yarn.lock | 5 + 7 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 .changeset/angry-eagles-end.md create mode 100644 .changeset/bright-eyes-film.md create mode 100644 packages/frontend-test-utils/src/app/createExtensionTester.ts create mode 100644 packages/frontend-test-utils/src/app/index.ts diff --git a/.changeset/angry-eagles-end.md b/.changeset/angry-eagles-end.md new file mode 100644 index 0000000000..eec1e7b710 --- /dev/null +++ b/.changeset/angry-eagles-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-test-utils': patch +--- + +Added `createExtensionTester` for rendering extensions in tests. diff --git a/.changeset/bright-eyes-film.md b/.changeset/bright-eyes-film.md new file mode 100644 index 0000000000..5c6211622a --- /dev/null +++ b/.changeset/bright-eyes-film.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-test-utils': minor +--- + +New testing utility library for `@backstage/frontend-app-api` and `@backstagr/frontend-plugin-api`. diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index c7ce21161e..064e996f82 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -28,5 +28,12 @@ }, "files": [ "dist" - ] + ], + "dependencies": { + "@backstage/frontend-app-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@backstage/types": "workspace:^", + "@testing-library/react": "^14.0.0" + } } diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.ts b/packages/frontend-test-utils/src/app/createExtensionTester.ts new file mode 100644 index 0000000000..211c7bb69a --- /dev/null +++ b/packages/frontend-test-utils/src/app/createExtensionTester.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createApp } from '@backstage/frontend-app-api'; +import { Extension, createPlugin } from '@backstage/frontend-plugin-api'; +import { MockConfigApi } from '@backstage/test-utils'; +import { JsonArray, JsonObject, JsonValue } from '@backstage/types'; +import { RenderResult, render, waitFor } from '@testing-library/react'; + +class ExtensionTester { + /** @internal */ + static forSubject( + subject: Extension, + options?: { config?: TConfig }, + ): ExtensionTester { + const tester = new ExtensionTester(); + tester.add(subject, options); + return tester; + } + + readonly #extensions = new Array<{ + extension: Extension; + config?: JsonValue; + }>(); + + add( + extension: Extension, + options?: { config?: TConfig }, + ): ExtensionTester { + this.#extensions.push({ + extension, + config: options?.config as JsonValue, + }); + + return this; + } + + async render(options?: { config?: JsonObject }): Promise { + const { config = {} } = options ?? {}; + + const [subject, ...rest] = this.#extensions; + if (!subject) { + throw new Error( + 'No subject found. At least one extension should be added to the tester.', + ); + } + + const extensionsConfig: JsonArray = [ + ...rest.map(entry => ({ + [entry.extension.id]: { + config: entry.config, + }, + })), + { + [subject.extension.id]: { + attachTo: { id: 'core', input: 'root' }, + config: subject.config, + disabled: false, + }, + }, + { + 'core.layout': false, + }, + { + 'core.nav': false, + }, + { + 'core.routes': false, + }, + ]; + + const finalConfig = { + ...config, + app: { + ...(typeof config.app === 'object' ? config.app : undefined), + extensions: extensionsConfig, + }, + }; + + const app = createApp({ + features: [ + createPlugin({ + id: 'test', + extensions: this.#extensions.map(entry => entry.extension), + }), + ], + configLoader: async () => new MockConfigApi(finalConfig), + }); + + const result = render(app.createRoot()); + await waitFor(() => + // eslint-disable-next-line jest/no-standalone-expect + expect(result.queryByText('Loading...')).not.toBeInTheDocument(), + ); + return result; + } +} + +export function createExtensionTester( + subject: Extension, + options?: { config?: TConfig }, +): ExtensionTester { + return ExtensionTester.forSubject(subject, options); +} diff --git a/packages/frontend-test-utils/src/app/index.ts b/packages/frontend-test-utils/src/app/index.ts new file mode 100644 index 0000000000..caefbfd697 --- /dev/null +++ b/packages/frontend-test-utils/src/app/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { createExtensionTester } from './createExtensionTester'; diff --git a/packages/frontend-test-utils/src/index.ts b/packages/frontend-test-utils/src/index.ts index aa70772592..6c49276721 100644 --- a/packages/frontend-test-utils/src/index.ts +++ b/packages/frontend-test-utils/src/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export {}; +export * from './app'; diff --git a/yarn.lock b/yarn.lock index a2f0d1b8fd..45a07bc83a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4350,7 +4350,12 @@ __metadata: resolution: "@backstage/frontend-test-utils@workspace:packages/frontend-test-utils" dependencies: "@backstage/cli": "workspace:^" + "@backstage/frontend-app-api": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/types": "workspace:^" "@testing-library/jest-dom": ^6.0.0 + "@testing-library/react": ^14.0.0 languageName: unknown linkType: soft