Skip to content

Commit

Permalink
feat: add Slider component (#190)
Browse files Browse the repository at this point in the history
* feat: add Slider component

* chore: update test snapshots

* chore: address PR feedback

* fix: ensure marker and thumb align

* fix: eliminate race condition in Slider

* chore: clean up testing output

* fix: cleanup build errors

Co-authored-by: phrough <[email protected]>
  • Loading branch information
jhoward-eightfold and phrough authored Jun 22, 2022
1 parent 3bdb62c commit 30a8229
Show file tree
Hide file tree
Showing 15 changed files with 686 additions and 37 deletions.
16 changes: 16 additions & 0 deletions config/jest/identity-obj-proxy-revised.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Proxy for jest tests to convert css moodule class names.
// Based on https://medium.com/trabe/testing-css-modules-in-react-components-with-jest-enzyme-and-a-custom-modulenamemapper-8ff86c7d18a2

module.exports = new Proxy(
{},
{
get: function getter(target, key) {
if (key === '__esModule') {
return false;
}

// Convert camelCase to kebab-case for class selectors in unit tests.
return key.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
},
}
);
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@
"html-webpack-plugin": "5.5.0",
"husky": "7.0.4",
"icomoon-react": "^3.0.0",
"identity-obj-proxy": "3.0.0",
"install-peers": "1.0.3",
"install-peers-cli": "2.2.0",
"jest": "27.4.3",
Expand Down Expand Up @@ -209,7 +208,7 @@
"modulePaths": [],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
"^.+\\.module\\.(css|sass|scss)$": "<rootDir>/config/jest/identity-obj-proxy-revised.js"
},
"moduleFileExtensions": [
"web.js",
Expand Down
10 changes: 5 additions & 5 deletions src/components/Dialog/Dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ describe('Dialog', () => {
onCancel,
onClose,
});
wrapper.find('.buttonPrimary').at(0).simulate('click');
wrapper.find('.buttonDefault').at(0).simulate('click');
wrapper.find('.buttonNeutral').at(0).simulate('click');
wrapper.find('.dialogBackdrop').at(0).simulate('click');
wrapper.find('.button-primary').at(0).simulate('click');
wrapper.find('.button-default').at(0).simulate('click');
wrapper.find('.button-neutral').at(0).simulate('click');
wrapper.find('.dialog-backdrop').at(0).simulate('click');

expect(onOk).toHaveBeenCalledTimes(1);
expect(onCancel).toHaveBeenCalledTimes(1);
Expand All @@ -76,7 +76,7 @@ describe('Dialog', () => {
maskClosable: false,
});

wrapper.find('.dialogBackdrop').at(0).simulate('click');
wrapper.find('.dialog-backdrop').at(0).simulate('click');
expect(onClose).toHaveBeenCalledTimes(2);
});
});
6 changes: 3 additions & 3 deletions src/components/Modal/Modal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ describe('Modal', () => {
body,
onClose,
});
wrapper.find('.buttonNeutral').at(0).simulate('click');
wrapper.find('.dialogBackdrop').at(0).simulate('click');
wrapper.find('.button-neutral').at(0).simulate('click');
wrapper.find('.dialog-backdrop').at(0).simulate('click');

expect(onClose).toHaveBeenCalledTimes(2);

wrapper.setProps({
maskClosable: false,
});

wrapper.find('.dialogBackdrop').at(0).simulate('click');
wrapper.find('.dialog-backdrop').at(0).simulate('click');
expect(onClose).toHaveBeenCalledTimes(2);
});
});
6 changes: 3 additions & 3 deletions src/components/Panel/Panel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ describe('Panel', () => {
visible: true,
onClose,
});
wrapper.find('.panelBackdrop').at(0).simulate('click');
wrapper.find('.panel-backdrop').at(0).simulate('click');

