Test coverage for extension factory middleware
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
@@ -925,6 +925,24 @@ describe('instantiateAppNodeTree', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should create an extension passed through an extension factory middleware', () => {
|
||||
const attachments = new Map();
|
||||
const instance = createAppNodeInstance({
|
||||
node: makeNode(simpleExtension),
|
||||
attachments,
|
||||
apis: testApis,
|
||||
*extensionFactoryMiddleware(originalFactory) {
|
||||
const output = originalFactory({
|
||||
config: { output: 'modified' },
|
||||
});
|
||||
yield* output;
|
||||
},
|
||||
});
|
||||
|
||||
expect(Array.from(instance.getDataRefs())).toEqual([testDataRef]);
|
||||
expect(instance.getData(testDataRef)).toEqual('modified');
|
||||
});
|
||||
|
||||
it('should refuse to create an extension with invalid config', () => {
|
||||
expect(() =>
|
||||
createAppNodeInstance({
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { screen, render } from '@testing-library/react';
|
||||
import { createSpecializedApp } from './createSpecializedApp';
|
||||
import { mockApis } from '@backstage/test-utils';
|
||||
import { mockApis, TestApiRegistry } from '@backstage/test-utils';
|
||||
import React from 'react';
|
||||
import {
|
||||
configApiRef,
|
||||
@@ -37,7 +37,7 @@ import {
|
||||
featureFlagsApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
|
||||
|
||||
describe('createSpecializedApp', () => {
|
||||
it('should render the root app', () => {
|
||||
@@ -166,6 +166,81 @@ describe('createSpecializedApp', () => {
|
||||
render(app.createRoot());
|
||||
|
||||
expect(screen.getByText('flags:test=a,test=b')).toBeInTheDocument();
|
||||
|
||||
expect(app.apis).toMatchInlineSnapshot(`
|
||||
ApiResolver {
|
||||
"apis": Map {
|
||||
"core.featureflags" => {
|
||||
"getRegisteredFlags": [Function],
|
||||
"registerFlag": [Function],
|
||||
},
|
||||
},
|
||||
"factories": ApiFactoryRegistry {
|
||||
"factories": Map {
|
||||
"core.featureflags" => {
|
||||
"factory": {
|
||||
"api": ApiRefImpl {
|
||||
"config": {
|
||||
"id": "core.featureflags",
|
||||
},
|
||||
},
|
||||
"deps": {},
|
||||
"factory": [Function],
|
||||
},
|
||||
"priority": 10,
|
||||
},
|
||||
"core.app-tree" => {
|
||||
"factory": {
|
||||
"api": ApiRefImpl {
|
||||
"config": {
|
||||
"id": "core.app-tree",
|
||||
},
|
||||
},
|
||||
"deps": {},
|
||||
"factory": [Function],
|
||||
},
|
||||
"priority": 100,
|
||||
},
|
||||
"core.config" => {
|
||||
"factory": {
|
||||
"api": ApiRefImpl {
|
||||
"config": {
|
||||
"id": "core.config",
|
||||
},
|
||||
},
|
||||
"deps": {},
|
||||
"factory": [Function],
|
||||
},
|
||||
"priority": 100,
|
||||
},
|
||||
"core.route-resolution" => {
|
||||
"factory": {
|
||||
"api": ApiRefImpl {
|
||||
"config": {
|
||||
"id": "core.route-resolution",
|
||||
},
|
||||
},
|
||||
"deps": {},
|
||||
"factory": [Function],
|
||||
},
|
||||
"priority": 100,
|
||||
},
|
||||
"core.identity" => {
|
||||
"factory": {
|
||||
"api": ApiRefImpl {
|
||||
"config": {
|
||||
"id": "core.identity",
|
||||
},
|
||||
},
|
||||
"deps": {},
|
||||
"factory": [Function],
|
||||
},
|
||||
"priority": 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should intitialize the APIs in the correct order to allow for overrides', () => {
|
||||
@@ -237,10 +312,59 @@ describe('createSpecializedApp', () => {
|
||||
expect(mockAnalyticsApi).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use provided apis', async () => {
|
||||
const app = createSpecializedApp({
|
||||
apis: TestApiRegistry.from([
|
||||
configApiRef,
|
||||
new ConfigReader({ anything: 'config' }),
|
||||
]),
|
||||
features: [
|
||||
createFrontendPlugin({
|
||||
id: 'test',
|
||||
extensions: [
|
||||
createExtension({
|
||||
attachTo: { id: 'root', input: 'app' },
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: ({ apis }) => [
|
||||
coreExtensionData.reactElement(
|
||||
<div>
|
||||
providedApis:
|
||||
{apis.get(configApiRef)!.getString('anything')}
|
||||
</div>,
|
||||
),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
render(app.createRoot());
|
||||
|
||||
expect(screen.getByText('providedApis:config')).toBeInTheDocument();
|
||||
|
||||
expect(app.apis).toMatchInlineSnapshot(`
|
||||
TestApiRegistry {
|
||||
"apis": Map {
|
||||
"core.config" => ConfigReader {
|
||||
"context": "mock-config",
|
||||
"data": {
|
||||
"anything": "config",
|
||||
},
|
||||
"fallback": undefined,
|
||||
"filteredKeys": undefined,
|
||||
"notifiedFilteredKeys": Set {},
|
||||
"prefix": "",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should make the app structure available through the AppTreeApi', async () => {
|
||||
let appTreeApi: AppTreeApi | undefined = undefined;
|
||||
|
||||
createSpecializedApp({
|
||||
const { tree } = createSpecializedApp({
|
||||
features: [
|
||||
createFrontendPlugin({
|
||||
id: 'test',
|
||||
@@ -265,6 +389,55 @@ describe('createSpecializedApp', () => {
|
||||
]
|
||||
</root>"
|
||||
`);
|
||||
|
||||
expect(tree).toMatchInlineSnapshot(`
|
||||
{
|
||||
"nodes": Map {
|
||||
"test" => {
|
||||
"attachments": undefined,
|
||||
"id": "test",
|
||||
"output": [
|
||||
"core.reactElement",
|
||||
],
|
||||
},
|
||||
"root" => {
|
||||
"attachments": {
|
||||
"app": [
|
||||
{
|
||||
"attachments": undefined,
|
||||
"id": "test",
|
||||
"output": [
|
||||
"core.reactElement",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"id": "root",
|
||||
"output": [
|
||||
"core.reactElement",
|
||||
],
|
||||
},
|
||||
},
|
||||
"orphans": [],
|
||||
"root": {
|
||||
"attachments": {
|
||||
"app": [
|
||||
{
|
||||
"attachments": undefined,
|
||||
"id": "test",
|
||||
"output": [
|
||||
"core.reactElement",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"id": "root",
|
||||
"output": [
|
||||
"core.reactElement",
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should support route bindings', async () => {
|
||||
|
||||
@@ -395,6 +395,46 @@ describe('createApp', () => {
|
||||
expect(screen.queryByText('Custom app root element')).toBeNull();
|
||||
});
|
||||
|
||||
it('should use a custom extensionFactoryMiddleware', async () => {
|
||||
const app = createApp({
|
||||
configLoader: async () => ({ config: mockApis.config() }),
|
||||
features: [
|
||||
appPlugin,
|
||||
createFrontendPlugin({
|
||||
id: 'test-plugin',
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
name: 'test-page',
|
||||
params: {
|
||||
defaultPath: '/',
|
||||
loader: async () => <>Test Page</>,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
*extensionFactoryMiddleware(originalFactory, context) {
|
||||
const output = originalFactory();
|
||||
yield* output;
|
||||
const element = output.get(coreExtensionData.reactElement);
|
||||
|
||||
if (element) {
|
||||
yield coreExtensionData.reactElement(
|
||||
<div data-testid={`wrapped(${context.node.spec.id})`}>
|
||||
{element}
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await renderWithEffects(app.createRoot());
|
||||
|
||||
await expect(
|
||||
screen.findByTestId('wrapped(page:test-plugin/test-page)'),
|
||||
).resolves.toHaveTextContent('Test Page');
|
||||
});
|
||||
|
||||
describe('modules', () => {
|
||||
it('should be able to override extensions with a plugin extension override', async () => {
|
||||
const mod = createFrontendModule({
|
||||
|
||||
Reference in New Issue
Block a user