From e344d825146edfbcac1c347da0e4820f3a14b249 Mon Sep 17 00:00:00 2001 From: Jeff Phillips Date: Fri, 6 Sep 2024 14:29:16 -0400 Subject: [PATCH] Fix for URI form field regex validation (#3157) --- .../connectionTypes/fields/UriFormField.tsx | 13 +++-- .../fields/__tests__/UriFormField.spec.tsx | 49 +++++++++++++++++-- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/frontend/src/concepts/connectionTypes/fields/UriFormField.tsx b/frontend/src/concepts/connectionTypes/fields/UriFormField.tsx index 6d2f3cbd6b..43ca3d0ce7 100644 --- a/frontend/src/concepts/connectionTypes/fields/UriFormField.tsx +++ b/frontend/src/concepts/connectionTypes/fields/UriFormField.tsx @@ -11,13 +11,12 @@ import { UriField } from '~/concepts/connectionTypes/types'; import { FieldProps } from '~/concepts/connectionTypes/fields/types'; import DefaultValueTextRenderer from '~/concepts/connectionTypes/fields/DefaultValueTextRenderer'; -const URI_REGEX = new RegExp( - '(?:(?:https?|ftp|file)://|www.|ftp.)(?:([-A-Z0-9+&@#/%=~_|$?!:,.]*)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:([-A-Z0-9+&@#/%=~_|$?!:,.]*)|[A-Z0-9+&@#/%=~_|$])', -); - const validateUrl = (url?: string) => { + if (!url) { + return true; + } try { - return !url || URI_REGEX.test(url); + return !!new URL(url); } catch (e) { return false; } @@ -68,9 +67,9 @@ const UriFormField: React.FC> = ({ /> {!isValid && ( - + } variant={ValidatedOptions.error}> - Invalid URL + Invalid URI diff --git a/frontend/src/concepts/connectionTypes/fields/__tests__/UriFormField.spec.tsx b/frontend/src/concepts/connectionTypes/fields/__tests__/UriFormField.spec.tsx index 222f781e23..00695efc10 100644 --- a/frontend/src/concepts/connectionTypes/fields/__tests__/UriFormField.spec.tsx +++ b/frontend/src/concepts/connectionTypes/fields/__tests__/UriFormField.spec.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import '@testing-library/jest-dom'; import { fireEvent, render, screen } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; import { UriField } from '~/concepts/connectionTypes/types'; import UriFormField from '~/concepts/connectionTypes/fields/UriFormField'; @@ -22,7 +21,7 @@ describe('UriFormField', () => { expect(input).toHaveValue('http://bar.com'); expect(input).not.toBeDisabled(); - act(() => { + React.act(() => { fireEvent.change(input, { target: { value: 'http://new.com' } }); }); expect(onChange).toHaveBeenCalledWith('http://new.com'); @@ -53,7 +52,7 @@ describe('UriFormField', () => { expect(input).not.toBeDisabled(); expect(input).toHaveAttribute('aria-readonly', 'true'); - act(() => { + React.act(() => { fireEvent.change(input, { target: { value: 'http://new.com' } }); }); expect(onChange).not.toHaveBeenCalled(); @@ -74,4 +73,48 @@ describe('UriFormField', () => { expect(screen.queryByRole('textbox')).not.toBeInTheDocument(); expect(screen.queryByText('http://foo.com')).toBeInTheDocument(); }); + + it('should validate the URI entry', async () => { + const field: UriField = { + type: 'uri', + name: 'test-name', + envVar: 'test-envVar', + properties: { + defaultValue: 'http://foo.com', + defaultReadOnly: false, + }, + }; + let renderResult; + + const validURIs = [ + 'http://www.someplace.com', + 'https://www.someplace.com:9090/blah', + 'http://www.ics.uci.edu/pub/ietf/uri?name=test/#Related', + 'ftp://ftp.someplace.com:9090/blah/test.tst', + 'file://var/log/some-log.log', + 'file:/www.someplace.com:9090/c:/mydir/myfile.csv.gz', + 'file:/www.someplace.com:9090/spaces are allowed/my file with no extension', + 'gs://', + 's3://', + 'hdfs://', + 'webhdfs://', + 'model-registry://iris/v1', + 'pvc://PVC-NAME/model.joblib', + ]; + validURIs.forEach((uri) => { + renderResult = render(); + expect(screen.queryByTestId('uri-form-field-helper-text')).not.toBeInTheDocument(); + renderResult.unmount(); + }); + + const invalidURIs = [ + '://www.someplace.com:9090/blah', + 'https://www.something ?#?!@#$%&()!@#$%&(?#>/.,/ is this valid', + ]; + invalidURIs.forEach((uri) => { + renderResult = render(); + expect(screen.queryByTestId('uri-form-field-helper-text')).toBeInTheDocument(); + renderResult.unmount(); + }); + }); });