Skip to content
Open
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
15 changes: 8 additions & 7 deletions src/lib/core/components/Form/types/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ export type NumberLayoutProps<
NumberSpec<undefined, InputComponentProps, LayoutComponentProps>
>;

export type NumberInput<InputComponentProps extends Record<string, any> | undefined = undefined> =
InputType<
number,
InputComponentProps,
undefined,
NumberSpec<undefined, InputComponentProps, undefined>
>;
export type NumberInputType<
InputComponentProps extends Record<string, any> | undefined = undefined,
> = InputType<
number,
InputComponentProps,
undefined,
NumberSpec<undefined, InputComponentProps, undefined>
>;

export type NumberIndependentInput<
InputComponentProps extends Record<string, any> | undefined = undefined,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions src/lib/kit/components/Inputs/Number/Number.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';

import type {NumberInputProps as NumberInputBaseProps} from '@gravity-ui/uikit';
import {NumberInput as CommonNumberInput} from '@gravity-ui/uikit';
import isNil from 'lodash/isNil';

import type {FieldRenderProps, NumberInputProps, StringInputProps} from '../../../../core';

export interface NumberProps
extends Omit<
NumberInputBaseProps,
'value' | 'onBlur' | 'onFocus' | 'onUpdate' | 'disabled' | 'placeholder' | 'qa'
> {}

export const NumberInput = <
T extends NumberInputProps<NumberProps> | StringInputProps<NumberProps>,
>({
name,
input: {value, onBlur, onChange, onFocus},
spec,
inputProps,
}: T) => {
const props = {
hasClear: true,
...inputProps,
value: isNil(value) ? null : Number(value),
defaultValue: isNil(inputProps?.defaultValue) ? null : Number(inputProps?.defaultValue),
onBlur: onBlur,
onFocus: onFocus,
onUpdate: onChange as FieldRenderProps<string | undefined>['input']['onChange'],
disabled: spec.viewSpec.disabled,
placeholder: spec.viewSpec.placeholder,
qa: name,
};

const handleUpdate = (value: number | null) => {
props.onUpdate(value !== null ? `${value}` : undefined);
};

return <CommonNumberInput {...props} onUpdate={handleUpdate} allowDecimal />;
};
159 changes: 159 additions & 0 deletions src/lib/kit/components/Inputs/Number/__tests__/Number.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import React from 'react';

