diff --git a/packages/eui/changelogs/upcoming/8952.md b/packages/eui/changelogs/upcoming/8952.md new file mode 100644 index 00000000000..00ab971c121 --- /dev/null +++ b/packages/eui/changelogs/upcoming/8952.md @@ -0,0 +1,3 @@ +**Bug fixes** + +- Fixed an issue where the validity state of `EuiFieldNumber` did not update when the `isInvalid` prop value changed diff --git a/packages/eui/src/components/form/field_number/field_number.spec.tsx b/packages/eui/src/components/form/field_number/field_number.spec.tsx index 30ab1b40dd5..cd7ecff0c32 100644 --- a/packages/eui/src/components/form/field_number/field_number.spec.tsx +++ b/packages/eui/src/components/form/field_number/field_number.spec.tsx @@ -10,19 +10,35 @@ /// /// -import React, { useState } from 'react'; +import React, { ChangeEventHandler, useState } from 'react'; +import { EuiForm } from '../form'; +import { EuiFormRow } from '../form_row'; import { EuiFieldNumber } from './field_number'; +import { EuiText } from '../../text'; describe('EuiFieldNumber', () => { describe('isNativelyInvalid', () => { - const checkIsValid = () => { - cy.get('[aria-invalid="true"]').should('not.exist'); - cy.get('.euiFormControlLayoutIcons').should('not.exist'); + const checkIsValid = (selector = 'input') => { + cy.get(selector) + .then(($el) => ($el[0] as HTMLInputElement).checkValidity()) + .should('be.true'); + cy.get(selector).should('not.have.attr', 'aria-invalid', 'true'); + cy.get(selector) + .parent() + .find('.euiFormControlLayoutIcons') + .should('not.exist'); }; - const checkIsInvalid = () => { - cy.get('[aria-invalid="true"]').should('exist'); - cy.get('.euiFormControlLayoutIcons').should('exist'); + + const checkIsInvalid = (selector = 'input') => { + cy.get(selector) + .then(($el) => ($el[0] as HTMLInputElement).checkValidity()) + .should('be.false'); + cy.get(selector).should('have.attr', 'aria-invalid', 'true'); + cy.get(selector) + .parent() + .find('.euiFormControlLayoutIcons') + .should('exist'); }; it('when the value is not a valid number', () => { @@ -171,6 +187,75 @@ describe('EuiFieldNumber', () => { cy.get('#setValidStep').click(); checkIsValid(); }); + + it('isInvalid', () => { + const FieldNumberValidationComponent = () => { + const [value1, setValue1] = useState('5'); + const [value2, setValue2] = useState('4'); + + const onChange1: ChangeEventHandler = (e) => { + const newValue = e.target.value; + setValue1(newValue); + }; + + const onChange2: ChangeEventHandler = (e) => { + const newValue = e.target.value; + setValue2(newValue); + }; + + const isValue2GreaterThanValue1 = value2 > value1; + + return ( + + + + + + + <> + + {isValue2GreaterThanValue1 && ( + + value2 should be smaller than value1 + + )} + + + + ); + }; + + const value1Selector = '[data-test-subj="value1"]'; + const value2Selector = '[data-test-subj="value2"]'; + + cy.mount(); + checkIsValid(value1Selector); + checkIsValid(value2Selector); + + // Set `value2` to a value greater than `value1` (5 < 6) => invalid + cy.get(value2Selector).clear(); + cy.get(value2Selector).focus().realType('6'); + checkIsValid(value1Selector); + checkIsInvalid(value2Selector); + + // Set `value1` to a value greater than `value2` (6 > 5) => valid + cy.get(value1Selector).clear(); + cy.get(value1Selector).focus().realType('6'); + checkIsValid(value1Selector); + checkIsValid(value2Selector); + }); }); }); }); diff --git a/packages/eui/src/components/form/field_number/field_number.tsx b/packages/eui/src/components/form/field_number/field_number.tsx index 2e648b9cdee..28129bd1ae5 100644 --- a/packages/eui/src/components/form/field_number/field_number.tsx +++ b/packages/eui/src/components/form/field_number/field_number.tsx @@ -132,7 +132,7 @@ export const EuiFieldNumber: FunctionComponent = ( if (_inputRef.current) { checkNativeValidity(_inputRef.current); } - }, [value, min, max, step, checkNativeValidity]); + }, [isInvalid, value, min, max, step, checkNativeValidity]); const classes = classNames('euiFieldNumber', className, { 'euiFieldNumber-isLoading': isLoading,