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

fix(Slider): onRelease not always firing (#2695) #5359

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -175,8 +175,8 @@
],
"testMatch": [
"<rootDir>/**/__tests__/**/*.js?(x)",
"<rootDir>/**/?(*.)(spec|test).js?(x)",
"<rootDir>/**/?(*-)(spec|test).js?(x)"
"<rootDir>/**/*.(spec|test).js?(x)",
"<rootDir>/**/*-(spec|test).js?(x)"
],
"transform": {
"^.+\\.(js|jsx)$": "./tasks/jest/jsTransform.js",
Expand Down
1 change: 0 additions & 1 deletion packages/components/src/components/slider/_slider.scss
Expand Up @@ -117,7 +117,6 @@
.#{$prefix}-slider-text-input {
width: rem(64px);
height: rem(40px);
padding: 0;
text-align: center;
-moz-appearance: textfield;

Expand Down
2 changes: 1 addition & 1 deletion packages/icon-build-helpers/src/search.js
Expand Up @@ -55,7 +55,7 @@ async function search(directory) {
const dirname = path.dirname(filepath);
const prefix = path
.relative(directory, dirname)
.split('/')
.split(path.sep)
.filter(Boolean);
return {
...file,
Expand Down
1 change: 1 addition & 0 deletions packages/react/package.json
Expand Up @@ -47,6 +47,7 @@
"lodash.findlast": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.omit": "^4.5.0",
"lodash.throttle": "^4.1.1",
"react-is": "^16.8.6",
"warning": "^3.0.0",
"window-or-global": "^1.0.1"
Expand Down
221 changes: 208 additions & 13 deletions packages/react/src/components/Slider/Slider-test.js
Expand Up @@ -15,9 +15,10 @@ import { settings } from 'carbon-components';
const { prefix } = settings;
describe('Slider', () => {
describe('Renders as expected', () => {
const id = 'slider';
const wrapper = mount(
<Slider
id="slider"
id={id}
className="extra-class"
value={50}
min={0}
Expand Down Expand Up @@ -55,6 +56,20 @@ describe('Slider', () => {
wrapper.setProps({ light: true });
expect(wrapper.props().light).toEqual(true);
});

it('marks input field as hidden if hidden via props', () => {
wrapper.setProps({ hideTextInput: true });
expect(wrapper.find(`#${id}-input-for-slider`).props().type).toEqual(
'hidden'
);
});

it('sets style to display:none on input field if hidden via props', () => {
wrapper.setProps({ hideTextInput: true });
expect(wrapper.find(`#${id}-input-for-slider`).props().style).toEqual({
display: 'none',
});
});
});

describe('Supporting label', () => {
Expand Down Expand Up @@ -102,7 +117,7 @@ describe('Slider', () => {
});
});

describe('updatePosition method', () => {
describe('key/mouse event processing', () => {
const handleChange = jest.fn();
const handleRelease = jest.fn();
const wrapper = mount(
Expand All @@ -113,6 +128,7 @@ describe('Slider', () => {
min={0}
max={100}
step={1}
stepMultiplier={5}
onChange={handleChange}
onRelease={handleRelease}
/>
Expand All @@ -123,38 +139,78 @@ describe('Slider', () => {
type: 'keydown',
which: '38',
};
wrapper.instance().updatePosition(evt);
expect(handleChange).lastCalledWith({ value: 51 });
wrapper.instance().onKeyDown(evt);
expect(wrapper.state().value).toEqual(51);
expect(handleChange).lastCalledWith({ value: 51 });
});

it('sets correct state from event with a left/down keydown', () => {
const evt = {
type: 'keydown',
which: '40',
};
wrapper.instance().updatePosition(evt);
expect(handleChange).lastCalledWith({ value: 50 });
wrapper.instance().onKeyDown(evt);
expect(wrapper.state().value).toEqual(50);
expect(handleChange).lastCalledWith({ value: 50 });
});

it('sets correct state from event with a clientX', () => {
it('correctly uses setMultiplier with a right/up keydown', () => {
const evt = {
type: 'click',
type: 'keydown',
which: '38',
shiftKey: true,
};
wrapper.instance().onKeyDown(evt);
expect(wrapper.state().value).toEqual(55);
expect(handleChange).lastCalledWith({ value: 55 });
});

it('sets correct state from event with a clientX in a mousemove', () => {
const evt = {
type: 'mousemove',
clientX: '1000',
};
wrapper.instance().updatePosition(evt);
wrapper.instance()._onDrag(evt);
expect(handleChange).lastCalledWith({ value: 100 });
expect(wrapper.state().value).toEqual(100);
});

it('sets correct state from event with a clientX in a touchmove', () => {
const evt = {
type: 'touchmove',
touches: [{ clientX: '0' }],
};
wrapper.instance()._onDrag(evt);
expect(handleChange).lastCalledWith({ value: 0 });
expect(wrapper.state().value).toEqual(0);
});

it('throttles mousemove events', () => {
const evt1 = {
type: 'mousemove',
clientX: '1000',
};
const evt2 = {
type: 'mousemove',
clientX: '0',
};
wrapper.instance().onDrag(evt1);
wrapper.instance().onDrag(evt2);
expect(wrapper.state().value).toEqual(100);
expect(handleChange).lastCalledWith({ value: 100 });
});

describe('user is holding the handle', () => {
it('does not call onRelease', () => {
const evt = {
type: 'mousemove',
clientX: '1000',
};
handleRelease.mockClear();
expect(handleRelease).not.toHaveBeenCalled();

wrapper.instance().handleMouseStart();
wrapper.instance().updatePosition();
wrapper.instance().onDragStart(evt);
wrapper.instance().onDrag(evt);
expect(handleRelease).not.toHaveBeenCalled();
});
});
Expand All @@ -164,12 +220,151 @@ describe('Slider', () => {
handleRelease.mockClear();
expect(handleRelease).not.toHaveBeenCalled();
wrapper.setState({
holding: false,
needsOnRelease: true,
});
wrapper.instance().updatePosition();
wrapper.instance().onDragStop();
expect(handleRelease).toHaveBeenCalled();
});
});

it('sets correct state when typing in input field', () => {
const evt = {
target: {
value: '999',
},
};
wrapper.instance().onChange(evt);
expect(wrapper.state().value).toEqual(100);
expect(handleChange).lastCalledWith({ value: 100 });
});
});

describe('error handling', () => {
const handleChange = jest.fn();
const handleRelease = jest.fn();
const wrapper = mount(
<Slider
id="slider"
className="extra-class"
value={50}
min={0}
max={100}
step={1}
onChange={handleChange}
onRelease={handleRelease}
/>
);

it('handles non-number typed into input field', () => {
const evt = {
target: {
value: '',
},
};
wrapper.instance().onChange(evt);
expect(wrapper.state().value).toEqual('');
expect(handleChange).not.toHaveBeenCalled();
});

it('gracefully tolerates empty event passed to _onDrag', () => {
const evt = {};
wrapper.instance()._onDrag(evt);
expect(wrapper.state().value).toEqual(''); // from last test
expect(handleChange).not.toHaveBeenCalled();
});

it('gracefully tolerates empty event passed to onChange', () => {
const evt = {};
wrapper.instance().onChange(evt);
expect(wrapper.state().value).toEqual(''); // from last test
expect(handleChange).not.toHaveBeenCalled();
});

it('gracefully tolerates empty event passed to onKeyDown', () => {
const evt = {};
wrapper.instance().onKeyDown(evt);
expect(wrapper.state().value).toEqual(''); // from last test
expect(handleChange).not.toHaveBeenCalled();
});

it('gracefully tolerates bad key code passed to onKeyDown', () => {
const evt = {
which: '123',
};
wrapper.instance().onKeyDown(evt);
expect(wrapper.state().value).toEqual(''); // from last test
expect(handleChange).not.toHaveBeenCalled();
});
});

describe('slider is disabled', () => {
const handleChange = jest.fn();
const handleRelease = jest.fn();
const wrapper = mount(
<Slider
id="slider"
className="extra-class"
value={50}
min={0}
max={100}
step={1}
onChange={handleChange}
onRelease={handleRelease}
disabled={true}
/>
);

it('does nothing when trying to type in the input', () => {
const evt = {
target: {
value: '',
},
};
wrapper.instance().onChange(evt);
expect(wrapper.state().value).toEqual(50);
expect(handleChange).not.toHaveBeenCalled();
});

it('does nothing when trying to start a drag', () => {
const evt = {
type: 'mousedown',
clientX: '1001',
};
wrapper.instance().onDragStart(evt);
expect(wrapper.state().value).toEqual(50);
expect(handleChange).not.toHaveBeenCalled();
});

it('does nothing when trying to drag', () => {
const evt = {
type: 'mousemove',
clientX: '1000',
};
wrapper.instance()._onDrag(evt);
expect(wrapper.state().value).toEqual(50);
expect(handleChange).not.toHaveBeenCalled();
});

it('does nothing when trying to stop a drag', () => {
const evt = {
type: 'mouseup',
clientX: '1001',
};
wrapper.instance().onDragStop(evt);
expect(wrapper.state().needsOnRelease).toEqual(false);
expect(handleChange).not.toHaveBeenCalled();
expect(handleRelease).not.toHaveBeenCalled();
});

it('does nothing when using arrow key', () => {
const evt = {
type: 'keydown',
which: '40',
};
wrapper.instance().onKeyDown(evt);
expect(wrapper.state().value).toEqual(50);
expect(handleChange).not.toHaveBeenCalled();
});
});
});

Expand Down