diff --git a/console/src/components/Services/Data/Common/Components/TypedInput.js b/console/src/components/Services/Data/Common/Components/TypedInput.js index e0b9865671d..e72ff641d2e 100644 --- a/console/src/components/Services/Data/Common/Components/TypedInput.js +++ b/console/src/components/Services/Data/Common/Components/TypedInput.js @@ -5,6 +5,7 @@ import JsonInput from '../../../../Common/CustomInputTypes/JsonInput'; import TextInput from '../../../../Common/CustomInputTypes/TextInput'; import styles from '../../../../Common/TableCommon/Table.module.scss'; import { dataSource } from '../../../../../dataSources'; +import { onClick } from './typedInputUtils/onClick'; export const TypedInput = ({ enumOptions, @@ -33,16 +34,6 @@ export const TypedInput = ({ return ''; }; - const onClick = e => { - const closestRadio = e.target.closest('.radio-inline'); - - if (closestRadio) { - closestRadio.querySelector('input[type="radio"]').checked = true; - } - - e.target.focus(); - }; - const standardInputProps = { onChange, onFocus, diff --git a/console/src/components/Services/Data/Common/Components/typedInputUtils/onClick.test.ts b/console/src/components/Services/Data/Common/Components/typedInputUtils/onClick.test.ts new file mode 100644 index 00000000000..dda8910a8ad --- /dev/null +++ b/console/src/components/Services/Data/Common/Components/typedInputUtils/onClick.test.ts @@ -0,0 +1,50 @@ +import { onClick } from './onClick'; + +describe('onClick', () => { + // @see: https://sentry.io/organizations/hasura-nn/issues/3679294754/activity/?project=6684052 + // @see: https://sentry.io/organizations/hasura-nn/issues/3679762841/activity/?project=6684052 + describe('When invoked with a non-valid event then should not throw (Sentry CONSOLE-6J and CONSOLE-6E)', () => { + it.each` + testCase | event + ${'null'} | ${null} + ${'empty object'} | ${{}} + ${'null target'} | ${{ target: null }} + ${'null focus'} | ${{ target: { focus: null } }} + ${'null closest'} | ${{ target: { focus: null, closest: null } }} + ${'closest returns null'} | ${{ target: { focus: null, closest: () => null } }} + ${'null querySelector'} | ${{ target: { focus: null, closest: () => ({ querySelector: null }) } }} + ${'querySelector returns null'} | ${{ target: { focus: null, closest: () => ({ querySelector: () => null }) } }} + `(`Test case: '$testCase'`, ({ event }) => { + expect(() => onClick(event)).not.toThrow(); + }); + }); + + it(`When invoked with a valid event, then should call the target' focus method`, () => { + // Arrange + const target = document.createElement('p'); + target.focus = jest.fn(); + const fakeEvent = { target }; + + // Act + onClick(fakeEvent); + + // Assert + expect(target.focus).toHaveBeenCalled(); + }); + + it(`When invoked with a valid event and a .radio-inline element exist, then should set the element's checked property`, () => { + // Arrange + const target = document.createElement('input'); + const fakeEvent = { target }; + + // simulating a "real" DOM case where the closes element exists + const fakeElement = { checked: false }; + target.closest = () => ({ querySelector: () => fakeElement }); + + // Act + onClick(fakeEvent); + + // Assert + expect(fakeElement.checked).toBe(true); + }); +}); diff --git a/console/src/components/Services/Data/Common/Components/typedInputUtils/onClick.ts b/console/src/components/Services/Data/Common/Components/typedInputUtils/onClick.ts new file mode 100644 index 00000000000..4d80dc7f0e1 --- /dev/null +++ b/console/src/components/Services/Data/Common/Components/typedInputUtils/onClick.ts @@ -0,0 +1,28 @@ +/** + * At the time of writing, the goal was just to fix the Sentry CONSOLE-6J and Console-6E issues. + * Because onClick is spread across a long variety of components, even identifying its correct type + * was hard. Based on the fact that onClick is also passed to a select Element, I was able to identify + * the event. Anyway, the SimplifiedClickEvent is a best guess that also allow us passing almost + * whatever from the unit tests. + * + * @see: https://sentry.io/organizations/hasura-nn/issues/3679294754/activity/?project=6684052 + * @see: https://sentry.io/organizations/hasura-nn/issues/3679762841/activity/?project=6684052 + */ +type SimplifiedClickEvent = { target: React.MouseEvent['target'] }; + +export function onClick(e?: SimplifiedClickEvent) { + if (!(e?.target instanceof HTMLElement)) return; + + const closestRadio = e.target.closest?.('.radio-inline'); + if (closestRadio) { + const radioButton = closestRadio.querySelector( + 'input[type="radio"]' + ); + + if (radioButton) { + radioButton.checked = true; + } + } + + e.target.focus?.(); +}