Merge pull request #25892 from backstage/rugvip/generators
frontend-plugin-api: add tests for generator factories + error on undeclared output
This commit is contained in:
@@ -914,7 +914,7 @@ describe('instantiateAppNodeTree', () => {
|
||||
namespace: 'app',
|
||||
name: 'test',
|
||||
attachTo: { id: 'ignored', input: 'ignored' },
|
||||
output: [],
|
||||
output: [testDataRef],
|
||||
factory() {
|
||||
const error = new Error('NOPE');
|
||||
error.name = 'NopeError';
|
||||
@@ -981,11 +981,12 @@ describe('instantiateAppNodeTree', () => {
|
||||
createAppNodeInstance({
|
||||
node: makeNode(
|
||||
resolveExtensionDefinition(
|
||||
// @ts-expect-error
|
||||
createExtension({
|
||||
namespace: 'app',
|
||||
name: 'test',
|
||||
attachTo: { id: 'ignored', input: 'ignored' },
|
||||
output: [],
|
||||
output: [], // Output not declared
|
||||
factory({}) {
|
||||
return [testDataRef('test')] as any;
|
||||
},
|
||||
|
||||
@@ -394,6 +394,18 @@ describe('createExtension', () => {
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
// @ts-expect-error
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef],
|
||||
factory() {
|
||||
return [stringDataRef('hello'), numberDataRef(4)];
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
@@ -428,6 +440,93 @@ describe('createExtension', () => {
|
||||
).toMatchObject({ version: 'v2' });
|
||||
});
|
||||
|
||||
it('should support new form of outputs with a generator', () => {
|
||||
expect(
|
||||
// @ts-expect-error
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef, numberDataRef],
|
||||
*factory() {
|
||||
// Missing all outputs
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
// @ts-expect-error
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef, numberDataRef],
|
||||
*factory() {
|
||||
yield stringDataRef('hello'); // Missing number output
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
// Duplicate output, we won't attempt to handle this a compile time and instead error out at runtime
|
||||
expect(
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef],
|
||||
*factory() {
|
||||
yield stringDataRef('hello');
|
||||
yield stringDataRef('hello');
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
// @ts-expect-error
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef],
|
||||
*factory() {
|
||||
yield stringDataRef('hello');
|
||||
yield numberDataRef(4); // No declared output
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef, numberDataRef],
|
||||
*factory() {
|
||||
yield stringDataRef('hello');
|
||||
yield numberDataRef(4);
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef, numberDataRef.optional()],
|
||||
*factory() {
|
||||
yield stringDataRef('hello');
|
||||
yield numberDataRef(4);
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
|
||||
expect(
|
||||
createExtension({
|
||||
namespace: 'test',
|
||||
attachTo: { id: 'root', input: 'default' },
|
||||
output: [stringDataRef, numberDataRef.optional()],
|
||||
*factory() {
|
||||
yield stringDataRef('hello'); // Missing number output, but it's optional so that's allowed
|
||||
},
|
||||
}),
|
||||
).toMatchObject({ version: 'v2' });
|
||||
});
|
||||
|
||||
it('should support new form of inputs', () => {
|
||||
expect(
|
||||
createExtension({
|
||||
|
||||
@@ -157,9 +157,16 @@ export type VerifyExtensionFactoryOutput<
|
||||
: never
|
||||
) extends infer IRequiredOutputIds
|
||||
? [IRequiredOutputIds] extends [UFactoryOutput['id']]
|
||||
? {}
|
||||
? [UFactoryOutput['id']] extends [UDeclaredOutput['id']]
|
||||
? {}
|
||||
: {
|
||||
'Error: The extension factory has undeclared output(s)': Exclude<
|
||||
UFactoryOutput['id'],
|
||||
UDeclaredOutput['id']
|
||||
>;
|
||||
}
|
||||
: {
|
||||
'Error: The extension factory is missing the following outputs': Exclude<
|
||||
'Error: The extension factory is missing the following output(s)': Exclude<
|
||||
IRequiredOutputIds,
|
||||
UFactoryOutput['id']
|
||||
>;
|
||||
|
||||
@@ -64,6 +64,45 @@ describe('createExtensionBlueprint', () => {
|
||||
expect(container.querySelector('h1')).toHaveTextContent('Hello, world!');
|
||||
});
|
||||
|
||||
it('should allow creation of extension blueprints with a generator', () => {
|
||||
const TestExtensionBlueprint = createExtensionBlueprint({
|
||||
kind: 'test-extension',
|
||||
attachTo: { id: 'test', input: 'default' },
|
||||
output: [coreExtensionData.reactElement],
|
||||
*factory(params: { text: string }) {
|
||||
yield coreExtensionData.reactElement(<h1>{params.text}</h1>);
|
||||
},
|
||||
});
|
||||
|
||||
const extension = TestExtensionBlueprint.make({
|
||||
name: 'my-extension',
|
||||
params: {
|
||||
text: 'Hello, world!',
|
||||
},
|
||||
});
|
||||
|
||||
expect(extension).toEqual({
|
||||
$$type: '@backstage/ExtensionDefinition',
|
||||
attachTo: {
|
||||
id: 'test',
|
||||
input: 'default',
|
||||
},
|
||||
configSchema: undefined,
|
||||
disabled: false,
|
||||
inputs: {},
|
||||
kind: 'test-extension',
|
||||
name: 'my-extension',
|
||||
namespace: undefined,
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: expect.any(Function),
|
||||
toString: expect.any(Function),
|
||||
version: 'v2',
|
||||
});
|
||||
|
||||
const { container } = createExtensionTester(extension).render();
|
||||
expect(container.querySelector('h1')).toHaveTextContent('Hello, world!');
|
||||
});
|
||||
|
||||
it('should allow overriding of the default factory', () => {
|
||||
const TestExtensionBlueprint = createExtensionBlueprint({
|
||||
kind: 'test-extension',
|
||||
|
||||
Reference in New Issue
Block a user