chore: fix some tests

Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Johan Haals <johan.haals@gmail.com>
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2024-08-26 15:06:16 +02:00
parent 7e9af96f7c
commit f66f603ef5
13 changed files with 109 additions and 98 deletions
-1
View File
@@ -45,7 +45,6 @@
"@backstage/frontend-app-api": "workspace:^",
"@backstage/integration-react": "workspace:^",
"@backstage/plugin-api-docs": "workspace:^",
"@backstage/plugin-app": "^0.0.0",
"@backstage/plugin-auth-react": "workspace:^",
"@backstage/plugin-catalog": "workspace:^",
"@backstage/plugin-catalog-common": "workspace:^",
-2
View File
@@ -82,7 +82,6 @@ import { customDevToolsPage } from './components/devtools/CustomDevToolsPage';
import { DevToolsPage } from '@backstage/plugin-devtools';
import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities';
import { NotificationsPage } from '@backstage/plugin-notifications';
import { AppPage } from '@backstage/plugin-app';
const app = createApp({
apis,
@@ -209,7 +208,6 @@ const routes = (
{customDevToolsPage}
</Route>
<Route path="/notifications" element={<NotificationsPage />} />
<Route path="/app" element={<AppPage />} />
</FlatRoutes>
);
+1
View File
@@ -48,6 +48,7 @@
},
"devDependencies": {
"@backstage/cli": "workspace:^",
"@backstage/plugin-app": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^15.0.0"
@@ -29,12 +29,15 @@ import {
createRouteRef,
} from '@backstage/frontend-plugin-api';
import { MockConfigApi, TestApiRegistry } from '@backstage/test-utils';
import appPlugin from '@backstage/plugin-app';
import { builtinExtensions } from '../wiring/createApp';
import { readAppExtensionsConfig } from '../tree/readAppExtensionsConfig';
import { resolveAppNodeSpecs } from '../tree/resolveAppNodeSpecs';
import { resolveAppTree } from '../tree/resolveAppTree';
import { instantiateAppNodeTree } from '../tree/instantiateAppNodeTree';
import { Root } from '../extensions/Root';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';
const ref1 = createRouteRef();
const ref2 = createRouteRef();
@@ -83,12 +86,12 @@ function routeInfoFromExtensions(extensions: ExtensionDefinition[]) {
});
const tree = resolveAppTree(
'app',
'root',
resolveAppNodeSpecs({
features: [plugin],
builtinExtensions,
features: [appPlugin, plugin],
builtinExtensions: [resolveExtensionDefinition(Root)],
parameters: readAppExtensionsConfig(new MockConfigApi({})),
forbidden: new Set(['app']),
forbidden: new Set(['root']),
}),
);
@@ -29,6 +29,7 @@ import { CreateAppFeatureLoader, createApp } from './createApp';
import { MockConfigApi, renderWithEffects } from '@backstage/test-utils';
import React from 'react';
import { featureFlagsApiRef, useApi } from '@backstage/core-plugin-api';
import appPlugin from '@backstage/plugin-app';
describe('createApp', () => {
it('should allow themes to be installed', async () => {
@@ -44,6 +45,7 @@ describe('createApp', () => {
}),
}),
features: [
appPlugin,
createFrontendPlugin({
id: 'test',
extensions: [
@@ -73,6 +75,7 @@ describe('createApp', () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
features: [
appPlugin,
createFrontendPlugin({
id: duplicatedFeatureId,
extensions: [
@@ -136,7 +139,7 @@ describe('createApp', () => {
configLoader: async () => ({
config: new MockConfigApi({ key: 'config-value' }),
}),
features: [loader],
features: [appPlugin, loader],
});
await renderWithEffects(app.createRoot());
@@ -174,6 +177,7 @@ describe('createApp', () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
features: [
appPlugin,
createFrontendPlugin({
id: 'test',
featureFlags: [{ name: 'test-1' }],
@@ -229,6 +233,7 @@ describe('createApp', () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
features: [
appPlugin,
createFrontendPlugin({
id: 'my-plugin',
extensions: [
@@ -255,13 +260,53 @@ describe('createApp', () => {
const { tree } = appTreeApi!.getTree();
expect(String(tree.root)).toMatchInlineSnapshot(`
"<root>
"<root out=[core.reactElement]>
apis [
<api:app/discovery out=[core.api.factory] />
<api:app/alert out=[core.api.factory] />
<api:app/analytics out=[core.api.factory] />
<api:app/error out=[core.api.factory] />
<api:app/storage out=[core.api.factory] />
<api:app/fetch out=[core.api.factory] />
<api:app/oauth-request out=[core.api.factory] />
<api:app/google-auth out=[core.api.factory] />
<api:app/microsoft-auth out=[core.api.factory] />
<api:app/github-auth out=[core.api.factory] />
<api:app/okta-auth out=[core.api.factory] />
<api:app/gitlab-auth out=[core.api.factory] />
<api:app/onelogin-auth out=[core.api.factory] />
<api:app/bitbucket-auth out=[core.api.factory] />
<api:app/bitbucket-server-auth out=[core.api.factory] />
<api:app/atlassian-auth out=[core.api.factory] />
<api:app/vmware-cloud-auth out=[core.api.factory] />
<api:app/permission out=[core.api.factory] />
<api:app/app-language out=[core.api.factory] />
<api:app/app-theme out=[core.api.factory]>
themes [
<theme:app/dark out=[core.theme.theme] />
<theme:app/light out=[core.theme.theme] />
]
</api:app/app-theme>
<api:app/components out=[core.api.factory]>
components [
<component:core.components.progress out=[core.component.component] />
<component:core.components.notFoundErrorPage out=[core.component.component] />
<component:core.components.errorBoundaryFallback out=[core.component.component] />
]
</api:app/components>
<api:app/icons out=[core.api.factory] />
<api:app/feature-flags out=[core.api.factory] />
<api:app/translations out=[core.api.factory] />
]
app [
<app out=[core.reactElement]>
root [
<app/root out=[core.reactElement]>
children [
<app/layout out=[core.reactElement]>
nav [
<app/nav out=[core.reactElement] />
]
content [
<app/routes out=[core.reactElement]>
routes [
@@ -269,9 +314,6 @@ describe('createApp', () => {
]
</app/routes>
]
nav [
<app/nav out=[core.reactElement] />
]
</app/layout>
]
elements [
@@ -282,43 +324,6 @@ describe('createApp', () => {
]
</app>
]
apis [
<api:app-theme out=[core.api.factory]>
themes [
<theme:app/light out=[core.theme.theme] />
<theme:app/dark out=[core.theme.theme] />
]
</api:app-theme>
<api:app-language out=[core.api.factory] />
<api:icons out=[core.api.factory] />
<api:translations out=[core.api.factory] />
<api:components out=[core.api.factory]>
components [
<component:core.components.progress out=[core.component.component] />
<component:core.components.errorBoundaryFallback out=[core.component.component] />
<component:core.components.notFoundErrorPage out=[core.component.component] />
]
</api:components>
<api:feature-flags out=[core.api.factory] />
<api:core.discovery out=[core.api.factory] />
<api:core.alert out=[core.api.factory] />
<api:core.analytics out=[core.api.factory] />
<api:core.error out=[core.api.factory] />
<api:core.storage out=[core.api.factory] />
<api:core.fetch out=[core.api.factory] />
<api:core.oauthrequest out=[core.api.factory] />
<api:core.auth.google out=[core.api.factory] />
<api:core.auth.microsoft out=[core.api.factory] />
<api:core.auth.github out=[core.api.factory] />
<api:core.auth.okta out=[core.api.factory] />
<api:core.auth.gitlab out=[core.api.factory] />
<api:core.auth.onelogin out=[core.api.factory] />
<api:core.auth.bitbucket out=[core.api.factory] />
<api:core.auth.bitbucket-server out=[core.api.factory] />
<api:core.auth.atlassian out=[core.api.factory] />
<api:core.auth.vmware-cloud out=[core.api.factory] />
<api:plugin.permission.api out=[core.api.factory] />
]
</root>"
`);
});
@@ -45,6 +45,7 @@
"@backstage/cli": "workspace:^",
"@backstage/frontend-app-api": "workspace:^",
"@backstage/frontend-test-utils": "workspace:^",
"@backstage/plugin-app": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^15.0.0",
@@ -26,6 +26,7 @@ import {
} from '../wiring';
import { MockConfigApi } from '@backstage/test-utils';
import { PageBlueprint } from './PageBlueprint';
import appPlugin from '@backstage/plugin-app';
describe('RouterBlueprint', () => {
it('should return an extension when calling make with sensible defaults', () => {
@@ -74,6 +75,7 @@ describe('RouterBlueprint', () => {
const app = createSpecializedApp({
features: [
appPlugin,
createExtensionOverrides({
extensions: [
extension,
@@ -126,6 +128,7 @@ describe('RouterBlueprint', () => {
const app = createSpecializedApp({
features: [
appPlugin,
createExtensionOverrides({
extensions: [
extension,
@@ -33,7 +33,7 @@ describe('ThemeBlueprint', () => {
"$$type": "@backstage/ExtensionDefinition",
"T": undefined,
"attachTo": {
"id": "api:app-theme",
"id": "api:app/app-theme",
"input": "themes",
},
"configSchema": undefined,
@@ -48,7 +48,7 @@ describe('TranslationBlueprint', () => {
"$$type": "@backstage/ExtensionDefinition",
"T": undefined,
"attachTo": {
"id": "api:translations",
"id": "api:app/translations",
"input": "translations",
},
"configSchema": undefined,
@@ -25,6 +25,7 @@ import { coreExtensionData } from './coreExtensionData';
import { MockConfigApi, renderWithEffects } from '@backstage/test-utils';
import { createExtensionInput } from './createExtensionInput';
import { BackstagePlugin } from './types';
import appPlugin from '@backstage/plugin-app';
const nameExtensionDataRef = createExtensionDataRef<string>().with({
id: 'name',
@@ -127,7 +128,7 @@ function createTestAppRoot({
config: JsonObject;
}) {
return createApp({
features,
features: [...features, appPlugin],
configLoader: async () => ({ config: new MockConfigApi(config) }),
}).createRoot();
}
@@ -34,6 +34,7 @@
"@backstage/config": "workspace:^",
"@backstage/frontend-app-api": "workspace:^",
"@backstage/frontend-plugin-api": "workspace:^",
"@backstage/plugin-app": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@backstage/types": "workspace:^"
},
@@ -27,12 +27,12 @@ import {
coreExtensionData,
RouteRef,
useRouteRef,
createExtensionInput,
IconComponent,
RouterBlueprint,
NavItemBlueprint,
FrontendFeature,
} from '@backstage/frontend-plugin-api';
import appPlugin from '@backstage/plugin-app';
/**
* Options to customize the behavior of the test app.
@@ -92,38 +92,36 @@ const NavItem = (props: {
);
};
export const TestAppNavExtension = createExtension({
namespace: 'app',
name: 'nav',
attachTo: { id: 'app/layout', input: 'nav' },
inputs: {
items: createExtensionInput([NavItemBlueprint.dataRefs.target]),
},
output: [coreExtensionData.reactElement],
factory({ inputs }) {
return [
coreExtensionData.reactElement(
<nav>
<ul>
{inputs.items.map((item, index) => {
const { icon, title, routeRef } = item.get(
NavItemBlueprint.dataRefs.target,
);
const appPluginOverride = appPlugin.withOverrides({
extensions: [
appPlugin.getExtension('app/nav').override({
output: [coreExtensionData.reactElement],
factory(_originalFactory, { inputs }) {
return [
coreExtensionData.reactElement(
<nav>
<ul>
{inputs.items.map((item, index) => {
const { icon, title, routeRef } = item.get(
NavItemBlueprint.dataRefs.target,
);
return (
<NavItem
key={index}
icon={icon}
title={title}
routeRef={routeRef}
/>
);
})}
</ul>
</nav>,
),
];
},
return (
<NavItem
key={index}
icon={icon}
title={title}
routeRef={routeRef}
/>
);
})}
</ul>
</nav>,
),
];
},
}),
],
});
/**
@@ -152,7 +150,6 @@ export function renderInTestApp(
Component: ({ children }) => <MemoryRouter>{children}</MemoryRouter>,
},
}),
TestAppNavExtension,
];
if (options?.mountedRoutes) {
@@ -183,6 +180,7 @@ export function renderInTestApp(
}
const features: FrontendFeature[] = [
appPluginOverride,
createExtensionOverrides({
extensions,
}),
+13 -12
View File
@@ -75,16 +75,12 @@ export const AppRoot = createExtension({
},
output: [coreExtensionData.reactElement],
factory({ inputs, apis }) {
const identityApi = apis.get(identityApiRef);
if (!identityApi) {
throw new Error('App requires an Identity API implementation');
}
if (!('enableCookieAuth' in identityApi)) {
throw new Error('Unexpected Identity API implementation');
}
const appIdentityProxy = identityApi as AppIdentityProxy;
if (isProtectedApp()) {
const identityApi = apis.get(identityApiRef);
if (!identityApi) {
throw new Error('App requires an Identity API implementation');
}
const appIdentityProxy = toAppIdentityProxy(identityApi);
const discoveryApi = apis.get(discoveryApiRef);
const errorApi = apis.get(errorApiRef);
const fetchApi = apis.get(fetchApiRef);
@@ -119,7 +115,6 @@ export const AppRoot = createExtension({
return [
coreExtensionData.reactElement(
<AppRouter
appIdentityProxy={appIdentityProxy}
SignInPageComponent={inputs.signInPage?.get(
SignInPageBlueprint.dataRefs.component,
)}
@@ -174,6 +169,13 @@ type AppIdentityProxy = IdentityApi & {
): void;
};
function toAppIdentityProxy(identityApi: IdentityApi): AppIdentityProxy {
if (!('enableCookieAuth' in identityApi)) {
throw new Error('Unexpected Identity API implementation');
}
return identityApi as AppIdentityProxy;
}
type RouteResolverProxy = {
getRouteObjects(): any[];
};
@@ -184,7 +186,6 @@ type RouteResolverProxy = {
*/
export interface AppRouterProps {
children?: ReactNode;
appIdentityProxy: AppIdentityProxy;
SignInPageComponent?: ComponentType<SignInPageProps>;
RouterComponent?: ComponentType<PropsWithChildren<{}>>;
}
@@ -208,12 +209,12 @@ function DefaultRouter(props: PropsWithChildren<{}>) {
export function AppRouter(props: AppRouterProps) {
const {
children,
appIdentityProxy,
SignInPageComponent,
RouterComponent = DefaultRouter,
} = props;
const configApi = useApi(configApiRef);
const appIdentityProxy = toAppIdentityProxy(useApi(identityApiRef));
const routeResolutionsApi = useApi(routeResolutionApiRef);
const basePath = getBasePath(configApi);