Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiFieldNumber] Improve step validation #7202

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`EuiFieldNumber is rendered 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="false"
icon="warning"
inputid="1"
isloading="false"
<div
class="euiFormControlLayout"
>
<eui-validatable-control>
<div
class="euiFormControlLayout__childrenWrapper"
>
<div
class="euiFormControlLayoutIcons euiFormControlLayoutIcons--left euiFormControlLayoutIcons--absolute"
>
<span
class="euiFormControlLayoutCustomIcon"
>
<span
aria-hidden="true"
class="euiFormControlLayoutCustomIcon__icon"
data-euiicon-type="warning"
/>
</span>
</div>
<input
aria-label="aria-label"
class="euiFieldNumber testClass1 testClass2 emotion-euiTestCss euiFieldNumber--withIcon"
Expand All @@ -21,47 +32,42 @@ exports[`EuiFieldNumber is rendered 1`] = `
type="number"
value="1"
/>
</eui-validatable-control>
</eui-form-control-layout>
</div>
</div>
`;

exports[`EuiFieldNumber props controlOnly is rendered 1`] = `
<eui-validatable-control>
<input
class="euiFieldNumber"
step="any"
type="number"
value=""
/>
</eui-validatable-control>
<input
class="euiFieldNumber"
step="any"
type="number"
value=""
/>
`;

exports[`EuiFieldNumber props fullWidth is rendered 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="true"
isloading="false"
<div
class="euiFormControlLayout euiFormControlLayout--fullWidth"
>
<eui-validatable-control>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
class="euiFieldNumber euiFieldNumber--fullWidth"
step="any"
type="number"
value=""
/>
</eui-validatable-control>
</eui-form-control-layout>
</div>
</div>
`;

exports[`EuiFieldNumber props isInvalid is rendered from a prop 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="false"
isinvalid="true"
isloading="false"
<div
class="euiFormControlLayout"
>
<eui-validatable-control
isinvalid="true"
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-invalid="true"
Expand All @@ -70,76 +76,92 @@ exports[`EuiFieldNumber props isInvalid is rendered from a prop 1`] = `
type="number"
value=""
/>
</eui-validatable-control>
</eui-form-control-layout>
<div
class="euiFormControlLayoutIcons euiFormControlLayoutIcons--right euiFormControlLayoutIcons--absolute"
>
<span
color="danger"
data-euiicon-type="warning"
/>
</div>
</div>
</div>
`;

