chore: test fixes and simplify the types a little bit

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2024-10-14 15:09:43 +02:00
parent f6874fbfa8
commit bcaba24892
6 changed files with 112 additions and 69 deletions
@@ -27,6 +27,12 @@ import { analyticsApiRef } from '@backstage/core-plugin-api';
import { ScaffolderApi, scaffolderApiRef } from '../../../api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import { SecretsContextProvider } from '../../../secrets';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { ScaffolderFormDecoratorsApi } from '../../../../../scaffolder/src/alpha/api/types';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { formDecoratorsApiRef } from '../../../../../scaffolder/src/alpha/api/ref';
const scaffolderApiMock: jest.Mocked<ScaffolderApi> = {
cancelTask: jest.fn(),
@@ -39,14 +45,19 @@ const scaffolderApiMock: jest.Mocked<ScaffolderApi> = {
listTasks: jest.fn(),
autocomplete: jest.fn(),
};
const scaffolderDecoratorsMock: jest.Mocked<ScaffolderFormDecoratorsApi> = {
getFormDecorators: jest.fn().mockResolvedValue([]),
};
const catalogApi = catalogApiMock.mock();
const analyticsMock = mockApis.analytics();
const apis = TestApiRegistry.from(
[scaffolderApiRef, scaffolderApiMock],
[formDecoratorsApiRef, scaffolderDecoratorsMock],
[catalogApiRef, catalogApi],
[analyticsApiRef, analyticsMock],
[catalogApiRef, catalogApi],
);
describe('<Workflow />', () => {
@@ -82,31 +93,33 @@ describe('<Workflow />', () => {
});
const { getByRole, getAllByRole, getByText } = await renderInTestApp(
<ApiProvider apis={apis}>
<Workflow
title="Different title than template"
description={`
<SecretsContextProvider initialSecrets={{}}>
<ApiProvider apis={apis}>
<Workflow
title="Different title than template"
description={`
## This is markdown
- overriding the template description
`}
onCreate={onCreate}
onError={onError}
namespace="default"
templateName="docs-template"
initialState={{
name: 'prefilled-name',
age: '53',
}}
components={{
ReviewStateComponent: () => (
<h1>This is a different wrapper for the review page</h1>
),
reviewButtonText: <i>Onwards</i>,
createButtonText: <b>Make</b>,
}}
extensions={[]}
/>
</ApiProvider>,
onCreate={onCreate}
onError={onError}
namespace="default"
templateName="docs-template"
initialState={{
name: 'prefilled-name',
age: '53',
}}
components={{
ReviewStateComponent: () => (
<h1>This is a different wrapper for the review page</h1>
),
reviewButtonText: <i>Onwards</i>,
createButtonText: <b>Make</b>,
}}
extensions={[]}
/>
</ApiProvider>
</SecretsContextProvider>,
);
// Test template title is overriden
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useEffect } from 'react';
import {
Content,
InfoCard,
@@ -90,11 +90,10 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => {
const minutesSaved = useTemplateTimeSavedMinutes(templateRef);
const { setSecrets } = useInternalTemplateSecrets();
const formDecorators = useFormDecorators();
const [formState, setFormState] = useState<Record<string, JsonValue>>({});
const workflowOnCreate = useCallback(
async (originalFormState: Record<string, JsonValue>) => {
setFormState(originalFormState);
let formState: Record<string, JsonValue> = { ...originalFormState };
if (manifest?.EXPERIMENTAL_formDecorators && formDecorators?.size) {
// for each of the form decorators, go and call the decorator with the context
@@ -109,7 +108,13 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => {
await formDecorator.fn({
setSecrets,
setFormState,
setFormState: (
handler: (
oldState: Record<string, JsonValue>,
) => Record<string, JsonValue>,
) => {
formState = { ...handler(formState) };
},
formState,
input: decorator.input,
});
@@ -129,7 +134,6 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => {
manifest?.EXPERIMENTAL_formDecorators,
formDecorators,
onCreate,
formState,
analytics,
templateName,
minutesSaved,
@@ -23,7 +23,14 @@ describe('createScaffolderFormDecorator', () => {
fn: async () => {},
});
expect(decorator).toMatchInlineSnapshot();
expect(decorator).toMatchInlineSnapshot(`
{
"deps": {},
"fn": [Function],
"id": "test",
"version": "v1",
}
`);
});
it('should allow passing schema and be typesafe', () => {
@@ -46,6 +53,19 @@ describe('createScaffolderFormDecorator', () => {
},
});
expect(decorator).toMatchInlineSnapshot();
expect(decorator).toMatchInlineSnapshot(`
{
"deps": {},
"fn": [Function],
"id": "test",
"schema": {
"input": {
"age": [Function],
"name": [Function],
},
},
"version": "v1",
}
`);
});
});
@@ -15,15 +15,18 @@
*/
import { AnyApiRef } from '@backstage/core-plugin-api';
import { JsonValue } from '@backstage/types';
import { Dispatch, SetStateAction } from 'react';
import { z } from 'zod';
export type ScaffolderFormDecoratorContext<TInput> = {
input: TInput;
formState: Record<string, JsonValue>;
setFormState: Dispatch<SetStateAction<Record<string, JsonValue>>>;
setSecrets: Dispatch<SetStateAction<Record<string, string>>>;
setFormState: (
fn: (currentState: Record<string, JsonValue>) => Record<string, JsonValue>,
) => void;
setSecrets: (
fn: (currentState: Record<string, string>) => Record<string, string>,
) => void;
};
export type ScaffolderFormDecorator<