frontend-plugin-api: add tests for generator factories + error on undeclared output

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-08-02 14:56:17 +02:00
parent f13b6c467b
commit 5020910446
4 changed files with 150 additions and 4 deletions
@@ -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',