Use Jest 🃏 and upgrade Webpack and other dependencies

old
Javi Velasco 2017-02-06 09:53:31 +01:00
parent 60b147f891
commit b48c17d1ad
19 changed files with 1536 additions and 1326 deletions

View File

@ -1,5 +1,8 @@
{
"extends": "stylelint-config-standard",
"plugins": [
"stylelint-order"
],
"rules": {
"at-rule-no-unknown": [true, {
ignoreAtRules: ["define-mixin", "mixin", "each"]
@ -11,7 +14,11 @@
]
}],
"color-hex-case": "lower",
"declaration-block-properties-order": "alphabetical",
"order/declaration-block-order": [
"custom-properties",
"declarations"
],
"order/declaration-block-properties-alphabetical-order": true,
"font-family-name-quotes": "always-where-recommended",
"string-quotes": "single",
"selector-pseudo-class-no-unknown": [

View File

@ -0,0 +1,7 @@
export function themr() {
return (Component) => {
Component.defaultProps = Component.defaultProps || {}; // eslint-disable-line no-param-reassign
Component.defaultProps.theme = {}; // eslint-disable-line no-param-reassign
return Component;
};
}

View File

@ -1,43 +1,35 @@
/* eslint-disable */
import expect from 'expect';
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import { mount } from 'enzyme';
import { Button } from '../Button';
import theme from '../theme.css';
import Button, { Button as RawButton } from '../Button';
const getRenderedClassName = (tree, Component) => {
const rendered = TestUtils.findRenderedComponentWithType(tree, Component);
return ReactDOM.findDOMNode(rendered).getAttribute('class');
};
describe('Button', () => {
describe('#render', () => {
it('uses flat and neutral styles by default', () => {
const tree = TestUtils.renderIntoDocument(<Button theme={theme} />);
const className = getRenderedClassName(tree, RawButton);
const wrapper = mount(<Button theme={theme} />);
const { className } = wrapper.find('button').props();
expect(className).toContain(theme.flat);
expect(className).toContain(theme.neutral);
});
it('renders accent button with accent style', () => {
const tree = TestUtils.renderIntoDocument(<Button accent theme={theme} />);
const className = getRenderedClassName(tree, RawButton);
const wrapper = mount(<Button accent theme={theme} />);
const { className } = wrapper.find('button').props();
expect(className).toContain(theme.flat);
expect(className).toContain(theme.accent);
});
it('renders mini button with mini style', () => {
const tree = TestUtils.renderIntoDocument(<Button floating mini theme={theme} />);
const className = getRenderedClassName(tree, RawButton);
const wrapper = mount(<Button floating mini theme={theme} />);
const { className } = wrapper.find('button').props();
expect(className).toContain(theme.floating);
expect(className).toContain(theme.neutral);
expect(className).toContain(theme.mini);
});
it('renders mini accented button with both styles', () => {
const tree = TestUtils.renderIntoDocument(<Button accent mini theme={theme} />);
const className = getRenderedClassName(tree, RawButton);
const wrapper = mount(<Button accent mini theme={theme} />);
const { className } = wrapper.find('button').props();
expect(className).toContain(theme.flat);
expect(className).toContain(theme.accent);
expect(className).toContain(theme.mini);

View File

@ -1,12 +1,9 @@
/* eslint-disable */
import expect from 'expect';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-addons-test-utils';
import { mount } from 'enzyme';
import { themr } from 'react-css-themr';
import { CHIP } from '../../identifiers.js';
import { chipFactory } from '../Chip';
import { CHIP } from '../../identifiers';
import { tooltipFactory } from '../../tooltip';
import { chipFactory } from '../Chip';
const Avatar = ({ title }) => <span>{title}</span>; // eslint-disable-line react/prop-types
const Chip = themr(CHIP)(chipFactory(Avatar));
@ -14,40 +11,37 @@ const Chip = themr(CHIP)(chipFactory(Avatar));
describe('Chip', () => {
describe('with avatar', () => {
it('adds the avatar class to the element', () => {
const tree = ReactTestUtils.renderIntoDocument(
const wrapper = mount(
<Chip theme={{ avatar: 'avatar-class' }}>
<Avatar title="Test" />
<span>Test</span>
</Chip>,
);
const chip = ReactTestUtils.findRenderedComponentWithType(tree, Chip);
const chipNode = ReactDOM.findDOMNode(chip);
const chipNode = wrapper.find('div').node;
expect(chipNode.className).toMatch(/\bavatar-class\b/);
});
it('works with non-flat children', () => {
const TooltippedChip = tooltipFactory()(Chip);
const tree = ReactTestUtils.renderIntoDocument(
const wrapper = mount(
<TooltippedChip theme={{ avatar: 'avatar-class' }} tooltip="Test tooltip">
<Avatar title="Test" />
<span>Test</span>
</TooltippedChip>,
);
const chip = ReactTestUtils.findRenderedComponentWithType(tree, Chip);
const chipNode = ReactDOM.findDOMNode(chip);
const chipNode = wrapper.find('div').node;
expect(chipNode.className).toMatch(/\bavatar-class\b/);
});
});
describe('without avatar', () => {
it('does not add avatar class to the element', () => {
const tree = ReactTestUtils.renderIntoDocument(
const wrapper = mount(
<Chip theme={{ avatar: 'avatar-class' }}>
<span>Test</span>
</Chip>,
);
const chip = ReactTestUtils.findRenderedComponentWithType(tree, Chip);
const chipNode = ReactDOM.findDOMNode(chip);
const chipNode = wrapper.find('div').node;
expect(chipNode.className).toNotMatch(/\bavatar-class\b/);
});
});

View File

@ -169,4 +169,5 @@ export {
DatePickerDialog,
factory as datePickerFactory,
};
export { Calendar };
export { DatePicker };

View File

@ -1,15 +1,14 @@
/* eslint-disable */
import expect from 'expect';
import React from 'react';
import { shallow } from 'enzyme';
import theme from '../theme.css';
import { DatePickerDialog } from '../DatePicker';
import utils from '../../utils/testing';
import { DatePickerDialog, Calendar } from '../DatePicker';
describe('DatePickerDialog', () => {
describe('#on mount', () => {
it('passes value through to calendar if no maxDate/minDate specified', () => {
const value = new Date(2016, 1, 1);
const wrapper = utils.shallowRenderComponent(DatePickerDialog, { theme, value });
expect(getDatePassedToCalendar(wrapper)).toBe(value);
const wrapper = shallow(<DatePickerDialog theme={theme} value={value} />);
expect(wrapper.find(Calendar).props().selectedDate).toBe(value);
});
describe('when minDate but not maxDate specified', () => {
@ -17,15 +16,19 @@ describe('DatePickerDialog', () => {
it('passes through a value after minDate', () => {
const value = new Date(2016, 1, 3);
const wrapper = utils.shallowRenderComponent(DatePickerDialog, { theme, value, minDate });
expect(getDatePassedToCalendar(wrapper)).toBe(value);
const wrapper = shallow(<DatePickerDialog theme={theme} minDate={minDate} value={value} />);
expect(wrapper.find(Calendar).props().selectedDate).toBe(value);
});
it('sanitises a value before minDate to minDate', () => {
const wrapper = utils.shallowRenderComponent(DatePickerDialog, {
theme, value: new Date(2016, 1, 1), minDate,
});
expect(getDatePassedToCalendar(wrapper)).toBe(minDate);
const wrapper = shallow(
<DatePickerDialog
theme={theme}
minDate={minDate}
value={new Date(2016, 1, 1)}
/>,
);
expect(wrapper.find(Calendar).props().selectedDate).toBe(minDate);
});
});
@ -34,15 +37,25 @@ describe('DatePickerDialog', () => {
it('passes through a value before maxDate', () => {
const value = new Date(2016, 1, 1);
const wrapper = utils.shallowRenderComponent(DatePickerDialog, { theme, value, maxDate });
expect(getDatePassedToCalendar(wrapper)).toBe(value);
const wrapper = shallow(
<DatePickerDialog
theme={theme}
maxDate={maxDate}
value={value}
/>,
);
expect(wrapper.find(Calendar).props().selectedDate).toBe(value);
});
it('sanitises a value after maxDate to maxDate', () => {
const wrapper = utils.shallowRenderComponent(DatePickerDialog, {
theme, value: new Date(2016, 1, 3), maxDate,
});
expect(getDatePassedToCalendar(wrapper)).toBe(maxDate);
const wrapper = shallow(
<DatePickerDialog
theme={theme}
maxDate={maxDate}
value={new Date(2016, 1, 3)}
/>,
);
expect(wrapper.find(Calendar).props().selectedDate).toBe(maxDate);
});
});
@ -51,34 +64,41 @@ describe('DatePickerDialog', () => {
const maxDate = new Date(2016, 1, 4);
it('sanitises value to minDate if value is before minDate', () => {
const wrapper = utils.shallowRenderComponent(DatePickerDialog, {
theme,
value: new Date(2016, 1, 1),
minDate,
maxDate,
});
expect(getDatePassedToCalendar(wrapper)).toBe(minDate);
const wrapper = shallow(
<DatePickerDialog
theme={theme}
minDate={minDate}
maxDate={maxDate}
value={new Date(2016, 1, 1)}
/>,
);
expect(wrapper.find(Calendar).props().selectedDate).toBe(minDate);
});
it('sanitises value to maxDate if value is after maxDate', () => {
const wrapper = utils.shallowRenderComponent(DatePickerDialog, {
theme,
value: new Date(2016, 1, 5),
minDate,
maxDate,
});
expect(getDatePassedToCalendar(wrapper)).toBe(maxDate);
const wrapper = shallow(
<DatePickerDialog
theme={theme}
minDate={minDate}
maxDate={maxDate}
value={new Date(2016, 1, 5)}
/>,
);
expect(wrapper.find(Calendar).props().selectedDate).toBe(maxDate);
});
it('doesn\'t sanitise when value is between maxDate/minDate', () => {
const value = new Date(2016, 1, 3);
const wrapper = utils.shallowRenderComponent(DatePickerDialog, { theme, value, minDate, maxDate });
expect(getDatePassedToCalendar(wrapper)).toBe(value);
const wrapper = shallow(
<DatePickerDialog
theme={theme}
minDate={minDate}
maxDate={maxDate}
value={value}
/>,
);
expect(wrapper.find(Calendar).props().selectedDate).toBe(value);
});
});
function getDatePassedToCalendar(wrapper) {
return wrapper.props.children[1].props.children.props.selectedDate;
}
});
});

View File

@ -1,44 +0,0 @@
/* eslint-disable */
import expect from 'expect';
import React from 'react';
import {
renderIntoDocument,
scryRenderedDOMComponentsWithClass,
Simulate,
} from 'react-addons-test-utils';
import sinon from 'sinon';
import theme from '../theme.css';
import Dropdown from '../Dropdown';
describe('Dropdown', () => {
describe('#renderValue', () => {
const source = [
{ value: 'EN-gb', label: 'England' },
{ value: 'ES-es', label: 'Spain', disabled: true },
{ value: 'TH-th', label: 'Thailand', disabled: true },
{ value: 'EN-en', label: 'USA' },
];
it('renders dropdown item with disabled style', () => {
const tree = renderIntoDocument(<Dropdown theme={theme} source={source} />);
const disabled = scryRenderedDOMComponentsWithClass(tree, theme.disabled);
expect(disabled.length).toEqual(2);
});
it('does not call onChange callback when disabled dorpdown item is clicked', () => {
const spy = sinon.spy();
const tree = renderIntoDocument(<Dropdown
theme={theme}
source={source}
value={source[0].value}
onChange={spy}
/>);
const disabled = scryRenderedDOMComponentsWithClass(tree, theme.disabled);
expect(spy.called).toEqual(false);
Simulate.click(disabled[0]);
expect(spy.called).toEqual(false);
const selected = scryRenderedDOMComponentsWithClass(tree, theme.selected);
Simulate.click(selected[0]);
expect(spy.called).toEqual(true);
});
});
});

View File

@ -1,30 +1,20 @@
/* eslint-disable */
import expect from 'expect';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-addons-test-utils';
import Menu from '../Menu';
import MenuItem, { MenuItem as RawMenuItem } from '../MenuItem';
import { shallow } from 'enzyme';
import { Menu } from '../Menu';
import { MenuItem } from '../MenuItem';
describe('MenuItem', () => {
describe('#onClick', () => {
it('passes to listener the event', () => {
let listenerCalled = false;
const handleClick = function (event) {
listenerCalled = true;
expect(event).toExist();
expect(event.target).toExist();
};
const tree = ReactTestUtils.renderIntoDocument(
const onClick = jest.fn();
const wrapper = shallow(
<Menu>
<MenuItem key="1" onClick={handleClick} />
</Menu>);
<MenuItem key="1" onClick={onClick} />
</Menu>,
);
const menuItem = ReactTestUtils.findRenderedComponentWithType(tree, RawMenuItem);
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(menuItem));
expect(listenerCalled).toBe(true);
wrapper.find(MenuItem).first().simulate('click', { persist: () => {} });
expect(onClick).toHaveBeenCalled();
});
});
});

View File

@ -1,70 +1,58 @@
/* eslint-disable */
import React from 'react';
import expect from 'expect';
import TestUtils from 'react-addons-test-utils';
import ProgressBar, { ProgressBar as RawProgressBar } from '../ProgressBar';
import { mount, shallow } from 'enzyme';
import { ProgressBar } from '../ProgressBar';
import theme from '../theme.css';
import utils from '../../utils/testing';
describe('ProgressBar', () => {
let progressBar;
describe('#calculateRatio', () => {
before(() => {
const tree = TestUtils.renderIntoDocument(<ProgressBar min={100} max={300} theme={theme} />);
progressBar = TestUtils.findRenderedComponentWithType(tree, RawProgressBar);
});
it('calculates the right ratio', () => {
const wrapper = shallow(<ProgressBar min={100} max={300} theme={theme} />);
const progressBar = wrapper.instance();
expect(progressBar.calculateRatio(150)).toEqual(0.25);
});
it('gets 0 when value is less than min', () => {
const wrapper = shallow(<ProgressBar min={100} max={300} theme={theme} />);
const progressBar = wrapper.instance();
expect(progressBar.calculateRatio(10)).toEqual(0);
});
it('gets 1 when value is more than max', () => {
const wrapper = shallow(<ProgressBar min={100} max={300} theme={theme} />);
const progressBar = wrapper.instance();
expect(progressBar.calculateRatio(400)).toEqual(1);
});
});
describe('#render', () => {
let buffer,
value,
wrapper,
circle,
strokeLength;
it('renders the value and buffer bars when it is linear', () => {
wrapper = utils.shallowRenderComponent(RawProgressBar, { theme }).props.children;
expect(wrapper.props.children.length).toEqual(2);
const wrapper = mount(<ProgressBar theme={theme} />);
expect(wrapper.childAt(0).props().children.length).toEqual(2);
});
it('renders the value and buffer bars when it is linear', () => {
progressBar = utils.shallowRenderComponent(RawProgressBar, { mode: 'determinate', value: 30, buffer: 60, theme });
buffer = (progressBar.props.children.props.children[0]);
value = (progressBar.props.children.props.children[1]);
expect(buffer.props.style.transform).toEqual(`scaleX(${0.6})`);
expect(value.props.style.transform).toEqual(`scaleX(${0.3})`);
const wrapper = mount(<ProgressBar mode="determinate" value={30} buffer={60} theme={theme} />);
const buffer = wrapper.childAt(0).childAt(0);
const value = wrapper.childAt(0).childAt(1);
expect(buffer.props().style.transform).toEqual(`scaleX(${0.6})`);
expect(value.props().style.transform).toEqual(`scaleX(${0.3})`);
});
it('renders the svg circle when it is circular', () => {
progressBar = utils.shallowRenderComponent(RawProgressBar, { type: 'circular', theme });
expect(progressBar.props.children.type).toEqual('svg');
expect(progressBar.props.children.props.children.type).toEqual('circle');
const wrapper = mount(<ProgressBar type="circular" theme={theme} />);
expect(wrapper.childAt(0).props().children.type).toEqual('circle');
});
it('renders the proper circle length style when it is circular and determinate', () => {
progressBar = utils.shallowRenderComponent(RawProgressBar, { type: 'circular', mode: 'determinate', value: 30, theme });
circle = progressBar.props.children.props.children;
strokeLength = 2 * Math.PI * circle.props.r * 0.3;
const wrapper = mount(<ProgressBar type="circular" mode="determinate" value={30} theme={theme} />);
const circle = wrapper.childAt(0).props().children;
const strokeLength = 2 * Math.PI * circle.props.r * 0.3;
expect(circle.props.style.strokeDasharray).toEqual(`${strokeLength}, 400`);
});
it('contains mode and className in its className', () => {
progressBar = utils.shallowRenderComponent(RawProgressBar, { mode: 'determinate', className: 'tight', theme });
expect(progressBar.props.className).toContain(theme.determinate);
expect(progressBar.props.className).toContain(theme.tight);
it('contains className in its className', () => {
const wrapper = mount(<ProgressBar className="tight" mode="determinate" theme={theme} />);
expect(wrapper.props().className).toContain('tight');
});
});
});

View File

@ -1,79 +1,64 @@
/* eslint-disable */
import React from 'react';
import TestUtils from 'react-addons-test-utils';
import sinon from 'sinon';
import expect from 'expect';
import { mount, shallow } from 'enzyme';
import { Input } from '../../input/Input';
import { ProgressBar } from '../../progress_bar/ProgressBar';
import Input, { Input as RawInput } from '../../input/Input';
import Slider, { Slider as RawSlider } from '../Slider';
import utils from '../../utils/testing';
import { Slider } from '../Slider';
import theme from '../theme.css';
describe('Slider', () => {
let slider,
progress,
input,
onChange;
describe('#positionToValue', () => {
before(() => {
const tree = TestUtils.renderIntoDocument(<Slider min={-500} max={500} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
slider.setState({ sliderStart: 500, sliderLength: 100 });
});
it('returns min when position is less than origin', () => {
expect(slider.positionToValue({ x: 400 })).toEqual(-500);
const instance = shallow(<Slider min={-500} max={500} />).instance();
instance.setState({ sliderStart: 500, sliderLength: 100 });
expect(instance.positionToValue({ x: 400 })).toEqual(-500);
});
it('returns max when position is more and origin plus length', () => {
expect(slider.positionToValue({ x: 900 })).toEqual(500);
const instance = shallow(<Slider min={-500} max={500} />).instance();
instance.setState({ sliderStart: 500, sliderLength: 100 });
expect(instance.positionToValue({ x: 900 })).toEqual(500);
});
it('returns the proper position when the position is inside slider', () => {
expect(slider.positionToValue({ x: 520 })).toEqual(-300);
const instance = shallow(<Slider min={-500} max={500} />).instance();
instance.setState({ sliderStart: 500, sliderLength: 100 });
expect(instance.positionToValue({ x: 520 })).toEqual(-300);
});
});
describe('#trimValue', () => {
before(() => {
const tree = TestUtils.renderIntoDocument(<Slider min={0} max={100} step={0.1} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
});
it('rounds to the proper number', () => {
expect(slider.trimValue(57.16)).toEqual(57.2);
expect(slider.trimValue(57.12)).toEqual(57.10);
const instance = shallow(<Slider min={0} max={100} step={0.1} />).instance();
expect(instance.trimValue(57.16)).toEqual(57.2);
expect(instance.trimValue(57.12)).toEqual(57.10);
});
it('returns min if number is less than min', () => {
expect(slider.trimValue(-57.16)).toEqual(0);
const instance = shallow(<Slider min={0} max={100} step={0.1} />).instance();
expect(instance.trimValue(-57.16)).toEqual(0);
});
it('returns max if number is more than max', () => {
expect(slider.trimValue(257.16)).toEqual(100);
const instance = shallow(<Slider min={0} max={100} step={0.1} />).instance();
expect(instance.trimValue(257.16)).toEqual(100);
});
});
describe('#valueForInput', () => {
before(() => {
const tree = TestUtils.renderIntoDocument(<Slider min={0} max={100} step={0.01} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
});
it('returns a fixed number when an integer is given', () => {
expect(slider.valueForInput(4)).toEqual('4.00');
const instance = shallow(<Slider min={0} max={100} step={0.01} />).instance();
expect(instance.valueForInput(4)).toEqual('4.00');
});
it('returns a fixed number when a float is given', () => {
expect(slider.valueForInput(4.06)).toEqual('4.06');
const instance = shallow(<Slider min={0} max={100} step={0.01} />).instance();
expect(instance.valueForInput(4.06)).toEqual('4.06');
});
});
describe('#knobOffset', () => {
it('returns the corresponding offset for a given value and slider length/start', () => {
const tree = TestUtils.renderIntoDocument(<Slider min={-500} max={500} value={-250} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
const slider = shallow(<Slider min={-500} max={500} value={-250} />).instance();
slider.setState({ sliderStart: 500, sliderLength: 100 });
expect(slider.knobOffset()).toEqual(25);
});
@ -81,91 +66,97 @@ describe('Slider', () => {
describe('#render', () => {
it('contains a linear progress bar with proper properties', () => {
const tree = TestUtils.renderIntoDocument(<Slider min={100} max={1000} value={140} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
progress = TestUtils.findRenderedComponentWithType(slider, ProgressBar);
expect(progress.props.mode).toEqual('determinate');
expect(progress.props.type).toEqual('linear');
expect(progress.props.value).toEqual(140);
expect(progress.props.min).toEqual(100);
expect(progress.props.max).toEqual(1000);
const wrapper = mount(<Slider min={100} max={1000} value={140} />);
const progress = wrapper.find(ProgressBar);
expect(progress.props().mode).toEqual('determinate');
expect(progress.props().type).toEqual('linear');
expect(progress.props().value).toEqual(140);
expect(progress.props().min).toEqual(100);
expect(progress.props().max).toEqual(1000);
});
it('contains an input component if its editable', () => {
const tree = TestUtils.renderIntoDocument(<Slider editable value={130} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
input = TestUtils.findRenderedComponentWithType(slider, Input);
expect(parseInt(input.props.value)).toEqual(slider.props.value);
const wrapper = mount(<Slider editable value={130} />);
const slider = wrapper.instance();
const input = wrapper.find(Input);
expect(parseInt(input.props().value, 10)).toEqual(slider.props.value);
});
it('contains the proper number of snaps when snapped', () => {
slider = utils.shallowRenderComponent(RawSlider, { editable: true, pinned: true, theme });
expect(slider.props.className).toContain(theme.ring);
expect(slider.props.className).toContain(theme.pinned);
slider = utils.shallowRenderComponent(RawSlider, { editable: true, value: 50, theme });
expect(slider.props.className).toNotContain(theme.ring);
const wrapper = mount(<Slider editable pinned theme={theme} />);
const sliderNode = wrapper.find('div').first();
expect(sliderNode.props().className).toContain(theme.ring);
expect(sliderNode.props().className).toContain(theme.pinned);
});
});
describe('#events', () => {
beforeEach(() => {
onChange = sinon.spy();
const tree = TestUtils.renderIntoDocument(<Slider min={-500} max={500} onChange={onChange} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
slider.setState({ sliderStart: 0, sliderLength: 1000 });
slider.handleResize = (event, callback) => { callback(); };
});
it('sets pressed state when knob is clicked', () => {
TestUtils.Simulate.mouseDown(slider.knobNode);
expect(slider.state.pressed).toEqual(true);
const onChange = jest.fn();
const wrapper = mount(<Slider min={-500} max={500} onChange={onChange} />);
const knob = wrapper.childAt(0).childAt(0);
knob.simulate('mouseDown');
expect(wrapper.state().pressed).toEqual(true);
});
it('sets pressed state when knob is touched', () => {
TestUtils.Simulate.touchStart(slider.knobNode, { touches: [{ pageX: 200 }] });
expect(slider.state.pressed).toEqual(true);
const onChange = jest.fn();
const event = { touches: [{ pageX: 200 }] };
const wrapper = mount(<Slider min={-500} max={500} onChange={onChange} />);
const knob = wrapper.childAt(0).childAt(0);
knob.simulate('touchStart', event);
expect(wrapper.state().pressed).toEqual(true);
});
it('sets a proper value when the slider is clicked', () => {
TestUtils.Simulate.mouseDown(slider.sliderNode, { pageX: 200 });
expect(onChange.called).toEqual(true);
expect(onChange.getCall(0).args[0]).toEqual(-300);
const onChange = jest.fn();
const event = { pageX: 200, pageY: 0 };
const wrapper = mount(<Slider min={-500} max={500} onChange={onChange} />);
const instance = wrapper.instance();
instance.setState({ sliderStart: 0, sliderLength: 1000 });
instance.handleResize = (evt, callback) => { callback(); };
wrapper.childAt(0).simulate('mouseDown', event);
expect(onChange).toHaveBeenCalledWith(-300);
});
it('sets a proper value when the slider is touched', () => {
TestUtils.Simulate.touchStart(slider.sliderNode, { touches: [{ pageX: 200, pageY: 0 }] });
expect(onChange.called).toEqual(true);
expect(onChange.getCall(0).args[0]).toEqual(-300);
const onChange = jest.fn();
const event = { touches: [{ pageX: 200, pageY: 0 }] };
const wrapper = mount(<Slider min={-500} max={500} onChange={onChange} />);
const instance = wrapper.instance();
instance.setState({ sliderStart: 0, sliderLength: 1000 });
instance.handleResize = (evt, callback) => { callback(); };
wrapper.childAt(0).simulate('touchStart', event);
expect(onChange).toHaveBeenCalledWith(-300);
});
it('changes input value when slider changes', () => {
const tree = TestUtils.renderIntoDocument(<Slider editable onChange={onChange} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
slider.setState({ sliderStart: 0, sliderLength: 1000 });
slider.handleResize = (event, callback) => { callback(); };
input = TestUtils.findRenderedComponentWithType(slider, Input);
TestUtils.Simulate.mouseDown(slider.sliderNode, { pageX: 900 });
expect(onChange.called).toEqual(true);
expect(onChange.getCall(0).args[0]).toEqual(90);
const onChange = jest.fn();
const event = { pageX: 900 };
const wrapper = mount(<Slider editable onChange={onChange} />);
const instance = wrapper.instance();
instance.setState({ sliderStart: 0, sliderLength: 1000 });
instance.handleResize = (evt, callback) => { callback(); };
wrapper.childAt(0).simulate('mouseDown', event);
expect(onChange).toHaveBeenCalledWith(90);
});
it('changes its value when input is blurred', () => {
const tree = TestUtils.renderIntoDocument(<Slider editable value={50} onChange={onChange} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
input = TestUtils.findRenderedComponentWithType(slider, RawInput);
TestUtils.Simulate.change(input.inputNode, { target: { value: '80' } });
TestUtils.Simulate.blur(input.inputNode);
expect(onChange.called).toEqual(true);
expect(onChange.getCall(0).args[0]).toEqual(80);
const onChange = jest.fn();
const event = { target: { value: '80' } };
const wrapper = mount(<Slider editable value={50} onChange={onChange} />);
wrapper.find('input').simulate('change', event);
wrapper.find('input').simulate('blur');
expect(onChange).toHaveBeenCalled();
expect(onChange.mock.calls[0][0]).toEqual(80);
});
it('calls onChange callback when the value is changed', () => {
const onChangeSpy = sinon.spy();
const tree = TestUtils.renderIntoDocument(<Slider onChange={onChangeSpy} />);
slider = TestUtils.findRenderedComponentWithType(tree, RawSlider);
slider.setState({ sliderStart: 0, sliderLength: 1000 });
TestUtils.Simulate.mouseDown(slider.sliderNode, { pageX: 900 });
expect(onChangeSpy.called).toEqual(true);
const onChange = jest.fn();
const wrapper = mount(<Slider editable value={50} onChange={onChange} />);
wrapper.instance().setState({ sliderStart: 0, sliderLength: 1000 });
wrapper.childAt(0).simulate('mouseDown', { pageX: 900, pageY: 0 });
expect(onChange).toHaveBeenCalled();
});
});
});

View File

@ -1,24 +1,11 @@
/* eslint-disable import/no-named-as-default */
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import expect from 'expect';
import ReactTestUtils from 'react-addons-test-utils';
import utils from '../../utils/testing';
import Tabs, { Tabs as RawTabs } from '../Tabs';
import Tab from '../Tab';
import TabContent from '../TabContent';
import { mount } from 'enzyme';
import { Tabs } from '../Tabs';
import { Tab } from '../Tab';
import { TabContent } from '../TabContent';
import theme from '../theme.css';
const getRenderedClassName = (tree, TargetComponent) => {
const rendered = ReactTestUtils.findRenderedComponentWithType(tree, TargetComponent);
return ReactDOM.findDOMNode(rendered).getAttribute('class');
};
describe('Tabs', () => {
let tabContents;
let composition;
class Composition extends Component {
constructor() {
super();
@ -36,80 +23,46 @@ describe('Tabs', () => {
}
it('defaults to only rendering the current tab', () => {
// initial render
composition = utils.renderComponent(Composition);
const wrapper = mount(<Composition />);
expect(wrapper.find(TabContent).length).toEqual(1);
expect(wrapper.find(TabContent).first().prop('tabIndex')).toEqual(0);
tabContents = ReactTestUtils
.scryRenderedComponentsWithType(composition, TabContent);
expect(tabContents.length).toEqual(1);
expect(tabContents[0].props.tabIndex).toEqual(0);
// after tab change
composition.setState({ index: 1 });
composition.forceUpdate();
tabContents = ReactTestUtils
.scryRenderedComponentsWithType(composition, TabContent);
expect(tabContents.length).toEqual(1);
expect(tabContents[0].props.tabIndex).toEqual(1);
wrapper.instance().setState({ index: 1 });
expect(wrapper.find(TabContent).length).toEqual(1);
expect(wrapper.find(TabContent).first().prop('tabIndex')).toEqual(1);
});
it('renders inactive tabs when hideMode is set to display', () => {
// initial render
composition = utils.renderComponent(Composition, { hideMode: 'display' });
const wrapper = mount(<Composition hideMode="display" />);
expect(wrapper.find(TabContent).length).toEqual(2);
expect(wrapper.find(TabContent).at(0).prop('hidden')).toEqual(false);
expect(wrapper.find(TabContent).at(1).prop('hidden')).toEqual(true);
tabContents = ReactTestUtils
.scryRenderedComponentsWithType(composition, TabContent);
expect(tabContents.length).toEqual(2);
let tabOne = tabContents.find(tab => (tab.props.children === 'tab1'));
let tabTwo = tabContents.find(tab => (tab.props.children === 'tab2'));
expect(tabOne.props.hidden).toEqual(false);
expect(tabTwo.props.hidden).toEqual(true);
// after tab change
composition.setState({ index: 1 });
composition.forceUpdate();
tabContents = ReactTestUtils
.scryRenderedComponentsWithType(composition, TabContent);
expect(tabContents.length).toEqual(2);
tabOne = tabContents.find(tab => (tab.props.children === 'tab1'));
tabTwo = tabContents.find(tab => (tab.props.children === 'tab2'));
expect(tabOne.props.hidden).toEqual(true);
expect(tabTwo.props.hidden).toEqual(false);
wrapper.instance().setState({ index: 1 });
expect(wrapper.find(TabContent).length).toEqual(2);
expect(wrapper.find(TabContent).at(0).prop('hidden')).toEqual(true);
expect(wrapper.find(TabContent).at(1).prop('hidden')).toEqual(false);
});
describe('#render', () => {
it('does not use fixed by default', () => {
const tree = ReactTestUtils.renderIntoDocument(<Tabs theme={theme} />);
const className = getRenderedClassName(tree, RawTabs);
expect(className).toNotContain(theme.fixed);
const wrapper = mount(<Tabs theme={theme} />);
expect(wrapper.find('div').first().prop('className')).not.toContain(theme.fixed);
});
it('uses fixed when set', () => {
const tree = ReactTestUtils.renderIntoDocument(<Tabs theme={theme} fixed />);
const className = getRenderedClassName(tree, RawTabs);
expect(className).toContain(theme.fixed);
const wrapper = mount(<Tabs fixed theme={theme} />);
expect(wrapper.find('div').first().prop('className')).toContain(theme.fixed);
});
it('does not use inverse by default', () => {
const tree = ReactTestUtils.renderIntoDocument(<Tabs theme={theme} />);
const className = getRenderedClassName(tree, RawTabs);
expect(className).toNotContain(theme.inverse);
const wrapper = mount(<Tabs theme={theme} />);
expect(wrapper.find('div').first().prop('className')).not.toContain(theme.inverse);
});
it('uses inverse when set', () => {
const tree = ReactTestUtils.renderIntoDocument(<Tabs theme={theme} inverse />);
const className = getRenderedClassName(tree, RawTabs);
expect(className).toContain(theme.inverse);
const wrapper = mount(<Tabs inverse theme={theme} />);
expect(wrapper.find('div').first().prop('className')).toContain(theme.inverse);
});
});
});

View File

@ -1,21 +0,0 @@
require('babel-polyfill');
const webpackConfig = require('./webpack.config.test');
module.exports = function (config) {
config.set({
browsers: ['PhantomJS'],
singleRun: true,
frameworks: ['mocha'],
files: [
'./node_modules/phantomjs-polyfill/bind-polyfill.js',
'./node_modules/babel-polyfill/dist/polyfill.js',
'tests.webpack.js',
],
reporters: ['dots'],
preprocessors: { 'tests.webpack.js': ['webpack'] },
webpack: webpackConfig,
webpackServer: {
noInfo: true,
},
});
};

View File

@ -5,21 +5,10 @@
"version": "2.0.0-beta.6",
"main": "./lib",
"author": {
"name": "React Toolbox Team",
"url": "http://github.com/react-toolbox"
"name": "Javier Velasco Arjona",
"email": "javier.velasco86@gmail.com",
"url": "http://javivelasco.com/"
},
"contributors": [
{
"name": "Javi Jimenez Villar",
"email": "javi.jimenez.villar@gmail.com",
"url": "http://soyjavi.com/"
},
{
"name": "Javi Velasco Arjona",
"email": "javier.velasco86@gmail.com",
"url": "http://javivelasco.com/"
}
],
"repository": {
"type": "git",
"url": "git+https://github.com/react-toolbox/react-toolbox.git"
@ -35,6 +24,20 @@
"react-component",
"toolkit"
],
"jest": {
"modulePaths": [
"<rootDir>"
],
"moduleDirectories": [
"node_modules"
],
"moduleNameMapper": {
"(\\.css$)|(normalize.css/normalize)|(^exports-loader)": "identity-obj-proxy"
},
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
},
"dependencies": {
"classnames": "^2.2.5",
"core-js": "^2.4.0",
@ -58,30 +61,27 @@
"cpx": "^1.5.0",
"cross-env": "^3.1.3",
"css-loader": "^0.26.1",
"eslint": "^3.14.1",
"eslint-config-airbnb": "^14.0.0",
"enzyme": "^2.7.1",
"enzyme-to-json": "^1.4.5",
"eslint": "^3.15.0",
"eslint-config-airbnb": "^14.1.0",
"eslint-import-resolver-webpack": "^0.8.1",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^3.0.2",
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-react": "^6.9.0",
"expect": "^1.20.1",
"express": "^4.14.0",
"extract-text-webpack-plugin": "^1.0.1",
"express": "^4.14.1",
"extract-text-webpack-plugin": "~2.0.0-rc.2",
"git-dirty": "^1.0.2",
"glob": "^7.1.1",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-postcss": "^6.3.0",
"identity-obj-proxy": "^3.0.0",
"internal-ip": "^1.2.0",
"karma": "^1.4.0",
"karma-cli": "^1.0.0",
"karma-mocha": "^1.3.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-webpack": "^2.0.2",
"lint-staged": "^3.2.8",
"jest": "^18.1.0",
"lint-staged": "^3.3.0",
"mocha": "^3.1.2",
"normalize.css": "^5.0.0",
"phantomjs-prebuilt": "^2.1.14",
"postcss-cssnext": "^2.8.0",
"postcss-each": "^0.9.3",
"postcss-import": "^9.1.0",
@ -92,17 +92,19 @@
"react": "^15.4.2",
"react-addons-test-utils": "^15.4.2",
"react-dom": "^15.4.2",
"react-test-renderer": "^15.4.2",
"react-transform-catch-errors": "^1.0.2",
"react-transform-hmr": "^1.0.4",
"redbox-react": "^1.3.2",
"rimraf": "^2.5.2",
"sinon": "^2.0.0-pre.2",
"style-loader": "^0.13.1",
"stylelint": "^7.5.0",
"stylelint-config-standard": "^15.0.0",
"webpack": "^1.14.0",
"webpack-dev-middleware": "^1.9.0",
"webpack-hot-middleware": "^2.13.0"
"stylelint": "^7.8.0",
"stylelint-config-standard": "^16.0.0",
"stylelint-order": "^0.2.2",
"webpack": "~2.2.0",
"webpack-dev-middleware": "^1.10.0",
"webpack-hot-middleware": "^2.16.1"
},
"scripts": {
"babel": "babel ./components --out-dir ./lib",
@ -118,8 +120,8 @@
"prepublish": "npm run build",
"release": "bumped release",
"start": "cross-env NODE_ENV=development UV_THREADPOOL_SIZE=100 node ./server",
"test": "cross-env NODE_ENV=test karma start",
"test:watch": "cross-env NODE_ENV=test karma start --no-single-run",
"test": "node --harmony_proxies node_modules/.bin/jest --maxWorkers 4",
"test:watch": "node --harmony_proxies node_modules/.bin/jest --watch --no-watchman",
"tsd": "cpx \"./components/**/*.d.ts\" ./lib"
},
"license": "MIT",

View File

@ -2,7 +2,7 @@ const path = require('path');
const express = require('express');
const webpack = require('webpack');
const internalIp = require('internal-ip');
const config = require('./webpack.config.development');
const config = require('./webpack/webpack.config.dev');
const app = express();
const compiler = webpack(config);

View File

@ -1,2 +0,0 @@
const context = require.context('./components', true, /.spec\.js$/);
context.keys().forEach(context);

View File

@ -1,59 +0,0 @@
const pkg = require('./package');
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
context: __dirname,
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'babel-polyfill',
'./spec/index.js'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'spec.js',
publicPath: '/build/'
},
resolve: {
extensions: ['', '.css', '.js', '.json'],
packageMains: ['browser', 'web', 'browserify', 'main', 'style']
},
module: {
loaders: [{
test: /\.js$/,
loader: 'babel',
include: [path.join(__dirname, './components'), path.join(__dirname, './spec')]
}, {
test: /\.css$/,
include: /node_modules/,
loader: ExtractTextPlugin.extract('style', 'css')
}, {
test: /\.css$/,
include: [path.join(__dirname, './components'), path.join(__dirname, './spec')],
loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss')
}]
},
postcss () {
return [
require('postcss-import')({
root: __dirname,
path: [path.join(__dirname, './components')]
}),
require('postcss-mixins')(),
require('postcss-each')(),
require('postcss-cssnext')(),
require('postcss-reporter')({ clearMessages: true })
];
},
plugins: [
new ExtractTextPlugin('spec.css', { allChunks: true, disable: true }),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
VERSION: JSON.stringify(pkg.version)
})
]
};

View File

@ -1,40 +0,0 @@
const path = require('path');
const webpack = require('webpack');
module.exports = {
module: {
loaders: [{
test: /\.js$/,
include: [path.join(__dirname, './components'), path.join(__dirname, './spec')],
loader: 'babel'
}, {
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader']
}, {
test: /\.css$/,
include: [path.join(__dirname, './components'), path.join(__dirname, './spec')],
loader: 'style!css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss'
}]
},
resolve: {
extensions: ['', '.css', '.js', '.json'],
packageMains: ['browser', 'web', 'browserify', 'main', 'style']
},
watch: true,
postcss () {
return [
require('postcss-import')({
root: __dirname,
path: [path.join(__dirname, './components')]
}),
require('postcss-cssnext')(),
require('postcss-reporter')({ clearMessages: true })
];
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('test')
})
]
};

View File

@ -0,0 +1,83 @@
const pkg = require('../package');
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
target: 'web',
context: path.join(__dirname, '../'),
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'babel-polyfill',
'./spec/index.js'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'spec.js',
publicPath: '/build/'
},
resolve: {
extensions: ['.js', '.css', '.json'],
modules: ['node_modules']
},
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.join(__dirname, '../components'),
path.join(__dirname, '../spec')
]
}, {
test: /\.css$/,
include: /node_modules/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
loader: 'css-loader',
})
}, {
test: /\.css$/,
include: [
path.join(__dirname, '../components'),
path.join(__dirname, '../spec')
],
use: ['style-loader', {
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
},
}, 'postcss-loader']
}]
},
plugins: [
new webpack.LoaderOptionsPlugin({
options: {
context: path.join(__dirname, '../'),
postcss () {
return [
require('postcss-import')({
root: path.join(__dirname, '../'),
path: [path.join(__dirname, '../components')]
}),
require('postcss-mixins')(),
require('postcss-each')(),
require('postcss-cssnext')(),
require('postcss-reporter')({
clearMessages: true
})
];
}
}
}),
new ExtractTextPlugin({ filename: 'spec.css', allChunks: true }),
new webpack.HotModuleReplacementPlugin(),
new webpack.EvalSourceMapDevToolPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
VERSION: JSON.stringify(pkg.version)
})
]
};

2008
yarn.lock

File diff suppressed because it is too large Load Diff