Skip to content

Commit

Permalink
Add tests for React component 'UnitInputField'
Browse files Browse the repository at this point in the history
* Add snapshots covering default params and disabled view
* Add interactive tests to verify onChange and input validation
  functions are called
  • Loading branch information
bastian-src committed Feb 11, 2025
1 parent f00377d commit 96af3f1
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React from 'react';
import '@testing-library/jest-dom';
import { TextInput } from '@patternfly/react-core';
import {
render,
waitFor,
waitForElementToBeRemoved,
screen,
act,
fireEvent,
} from '@testing-library/react';

import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
import LabelIcon from 'foremanReact/components/common/LabelIcon';

import UnitInputField from '../UnitInputField';

const getDefaultProps = () => ({
initialValue: 0,
onChange: jest.fn(),
isDisabled: false,
handleInputValidation: jest.fn(),
units: [
{ symbol: 'MiB', factor: 1 },
{ symbol: 'GiB', factor: 1024 },
],
labelIcon: <LabelIcon text="Descriptive title." />,
minValue: 0,
maxValue: 5,
});

const fixtureDefault = {
'should render default': {
...getDefaultProps(),
},
};

const fixtureSingleUnit = {
'should render without dropdown (single unit)': {
...getDefaultProps(),
units: [{ symbol: 'cores', factor: 1 }],
},
};

const fixtureDisabled = {
'should render as disabled field': {
...getDefaultProps(),
isDisabled: true,
},
};

describe('UnitInputField', () => {
testComponentSnapshotsWithFixtures(UnitInputField, fixtureDefault);
testComponentSnapshotsWithFixtures(UnitInputField, fixtureSingleUnit);
testComponentSnapshotsWithFixtures(UnitInputField, fixtureDisabled);

it('triggers handleInputValidation on unit change', async () => {
const props = getDefaultProps();

render(<UnitInputField {...props} />);
const input = screen.getByRole('textbox');
fireEvent.change(input, { target: { value: 3 } });

// gets called (1.) with initialValue and (2.) the simulated change
expect(props.onChange).toHaveBeenCalledTimes(2);
expect(props.onChange).toHaveBeenCalledWith(props.initialValue);
expect(props.onChange).toHaveBeenLastCalledWith(3);
expect(props.handleInputValidation).toHaveBeenCalledTimes(2);
expect(props.handleInputValidation).toHaveBeenCalledWith(true);
});

test('triggers onChange with rounded value', () => {
const props = getDefaultProps();

render(<UnitInputField {...props} />);
const input = screen.getByRole('textbox');
fireEvent.change(input, { target: { value: 3.5 } });

// gets called (1.) with initialValue and (2.) the simulated change
expect(props.onChange).toHaveBeenCalledTimes(2);
expect(props.onChange).toHaveBeenCalledWith(props.initialValue);
expect(props.onChange).toHaveBeenLastCalledWith(3);
expect(props.handleInputValidation).toHaveBeenCalledTimes(2);
expect(props.handleInputValidation).toHaveBeenCalledWith(true);
});

test('does not trigger onChange when value out of bounds', () => {
const props = getDefaultProps();

render(<UnitInputField {...props} />);
const input = screen.getByRole('textbox');
fireEvent.change(input, { target: { value: props.maxValue + 1 } });

// onChange only called for initialValue
expect(props.onChange).toHaveBeenCalledTimes(1);
expect(props.onChange).toHaveBeenCalledWith(props.initialValue);
// handleInputValidation called with false => invalid
expect(props.handleInputValidation).toHaveBeenCalledTimes(2);
expect(props.handleInputValidation).toHaveBeenLastCalledWith(false);
});

test('does not trigger onChange when value is not a number', () => {
const props = getDefaultProps();

render(<UnitInputField {...props} />);
const input = screen.getByRole('textbox');
fireEvent.change(input, { target: { value: 'no number' } });

// onChange only called for initialValue
expect(props.onChange).toHaveBeenCalledTimes(1);
expect(props.onChange).toHaveBeenCalledWith(props.initialValue);
// handleInputValidation called with false => invalid
expect(props.handleInputValidation).toHaveBeenCalledTimes(2);
expect(props.handleInputValidation).toHaveBeenLastCalledWith(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`UnitInputField should render as disabled field 1`] = `
<FormGroup
fieldId="quota-limit-resource-quota-form-group"
helperText={
<FormHelperText
isHidden={true}
>
</FormHelperText>
}
helperTextInvalid=""
label="Quota Limit"
labelIcon={
<LabelIcon
text="Descriptive title."
/>
}
validated="default"
>
<InputGroup>
<TextInput
id="reg_token_life_time_input"
isDisabled={true}
max={5}
min={0}
onChange={[Function]}
validated="default"
value={0}
/>
<Dropdown
dropdownItems={
Array [
<DropdownItem
id="unit-dropdownitem-mib"
>
MiB
</DropdownItem>,
<DropdownItem
id="unit-dropdownitem-gib"
>
GiB
</DropdownItem>,
]
}
isOpen={false}
onSelect={[Function]}
toggle={
<DropdownToggle
isDisabled={true}
onToggle={[Function]}
>
MiB
</DropdownToggle>
}
/>
</InputGroup>
</FormGroup>
`;

exports[`UnitInputField should render default 1`] = `
<FormGroup
fieldId="quota-limit-resource-quota-form-group"
helperText={
<FormHelperText
isHidden={true}
>
</FormHelperText>
}
helperTextInvalid=""
label="Quota Limit"
labelIcon={
<LabelIcon
text="Descriptive title."
/>
}
validated="default"
>
<InputGroup>
<TextInput
id="reg_token_life_time_input"
isDisabled={false}
max={5}
min={0}
onChange={[Function]}
validated="default"
value={0}
/>
<Dropdown
dropdownItems={
Array [
<DropdownItem
id="unit-dropdownitem-mib"
>
MiB
</DropdownItem>,
<DropdownItem
id="unit-dropdownitem-gib"
>
GiB
</DropdownItem>,
]
}
isOpen={false}
onSelect={[Function]}
toggle={
<DropdownToggle
isDisabled={false}
onToggle={[Function]}
>
MiB
</DropdownToggle>
}
/>
</InputGroup>
</FormGroup>
`;

exports[`UnitInputField should render without dropdown (single unit) 1`] = `
<FormGroup
fieldId="quota-limit-resource-quota-form-group"
helperText={
<FormHelperText
isHidden={true}
>
</FormHelperText>
}
helperTextInvalid=""
label="Quota Limit"
labelIcon={
<LabelIcon
text="Descriptive title."
/>
}
validated="default"
>
<InputGroup>
<TextInput
id="reg_token_life_time_input"
isDisabled={false}
max={5}
min={0}
onChange={[Function]}
validated="default"
value={0}
/>
<InputGroupText>
cores
</InputGroupText>
</InputGroup>
</FormGroup>
`;

0 comments on commit 96af3f1

Please sign in to comment.