UNPKG

react-themable-hoc

Version:

React higher-order-components that allow for css-in-js-style themes.

127 lines (100 loc) 5.29 kB
import { mount, shallow } from 'enzyme'; import AphroditeInterface from 'react-themable-hoc-aphrodite-interface'; import { ON_THEME_CHANGE } from '../events'; import React from 'react'; import ThemeEvents from '../ThemeEvents'; import ThemeManager from '../ThemeManager'; import { expect } from 'chai'; import sinon from 'sinon'; import themed from '../themed'; // TODO create ThemeManager factory... beforeEach(() => { ThemeManager.reset(); const aphroditeInterface = new AphroditeInterface(); ThemeManager.setStyleInterface(aphroditeInterface); ThemeManager.addTheme('testTheme1', TEST_THEME1); ThemeManager.addTheme('testTheme2', TEST_THEME2); ThemeManager.setCurrentTheme('testTheme1'); }); describe('themed', () => { const TEST_THEME1 = { color: 'blue' }; const TEST_THEME2 = { color: 'green' }; const Div = ({ classNames }) => <div className={classNames.styles} />; const DivStyledByProps = themed((theme, props) => ({ styles: { backgroundColor: props.color } }))(Div); const ThemedDiv = themed(theme => ({ styles: { backgroundColor: theme.color } }))(Div); it('should re-create stylesheets when the theme changes', () => { const getThemedStylesSpy = sinon.spy(ThemedDiv.prototype, 'getThemedStyles'); const onThemeChangeSpy = sinon.spy(ThemedDiv.prototype, 'onThemeChange'); const wrapper = mount(<ThemedDiv />); const div = wrapper.find(Div); const initialClassName = div.props().classNames.styles; ThemeEvents.publish(ON_THEME_CHANGE, ThemeManager.getTheme('testTheme2')); wrapper.update(); const finalClassName = div.props().classNames.styles; expect(initialClassName).to.not.equal(finalClassName); expect(onThemeChangeSpy.calledOnce).to.equal(true); expect(getThemedStylesSpy.calledAfter(onThemeChangeSpy)).to.equal(true); ThemedDiv.prototype.getThemedStyles.restore(); ThemedDiv.prototype.onThemeChange.restore(); }); it('should re-create stylesheets if createStyles function has a prop parameter', () => { const componentWillReceivePropsSpy = sinon.spy(DivStyledByProps.prototype, 'componentWillReceiveProps'); const getThemedStylesSpy = sinon.spy(DivStyledByProps.prototype, 'getThemedStyles'); const wrapper = mount(<DivStyledByProps color="red" />); const div = wrapper.find(Div); const initialClassName = div.props().classNames.styles; wrapper.setProps({ color: 'blue' }); const finalClassName = div.props().classNames.styles; expect(initialClassName).to.not.equal(finalClassName); expect(getThemedStylesSpy.calledTwice).to.equal(true); expect(getThemedStylesSpy.calledImmediatelyAfter(componentWillReceivePropsSpy)).to.equal(true); DivStyledByProps.prototype.componentWillReceiveProps.restore(); DivStyledByProps.prototype.getThemedStyles.restore(); }); it('should not re-create stylesheets if createStyles has no prop parameter', () => { const componentWillReceivePropsSpy = sinon.spy(ThemedDiv.prototype, 'componentWillReceiveProps'); const getThemedStylesSpy = sinon.spy(ThemedDiv.prototype, 'getThemedStyles'); const wrapper = mount(<ThemedDiv />); const div = wrapper.find(Div); const initialClassName = div.props().classNames.styles; wrapper.setProps({ color: 'red' }); const finalClassName = div.props().classNames.styles; expect(initialClassName).to.equal(finalClassName); expect(getThemedStylesSpy.calledOnce).to.equal(true); expect(getThemedStylesSpy.calledImmediatelyAfter(componentWillReceivePropsSpy)).to.equal(false); ThemedDiv.prototype.componentWillReceiveProps.restore(); ThemedDiv.prototype.getThemedStyles.restore(); }); it('should not re-create stylesheets if "shouldUpdateStyles" function returns false', () => { const shouldUpdateStyles = (currProps, nextProps) => false; const NoUpdateDiv = themed(() => ({ styles: {} }), { shouldUpdateStyles })(Div); const wrapper = mount(<NoUpdateDiv />); const div = wrapper.find(Div); const initialClassName = div.props().classNames.styles; wrapper.setProps({ color: 'red' }); const finalClassName = div.props().classNames.styles; expect(initialClassName).to.equal(finalClassName); }); it('should extend React.PureComponent if options.pure === true', () => { const PureDiv = themed(() => {}, { pure: true })(Div); const pureWrapper = shallow(<PureDiv />); const wrapper = shallow(<ThemedDiv />); expect(pureWrapper.instance() instanceof React.PureComponent).to.equal(true); expect(wrapper.instance() instanceof React.Component).to.equal(true); }); it('should set the name of the styles props with the "classesPropName" option', () => { const classesPropName = 'testProp'; const DivWithCustomPropName = themed(() => ({}), { classesPropName })(Div); const wrapper = shallow(<DivWithCustomPropName />); const div = wrapper.find(Div); expect(div.props()[classesPropName]).to.exist; }); });