wrapper.find('.buttonNeutral').at(0).simulate('click');
wrapper.find('.button-neutral').at(0).simulate('click');
expect(onClose).toHaveBeenCalledTimes(2);

wrapper.setProps({
maskClosable: false,
});
wrapper.find('.panelBackdrop').at(0).simulate('click');
wrapper.find('.panel-backdrop').at(0).simulate('click');
expect(onClose).toHaveBeenCalledTimes(2);
});
});
47 changes: 47 additions & 0 deletions src/components/Slider/Slider.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { ComponentMeta, ComponentStory } from '@storybook/react';

import { Slider } from './';

export default {
title: 'Slider',
component: Slider,
} as ComponentMeta<typeof Slider>;

const Slider_Story: ComponentStory<typeof Slider> = (args) => (
<Slider {...args} />
);

const sliderArgs: Object = {
ariaLabel: 'Slider',
autoFocus: false,
classNames: 'my-slider',
disabled: false,
id: 'mySliderId',
min: 100,
max: 200,
name: 'mySlider',
onChange: () => {
// handle change.
},
};

export const StandardSlider = Slider_Story.bind({});
StandardSlider.args = {
...sliderArgs,
autoFocus: true,
min: 1,
max: 5,
showLabels: false,
value: 2,
};

export const RangeSlider = Slider_Story.bind({});
RangeSlider.args = {
...sliderArgs,
min: 0,
showLabels: true,
showMarkers: true,
step: 10,
value: [110, 150],
};
88 changes: 88 additions & 0 deletions src/components/Slider/Slider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import Enzyme, { mount, ReactWrapper } from 'enzyme';
import MatchMediaMock from 'jest-matchmedia-mock';

import { Slider } from './';

Enzyme.configure({ adapter: new Adapter() });

let matchMedia: any;

describe('Slider', () => {
let wrapper: ReactWrapper;

beforeAll(() => {
matchMedia = new MatchMediaMock();
});
afterEach(() => {
matchMedia.clear();
});

test('Should render', () => {
wrapper = mount(<Slider min={20} max={40} value={30} />);
expect(wrapper.children().length).toEqual(1);
});

test('should correctly display markers and indicate when they are active', () => {
let markers;
let activeMarkers;

wrapper = mount(
<Slider min={20} max={40} value={30} showMarkers={true} />
);
markers = wrapper.find('.rail-marker');
expect(markers.length).toEqual(19);
activeMarkers = wrapper.find('.rail-marker.active');
expect(activeMarkers.length).toEqual(10);

wrapper = mount(
<Slider
min={0}
max={40}
step={10}
value={[10, 20]}
showMarkers={true}
/>
);
markers = wrapper.find('.rail-marker');
expect(markers.length).toEqual(3);
activeMarkers = wrapper.find('.rail-marker.active');
expect(activeMarkers.length).toEqual(2);
});

test('should update values correctly', () => {
let val = 1;
wrapper = mount(
<Slider
min={0}
max={10}
value={val}
onChange={(newVal: number) => (val = newVal)}
/>
);

let thumb = wrapper.find('input[type="range"]').at(0);
expect(thumb.prop('value')).toEqual(1);
thumb.simulate('change', { target: { value: 3 } });
expect(val).toEqual(3);

let vals = [0, 10];
wrapper = mount(
<Slider
min={0}
max={20}
value={vals}
onChange={(newVal: number[]) => (vals = [...newVal])}
/>
);
let thumb1 = wrapper.find('input[type="range"]').at(0);
let thumb2 = wrapper.find('input[type="range"]').at(1);
expect(thumb1.prop('value')).toEqual(0);
expect(thumb2.prop('value')).toEqual(10);
thumb1.simulate('change', { target: { value: 3 } });
thumb2.simulate('change', { target: { value: 7 } });
expect(vals[0]).toEqual(3);
expect(vals[1]).toEqual(7);
});
});
Loading

0 comments on commit 30a8229

Please sign in to comment.