frontend-app-api: update instantiateAppNodeTree tests for ExtensionDefinition

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-11-22 13:14:52 +01:00
parent 5196a136c1
commit b21f33deda
@@ -28,28 +28,33 @@ import {
} from './instantiateAppNodeTree';
import { AppNodeInstance, AppNodeSpec } from '@backstage/frontend-plugin-api';
import { resolveAppTree } from './resolveAppTree';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';
const testDataRef = createExtensionDataRef<string>('test');
const otherDataRef = createExtensionDataRef<number>('other');
const inputMirrorDataRef = createExtensionDataRef<unknown>('mirror');
const simpleExtension = createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {
test: testDataRef,
other: otherDataRef.optional(),
},
configSchema: createSchemaFromZod(z =>
z.object({
output: z.string().default('test'),
other: z.number().optional(),
}),
),
factory({ config }) {
return { test: config.output, other: config.other };
},
});
const simpleExtension = resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {
test: testDataRef,
other: otherDataRef.optional(),
},
configSchema: createSchemaFromZod(z =>
z.object({
output: z.string().default('test'),
other: z.number().optional(),
}),
),
factory({ config }) {
return { test: config.output, other: config.other };
},
}),
);
function makeSpec<TConfig>(
extension: Extension<TConfig>,
@@ -117,19 +122,21 @@ describe('instantiateAppNodeTree', () => {
it('should instantiate a node with attachments', () => {
const tree = resolveAppTree('root-node', [
makeSpec(
createExtension({
id: 'root-node',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
test: createExtensionInput({ test: testDataRef }),
},
output: {
inputMirror: inputMirrorDataRef,
},
factory({ inputs }) {
return { inputMirror: inputs };
},
}),
resolveExtensionDefinition(
createExtension({
namespace: 'root-node',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
test: createExtensionInput({ test: testDataRef }),
},
output: {
inputMirror: inputMirrorDataRef,
},
factory({ inputs }) {
return { inputMirror: inputs };
},
}),
),
),
makeSpec(simpleExtension, {
id: 'child-node',
@@ -159,19 +166,21 @@ describe('instantiateAppNodeTree', () => {
const tree = resolveAppTree('root-node', [
{
...makeSpec(
createExtension({
id: 'root-node',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
test: createExtensionInput({ test: testDataRef }),
},
output: {
inputMirror: inputMirrorDataRef,
},
factory({ inputs }) {
return { inputMirror: inputs };
},
}),
resolveExtensionDefinition(
createExtension({
namespace: 'root-node',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
test: createExtensionInput({ test: testDataRef }),
},
output: {
inputMirror: inputMirrorDataRef,
},
factory({ inputs }) {
return { inputMirror: inputs };
},
}),
),
),
},
{
@@ -242,43 +251,46 @@ describe('createAppNodeInstance', () => {
const instance = createAppNodeInstance({
attachments,
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
optionalSingletonPresent: createExtensionInput(
{
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
optionalSingletonPresent: createExtensionInput(
{
test: testDataRef,
other: otherDataRef.optional(),
},
{ singleton: true, optional: true },
),
optionalSingletonMissing: createExtensionInput(
{
test: testDataRef,
other: otherDataRef.optional(),
},
{ singleton: true, optional: true },
),
singleton: createExtensionInput(
{
test: testDataRef,
other: otherDataRef.optional(),
},
{ singleton: true },
),
many: createExtensionInput({
test: testDataRef,
other: otherDataRef.optional(),
},
{ singleton: true, optional: true },
),
optionalSingletonMissing: createExtensionInput(
{
test: testDataRef,
other: otherDataRef.optional(),
},
{ singleton: true, optional: true },
),
singleton: createExtensionInput(
{
test: testDataRef,
other: otherDataRef.optional(),
},
{ singleton: true },
),
many: createExtensionInput({
test: testDataRef,
other: otherDataRef.optional(),
}),
},
output: {
inputMirror: inputMirrorDataRef,
},
factory({ inputs }) {
return { inputMirror: inputs };
},
}),
}),
},
output: {
inputMirror: inputMirrorDataRef,
},
factory({ inputs }) {
return { inputMirror: inputs };
},
}),
),
),
});
@@ -297,7 +309,7 @@ describe('createAppNodeInstance', () => {
attachments: new Map(),
}),
).toThrow(
"Invalid configuration for extension 'core.test'; caused by Error: Expected number, received string at 'other'",
"Invalid configuration for extension 'core/test'; caused by Error: Expected number, received string at 'other'",
);
});
@@ -305,21 +317,24 @@ describe('createAppNodeInstance', () => {
expect(() =>
createAppNodeInstance({
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {},
factory() {
const error = new Error('NOPE');
error.name = 'NopeError';
throw error;
},
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {},
factory() {
const error = new Error('NOPE');
error.name = 'NopeError';
throw error;
},
}),
),
),
attachments: new Map(),
}),
).toThrow(
"Failed to instantiate extension 'core.test'; caused by NopeError: NOPE",
"Failed to instantiate extension 'core/test'; caused by NopeError: NOPE",
);
});
@@ -327,22 +342,25 @@ describe('createAppNodeInstance', () => {
expect(() =>
createAppNodeInstance({
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {
test1: testDataRef,
test2: testDataRef,
},
factory({}) {
return { test1: 'test', test2: 'test2' };
},
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {
test1: testDataRef,
test2: testDataRef,
},
factory({}) {
return { test1: 'test', test2: 'test2' };
},
}),
),
),
attachments: new Map(),
}),
).toThrow(
"Failed to instantiate extension 'core.test', duplicate extension data 'test' received via output 'test2'",
"Failed to instantiate extension 'core/test', duplicate extension data 'test' received via output 'test2'",
);
});
@@ -350,21 +368,24 @@ describe('createAppNodeInstance', () => {
expect(() =>
createAppNodeInstance({
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {
test: testDataRef,
},
factory({}) {
return { nonexistent: 'test' } as any;
},
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {
test: testDataRef,
},
factory({}) {
return { nonexistent: 'test' } as any;
},
}),
),
),
attachments: new Map(),
}),
).toThrow(
"Failed to instantiate extension 'core.test', unknown output provided via 'nonexistent'",
"Failed to instantiate extension 'core/test', unknown output provided via 'nonexistent'",
);
});
@@ -372,25 +393,28 @@ describe('createAppNodeInstance', () => {
expect(() =>
createAppNodeInstance({
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
test: testDataRef,
},
{ singleton: true },
),
},
output: {},
factory: () => ({}),
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
test: testDataRef,
},
{ singleton: true },
),
},
output: {},
factory: () => ({}),
}),
),
),
attachments: new Map(),
}),
).toThrow(
"Failed to instantiate extension 'core.test', input 'singleton' is required but was not received",
"Failed to instantiate extension 'core/test', input 'singleton' is required but was not received",
);
});
@@ -416,21 +440,24 @@ describe('createAppNodeInstance', () => {
],
]),
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
declared: createExtensionInput({
test: testDataRef,
}),
},
output: {},
factory: () => ({}),
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
declared: createExtensionInput({
test: testDataRef,
}),
},
output: {},
factory: () => ({}),
}),
),
),
}),
).toThrow(
"Failed to instantiate extension 'core.test', received undeclared input 'undeclared' from extension 'core.test'",
"Failed to instantiate extension 'core/test', received undeclared input 'undeclared' from extension 'core/test'",
);
});
@@ -451,16 +478,19 @@ describe('createAppNodeInstance', () => {
],
]),
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {},
factory: () => ({}),
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
output: {},
factory: () => ({}),
}),
),
),
}),
).toThrow(
"Failed to instantiate extension 'core.test', received undeclared inputs 'undeclared1' from extension 'core.test' and 'undeclared2' from extensions 'core.test', 'core.test'",
"Failed to instantiate extension 'core/test', received undeclared inputs 'undeclared1' from extension 'core/test' and 'undeclared2' from extensions 'core/test', 'core/test'",
);
});
@@ -477,24 +507,27 @@ describe('createAppNodeInstance', () => {
],
]),
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
test: testDataRef,
},
{ singleton: true },
),
},
output: {},
factory: () => ({}),
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
test: testDataRef,
},
{ singleton: true },
),
},
output: {},
factory: () => ({}),
}),
),
),
}),
).toThrow(
"Failed to instantiate extension 'core.test', expected exactly one 'singleton' input but received multiple: 'core.test', 'core.test'",
"Failed to instantiate extension 'core/test', expected exactly one 'singleton' input but received multiple: 'core/test', 'core/test'",
);
});
@@ -511,24 +544,27 @@ describe('createAppNodeInstance', () => {
],
]),
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
test: testDataRef,
},
{ singleton: true, optional: true },
),
},
output: {},
factory: () => ({}),
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
test: testDataRef,
},
{ singleton: true, optional: true },
),
},
output: {},
factory: () => ({}),
}),
),
),
}),
).toThrow(
"Failed to instantiate extension 'core.test', expected at most one 'singleton' input but received multiple: 'core.test', 'core.test'",
"Failed to instantiate extension 'core/test', expected at most one 'singleton' input but received multiple: 'core/test', 'core/test'",
);
});
@@ -539,24 +575,27 @@ describe('createAppNodeInstance', () => {
['singleton', [makeInstanceWithId(simpleExtension, undefined)]],
]),
node: makeNode(
createExtension({
id: 'core.test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
other: otherDataRef,
},
{ singleton: true },
),
},
output: {},
factory: () => ({}),
}),
resolveExtensionDefinition(
createExtension({
namespace: 'core',
name: 'test',
attachTo: { id: 'ignored', input: 'ignored' },
inputs: {
singleton: createExtensionInput(
{
other: otherDataRef,
},
{ singleton: true },
),
},
output: {},
factory: () => ({}),
}),
),
),
}),
).toThrow(
"Failed to instantiate extension 'core.test', input 'singleton' did not receive required extension data 'other' from extension 'core.test'",
"Failed to instantiate extension 'core/test', input 'singleton' did not receive required extension data 'other' from extension 'core/test'",
);
});
});