import {ThemeProvider} from '@gravity-ui/uikit';
import {render, screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import cloneDeep from 'lodash/cloneDeep';
import noop from 'lodash/noop';
import {Form} from 'react-final-form';

import type {NumberSpec, Spec} from '../../../../../core';
import {DynamicField, SpecTypes} from '../../../../../core';
import {dynamicConfig} from '../../../../constants';

const NAME = 'input';

const PLACEHOLDER = 'placeholder text';

const SPEC_NUMBER: NumberSpec = {
type: SpecTypes.Number,
required: true,
viewSpec: {
type: 'base',
layout: 'row',
layoutTitle: 'Age',
placeholder: PLACEHOLDER,
},
};

const DynamicForm = ({spec}: {spec: Spec}) => (
<ThemeProvider>
<Form initialValues={{}} onSubmit={noop}>
{() => <DynamicField name={NAME} spec={spec} config={dynamicConfig} />}
</Form>
</ThemeProvider>
);

beforeEach(() => {
window.matchMedia = () => ({
media: '',
matches: false,
onchange: () => {},
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: (_) => true,
});
});

describe('Text input', () => {
test('input display check', () => {
render(<DynamicForm spec={SPEC_NUMBER} />);

const input = screen.getByPlaceholderText(PLACEHOLDER);

expect(input).toBeVisible();
});

test('checking value change, focus, deleting input value in Number spec', async () => {
render(<DynamicForm spec={SPEC_NUMBER} />);

const user = userEvent.setup();
const input = screen.getByPlaceholderText(PLACEHOLDER);

expect(input).not.toHaveFocus();

await user.click(input);

expect(input).toHaveFocus();

await user.keyboard('1');

expect(input).toHaveValue('1');

await user.type(input, '{backspace}');

expect(input).toHaveValue('');
});

test('check button clear', async () => {
render(<DynamicForm spec={SPEC_NUMBER} />);

const user = userEvent.setup();
const input = screen.getByPlaceholderText(PLACEHOLDER);

let clearButton = screen.queryByRole('button', {name: 'Clear'});

expect(clearButton).not.toBeInTheDocument();

await user.click(input);
await user.keyboard('1');

clearButton = screen.queryByRole('button', {name: 'Clear'});

expect(clearButton).toBeInTheDocument();

if (clearButton) {
await user.click(clearButton);
}

expect(input).toHaveValue('');
expect(clearButton).not.toBeInTheDocument();
});

test('checking default values Number spec', async () => {
const spec = cloneDeep(SPEC_NUMBER);
spec.defaultValue = 123;

render(<DynamicForm spec={spec} />);

const input = screen.getByPlaceholderText(PLACEHOLDER);

expect(input).toHaveValue('123');
});

test('disabled input check', async () => {
const spec = cloneDeep(SPEC_NUMBER);
spec.viewSpec.disabled = true;

render(<DynamicForm spec={spec} />);

const user = userEvent.setup();
const input = screen.getByPlaceholderText(PLACEHOLDER);

await user.click(input);

expect(input).not.toHaveFocus();
expect(input).toBeDisabled();
});

test('error message check in Number spec', async () => {
const {container} = render(<DynamicForm spec={SPEC_NUMBER} />);

const user = userEvent.setup();
const input = screen.getByPlaceholderText(PLACEHOLDER);

await user.click(input);
await user.keyboard('1');

expect(input).toHaveValue('1');

const clearButton = screen.queryByRole('button', {name: 'Clear'});

expect(clearButton).toBeInTheDocument();

if (clearButton) {
await user.click(clearButton);
}

expect(input).toHaveValue('');
expect(container.querySelector('.df-error-wrapper__error-text')).toBeInTheDocument();
expect(screen.getByText('Empty field')).toBeVisible();

await user.keyboard('1');

expect(input).toHaveValue('1');
expect(container.querySelector('.df-error-wrapper__error-text')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';

import {test} from '~playwright/core';
import {DynamicForm} from '~playwright/core/DynamicForm';

import {NUMBER_SPEC} from './helpers';

test.describe('Text Input', () => {
test.describe('Number spec', () => {
test('default', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.default} />);

await expectScreenshot();
});

test('required', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.required} />);

await expectScreenshot();
});

test('disabled', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.disabled} />);

await expectScreenshot();
});

test('description', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.description} />);

await expectScreenshot();
});

test('hidden', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.hidden} />);

await expectScreenshot();
});

test('layout row verbose', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.layoutRowVerbose} />);

await expectScreenshot();
});

test('layout table item', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.layoutTableItem} />);

await expectScreenshot();
});

test('layout transperant', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.layoutTransparent} />);

await expectScreenshot();
});

test('default value', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={NUMBER_SPEC.defaultValue} />);

await expectScreenshot();
});
});
});
92 changes: 92 additions & 0 deletions src/lib/kit/components/Inputs/Number/__tests__/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type {NumberSpec} from '../../../../../core';
import {SpecTypes} from '../../../../../core';

export const NUMBER_SPEC: Record<string, NumberSpec> = {
default: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'row',
layoutTitle: 'Age',
placeholder: 'placeholder text',
},
},
required: {
type: SpecTypes.Number,
required: true,
viewSpec: {
type: 'base',
layout: 'row',
layoutTitle: 'Age',
placeholder: 'placeholder text',
},
},
disabled: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'row',
layoutTitle: 'Age',
placeholder: 'placeholder text',
disabled: true,
},
},
description: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'row',
layoutTitle: 'Age',
placeholder: 'placeholder text',
layoutDescription: 'description',
},
},
hidden: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'row',
layoutTitle: 'Age',
placeholder: 'placeholder text',
hidden: true,
},
},
layoutRowVerbose: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'row_verbose',
layoutTitle: 'Age',
placeholder: 'placeholder text',
layoutDescription: 'description',
},
},
layoutTableItem: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'table_item',
layoutTitle: 'Age',
placeholder: 'placeholder text',
},
},
layoutTransparent: {
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'transparent',
layoutTitle: 'Age',
placeholder: 'placeholder text',
},
},
defaultValue: {
defaultValue: 12,
type: SpecTypes.Number,
viewSpec: {
type: 'base',
layout: 'transparent',
layoutTitle: 'Age',
placeholder: 'placeholder text',
},
},
};
1 change: 1 addition & 0 deletions src/lib/kit/components/Inputs/Number/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Number';
Loading