From 202e52c5e3617735304dfc09114c72f3f3bdd792 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 6 Sep 2023 16:05:02 +0200 Subject: [PATCH] backend-test-utils: implement support for feature module imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: Camila Belo Co-authored-by: Johan Haals Co-authored-by: Philipp Hugenroth Signed-off-by: Patrik Oldsberg --- .changeset/hungry-cherries-speak.md | 5 ++ packages/backend-test-utils/api-report.md | 8 +++- .../src/next/wiring/TestBackend.ts | 46 +++++++++++++++---- 3 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 .changeset/hungry-cherries-speak.md diff --git a/.changeset/hungry-cherries-speak.md b/.changeset/hungry-cherries-speak.md new file mode 100644 index 0000000000..bd67f61446 --- /dev/null +++ b/.changeset/hungry-cherries-speak.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Add support for installing backend features via module imports, for example `startTestBackend({ features: [import('my-plugin')] })`. diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 5831b093c5..43e671e440 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -246,7 +246,13 @@ export interface TestBackendOptions { }, ]; // (undocumented) - features?: Array BackendFeature)>; + features?: Array< + | BackendFeature + | (() => BackendFeature) + | Promise<{ + default: BackendFeature | (() => BackendFeature); + }> + >; } // @public diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 0b92ec3353..59b5906eb4 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -47,7 +47,11 @@ export interface TestBackendOptions { ]; }, ]; - features?: Array BackendFeature)>; + features?: Array< + | BackendFeature + | (() => BackendFeature) + | Promise<{ default: BackendFeature | (() => BackendFeature) }> + >; } /** @public */ @@ -78,11 +82,12 @@ export const defaultServiceFactories = [ ]; /** - * Given a set of extension points and plugins, find + * Given a set of extension points and features, find the extension + * points that we mock and tie them to the correct plugin ID. * @returns */ function createExtensionPointTestModules( - features: Array BackendFeature)>, + features: Array, extensionPointTuples?: readonly [ ref: ExtensionPoint, impl: unknown, @@ -92,12 +97,7 @@ function createExtensionPointTestModules( return []; } - const registrations = features.flatMap(featureOrFunction => { - const feature = - typeof featureOrFunction === 'function' - ? featureOrFunction() - : featureOrFunction; - + const registrations = features.flatMap(feature => { if (feature.$$type !== '@backstage/BackendFeature') { throw new Error( `Failed to add feature, invalid type '${feature.$$type}'`, @@ -172,13 +172,39 @@ function createExtensionPointTestModules( return modules; } +function isPromise(value: unknown | Promise): value is Promise { + return ( + typeof value === 'object' && + value !== null && + 'then' in value && + typeof value.then === 'function' + ); +} + +function unwrapFeature( + feature: BackendFeature | (() => BackendFeature), +): BackendFeature { + return typeof feature === 'function' ? feature() : feature; +} + const backendInstancesToCleanUp = new Array(); /** @public */ export async function startTestBackend( options: TestBackendOptions, ): Promise { - const { extensionPoints, features = [], ...otherOptions } = options; + const { extensionPoints, ...otherOptions } = options; + + // Unpack input into awaited plain BackendFeatures + const features: BackendFeature[] = await Promise.all( + options.features?.map(async val => { + if (isPromise(val)) { + const { default: feature } = await val; + return unwrapFeature(feature); + } + return unwrapFeature(val); + }) ?? [], + ); let server: ExtendedHttpServer;