exports[`EuiFieldNumber props isLoading is rendered 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="false"
isloading="true"
<div
class="euiFormControlLayout"
>
<eui-validatable-control>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
class="euiFieldNumber euiFormControlLayout--1icons euiFieldNumber-isLoading"
step="any"
type="number"
value=""
/>
</eui-validatable-control>
</eui-form-control-layout>
<div
class="euiFormControlLayoutIcons euiFormControlLayoutIcons--right euiFormControlLayoutIcons--absolute"
>
<span
aria-label="Loading"
class="euiLoadingSpinner emotion-euiLoadingSpinner-m"
role="progressbar"
/>
</div>
</div>
</div>
`;

exports[`EuiFieldNumber props readOnly is rendered 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="false"
isloading="false"
readonly="true"
<div
class="euiFormControlLayout euiFormControlLayout--readOnly"
>
<eui-validatable-control>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
class="euiFieldNumber"
readonly=""
step="any"
type="number"
value=""
/>
</eui-validatable-control>
</eui-form-control-layout>
</div>
</div>
`;

exports[`EuiFieldNumber props value no initial value 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="false"
isloading="false"
<div
class="euiFormControlLayout"
>
<eui-validatable-control>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
class="euiFieldNumber"
step="any"
type="number"
value=""
/>
</eui-validatable-control>
</eui-form-control-layout>
</div>
</div>
`;

exports[`EuiFieldNumber props value value is number 1`] = `
<eui-form-control-layout
compressed="false"
fullwidth="false"
isloading="false"
<div
class="euiFormControlLayout"
>
<eui-validatable-control>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
class="euiFieldNumber"
step="any"
type="number"
value="0"
/>
</eui-validatable-control>
</eui-form-control-layout>
</div>
</div>
`;
91 changes: 75 additions & 16 deletions src/components/form/field_number/field_number.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ import React from 'react';
import { EuiFieldNumber } from './field_number';

describe('EuiFieldNumber', () => {
describe('isNativelyInvalid', () => {
const checkIsValid = () => {
cy.get('[aria-invalid="true"]').should('not.exist');
cy.get('.euiFormControlLayoutIcons').should('not.exist');
};
const checkIsInvalid = () => {
cy.get('[aria-invalid="true"]').should('exist');
cy.get('.euiFormControlLayoutIcons').should('exist');
};
const checkIsValid = () => {
cy.get('[aria-invalid="true"]').should('not.exist');
cy.get('.euiFormControlLayoutIcons').should('not.exist');
};
const checkIsInvalid = () => {
cy.get('[aria-invalid="true"]').should('exist');
cy.get('.euiFormControlLayoutIcons').should('exist');
};

describe('isNativelyInvalid', () => {
it('when the value is not a valid number', () => {
cy.mount(<EuiFieldNumber />);
checkIsValid();
Expand All @@ -45,26 +45,85 @@ describe('EuiFieldNumber', () => {
checkIsInvalid();
});

it('sets invalid state when the value is not a valid step', () => {
cy.mount(<EuiFieldNumber step={3} />);
checkIsValid();
cy.get('input').click().type('2');
checkIsInvalid();
});

it('shows invalid state on blur', () => {
cy.mount(<EuiFieldNumber max={1} value={2} />);
checkIsValid();
cy.get('input').click();
cy.get('body').click('bottomRight');
checkIsInvalid();
});
});

describe('isStepInvalid', () => {
const checkHasInvalidMessage = (message: string) => {
cy.get('input[type="number"]').should(($el) => {
const inputEl = $el[0] as HTMLInputElement;
expect(inputEl.validationMessage).to.equal(message);
});
};

it('does not show invalid state on decimal values by default', () => {
cy.mount(<EuiFieldNumber />);
checkIsValid();
cy.get('input').click().type('1.5');
checkIsValid();
});

it('shows invalid state on user input', () => {
cy.mount(<EuiFieldNumber step={1} />);
checkIsValid();
cy.get('input').click().type('1.5');
cy.get('body').click('bottomRight');
checkIsInvalid();
checkHasInvalidMessage(
'Please enter a valid value. The two nearest valid values are 1 and 2.'
);
});

it('restores valid state when step is corrected', () => {
cy.mount(<EuiFieldNumber step={3} />);
checkIsValid();
cy.get('input').click().type('2');
checkIsInvalid();
cy.realType('{backspace}3');
checkIsValid();
});

describe('invalid step/values on mount', () => {
beforeEach(() => {
cy.window().then((win) => {
cy.wrap(cy.spy(win.console, 'warn')).as('spyConsoleWarn');
});
});

it('warns and does not validate step if an invalid step/value combo is passed', () => {
cy.mount(<EuiFieldNumber step={10} value={5} />);
checkIsValid();
cy.get('@spyConsoleWarn').should(
'be.calledOnceWith',
'Disabling step validity checking. The passed `step` value does not match the initial component value.'
);
});

it('warns and does not validate step if an invalid step/defaultValue combo is passed', () => {
cy.mount(<EuiFieldNumber step={3} defaultValue={4} />);
checkIsValid();

// Default browser behavior: browsers will automatically adjust the valid internal `step` value
cy.get('input').click().type('{backspace}2');
checkIsInvalid();
checkHasInvalidMessage(
'Please enter a valid value. The two nearest valid values are 1 and 4.'
);
cy.get('input').click().type('{backspace}7');
checkIsValid();

// Console warn should only have been called once on mount
cy.get('@spyConsoleWarn').should(
'be.calledOnceWith',
'Disabling step validity checking. The passed `step` value does not match the initial component value.'
);
});
});
});
});
11 changes: 0 additions & 11 deletions src/components/form/field_number/field_number.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,6 @@ import { requiredProps } from '../../../test/required_props';
import { EuiForm } from '../form';
import { EuiFieldNumber } from './field_number';

jest.mock('../form_control_layout', () => {
const formControlLayout = jest.requireActual('../form_control_layout');
return {
...formControlLayout,
EuiFormControlLayout: 'eui-form-control-layout',
};
});
jest.mock('../validatable_control', () => ({
EuiValidatableControl: 'eui-validatable-control',
}));

describe('EuiFieldNumber', () => {
test('is rendered', () => {
const { container } = render(
Expand Down
Loading
Loading