From 0c7094940fb378e6a7247dd76478997398cbb179 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 12 Sep 2024 16:08:04 +0200 Subject: [PATCH] chore: make sure to load the api factories in reverse so that things are loaded in the correct order Signed-off-by: blam --- .changeset/ninety-brooms-fry.md | 5 ++ .../src/wiring/createSpecializedApp.test.tsx | 70 +++++++++++++++++++ .../src/wiring/createSpecializedApp.tsx | 2 +- 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 .changeset/ninety-brooms-fry.md diff --git a/.changeset/ninety-brooms-fry.md b/.changeset/ninety-brooms-fry.md new file mode 100644 index 0000000000..1d7f48ba81 --- /dev/null +++ b/.changeset/ninety-brooms-fry.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Reverse the order of API factory initialization in order to make sure that overrides from modules take priority diff --git a/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx b/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx index e98014f273..72594cefd1 100644 --- a/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx @@ -25,6 +25,7 @@ import { createExternalRouteRef, createExtensionInput, useRouteRef, + analyticsApiRef, } from '@backstage/frontend-plugin-api'; import { screen, render } from '@testing-library/react'; import { createSpecializedApp } from './createSpecializedApp'; @@ -167,6 +168,75 @@ describe('createSpecializedApp', () => { expect(screen.getByText('flags:test=a,test=b')).toBeInTheDocument(); }); + it('should intitialize the APIs in the correct order to allow for overrides', () => { + const mockAnalyticsApi = jest.fn(() => ({ captureEvent: jest.fn() })); + + const app = createSpecializedApp({ + features: [ + createFrontendPlugin({ + id: 'first', + extensions: [ + ApiBlueprint.make({ + params: { + factory: createApiFactory({ + api: analyticsApiRef, + deps: {}, + factory: () => { + throw new Error('BROKEN'); + }, + }), + }, + }), + ], + }), + createFrontendPlugin({ + id: 'test', + featureFlags: [{ name: 'a' }, { name: 'b' }], + extensions: [ + createExtension({ + attachTo: { id: 'root', input: 'app' }, + output: [coreExtensionData.reactElement], + factory: ({ apis }) => { + const Component = () => { + const analytics = apis.get(analyticsApiRef); + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions +
+ analytics!.captureEvent({ + action: 'asd', + subject: 'asd', + context: { extensionId: 'asd', pluginId: 'asd' }, + }) + } + > + Click me +
+ ); + }; + + return [coreExtensionData.reactElement()]; + }, + }), + ApiBlueprint.make({ + params: { + factory: createApiFactory({ + api: analyticsApiRef, + deps: {}, + factory: mockAnalyticsApi, + }), + }, + }), + ], + }), + ], + }); + + render(app.createRoot()); + + expect(mockAnalyticsApi).toHaveBeenCalled(); + }); + it('should make the app structure available through the AppTreeApi', async () => { let appTreeApi: AppTreeApi | undefined = undefined; diff --git a/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx b/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx index 612befc597..f79ed4510a 100644 --- a/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx +++ b/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx @@ -305,7 +305,7 @@ function createApiHolder(options: { }): ApiHolder { const factoryRegistry = new ApiFactoryRegistry(); - for (const factory of options.factories) { + for (const factory of options.factories.slice().reverse()) { factoryRegistry.register('default', factory); }