diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index ee23da2f82..5a2a7186c1 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -197,41 +197,3 @@ describe('TemplatePage', () => { expect(await findByText('Reset')).toBeInTheDocument(); }); }); - -describe('createValidator', () => { - it('should validate deep schema', () => { - const validator = createValidator( - { - type: 'object', - properties: { - foo: { - type: 'object', - properties: { - bar: { - type: 'string', - 'ui:field': 'RepoUrlPicker', - }, - }, - }, - }, - }, - {}, - ); - - const errors = { foo: { bar: { addError: jest.fn() } } }; - validator({ foo: { bar: 'github.com?owner=a' } }, errors as any); - expect(errors.foo.bar.addError).toHaveBeenCalledWith( - 'Incomplete repository location provided', - ); - jest.resetAllMocks(); - - validator({ foo: { bar: 'github.com?repo=b' } }, errors as any); - expect(errors.foo.bar.addError).toHaveBeenCalledWith( - 'Incomplete repository location provided', - ); - jest.resetAllMocks(); - - validator({ foo: { bar: 'github.com?owner=a&repo=b' } }, errors as any); - expect(errors.foo.bar.addError).not.toHaveBeenCalled(); - }); -}); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts index b0f3df61d9..32bb6ee7f7 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { RepoUrlPicker } from './RepoUrlPicker'; +export { repoPickerValidation } from './validation'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts new file mode 100644 index 0000000000..7e05ca7851 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { repoPickerValidation } from './validation'; +import { FieldValidation } from '@rjsf/core'; + +describe('RepoPicker Validation', () => { + const fieldValidator = () => + (({ + addError: jest.fn(), + } as unknown) as FieldValidation); + + it('validaties when no repo', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('github.com?owner=a', mockFieldValidation); + + expect(mockFieldValidation.addError).toHaveBeenCalledWith( + 'Incomplete repository location provided', + ); + }); + + it('validates when no owner', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('github.com?repo=a', mockFieldValidation); + + expect(mockFieldValidation.addError).toHaveBeenCalledWith( + 'Incomplete repository location provided', + ); + }); + + it('validates when not a real url', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('', mockFieldValidation); + + expect(mockFieldValidation.addError).toHaveBeenCalledWith( + 'Unable to parse the Repository URL', + ); + }); + + it('validates properly with proper input', () => { + const mockFieldValidation = fieldValidator(); + + repoPickerValidation('github.com?owner=a&repo=b', mockFieldValidation); + + expect(mockFieldValidation.addError).not.toHaveBeenCalled(); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts new file mode 100644 index 0000000000..f573838081 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { FieldValidation } from '@rjsf/core'; + +export const repoPickerValidation = ( + value: string, + validation: FieldValidation, +) => { + try { + const { host, searchParams } = new URL(`https://${value}`); + if (!host || !searchParams.get('owner') || !searchParams.get('repo')) { + validation.addError('Incomplete repository location provided'); + } + } catch { + validation.addError('Unable to parse the Repository URL'); + } +}; diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts index 1ffe3bdb81..5991ae4bc3 100644 --- a/plugins/scaffolder/src/plugin.ts +++ b/plugins/scaffolder/src/plugin.ts @@ -22,7 +22,10 @@ import { identityApiRef, } from '@backstage/core'; import { OwnerPicker } from './components/fields/OwnerPicker'; -import { RepoUrlPicker } from './components/fields/RepoUrlPicker'; +import { + RepoUrlPicker, + repoPickerValidation, +} from './components/fields/RepoUrlPicker'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { scaffolderApiRef, ScaffolderClient } from './api'; import { createScaffolderFieldExtension } from './extensions'; @@ -54,16 +57,7 @@ export const RepoUrlPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ component: RepoUrlPicker, name: 'RepoUrlPicker', - validation: (value, validation) => { - try { - const { host, searchParams } = new URL(`https://${value}`); - if (!host || !searchParams.get('owner') || !searchParams.get('repo')) { - validation.addError('Incomplete repository location provided'); - } - } catch { - validation.addError('Unable to parse the Repository URL'); - } - }, + validation: repoPickerValidation, }), );