<commit_before>import React from 'react';
import TestUtils from 'react-dom/test-utils';
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
import { shallow } from 'enzyme';
import { Carousel, Slide } from './carousel.component';
import { elementsTagTest, rootTagTest } from '../../utils/helpers/tags/tags-specs/tags-specs';

/* global jest */

describe('Carousel', () => {
  let instance;

  beforeEach(() => {
    instance = TestUtils.renderIntoDocument(
      <Carousel className='foobar'>
        <Slide />
        <Slide />
        <Slide />
      </Carousel>
    );
  });

  describe('componentWillMount', () => {
    describe('when slideIndex is passed', () => {
      it('sets the intial slide to the prop', () => {
        const wrapper = shallow(
          <Carousel slideIndex={ 1 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

        expect(wrapper.state('selectedSlideIndex')).toEqual(1);
      });
    });

    describe('when initialSlideIndex is passed', () => {
      it('sets the intial slide to the prop', () => {
        const wrapper = shallow(
          <Carousel initialSlideIndex={ 2 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

        expect(wrapper.state('selectedSlideIndex')).toEqual(2);
      });
    });

    describe('when initialSelectedId is not passed', () => {
      it('defaults the initial slide to slide 0', () => {
        const wrapper = shallow(
          <Carousel>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

        expect(wrapper.state('selectedSlideIndex')).toEqual(0);
      });
    });
  });

  describe('componentWillReceiveProps', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
    });

    it('navigates between slides correctly when the slideIndex prop changes', () => {
      // Initial state
      expect(wrapper.state().selectedSlideIndex).toEqual(0);
      expect(wrapper.state().disabled).toBeFalsy();
      expect(enableButtonsAfterTimeoutSpy).not.toHaveBeenCalled();

      // Move to slide 2
      wrapper.setProps({ slideIndex: 2 });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(wrapper.instance().transitionDirection).toEqual('next');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(1);

      // Move to slide 1
      wrapper.setProps({ slideIndex: 1 });

      expect(wrapper.state().selectedSlideIndex).toEqual(1);
      expect(wrapper.instance().transitionDirection).toEqual('previous');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(2);

      // Move to slide 3
      wrapper.setProps({ slideIndex: 3 });

      expect(wrapper.state().selectedSlideIndex).toEqual(0);
      expect(wrapper.instance().transitionDirection).toEqual('previous');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(3);

      // Move to slide -1
      wrapper.setProps({ slideIndex: -1 });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(wrapper.instance().transitionDirection).toEqual('next');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(4);

      // Move to slide 2
      wrapper.setProps({ slideIndex: 2 });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(4);

      // Undefined slideIndex
      wrapper.setProps({ slideIndex: undefined });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(4);
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setProps({ slideIndex: 1 });

        expect(onSlideChangeSpy).toHaveBeenCalledWith(1, 'previous');
      });
    });
  });

  describe('enableButtonsAfterTimeout', () => {
    it('sets a timeout', () => {
      spyOn(window, 'setTimeout');
      instance.enableButtonsAfterTimeout();
      expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 750);
    });

    it('sets the disabled state to false', () => {
      jest.useFakeTimers();
      instance.setState({ disabled: true });
      instance.enableButtonsAfterTimeout();
      jest.runTimersToTime(750);

      expect(instance.state.disabled).toBeFalsy();
    });
  });

  describe('onPreviousClick', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
      wrapper.setState({ selectedSlideIndex: 2 });
      wrapper.instance().onPreviousClick();
    });

    it('decrements the selectedSlideIndex', () => {
      expect(wrapper.state().selectedSlideIndex).toEqual(1);
    });

    it('sets the transistion direction to previous', () => {
      expect(wrapper.instance().transitionDirection).toEqual('previous');
    });

    it('disables the buttons', () => {
      expect(wrapper.state().disabled).toBeTruthy();
    });

    it('calls to re-enable buttons after timeout', () => {
      expect(wrapper.instance().enableButtonsAfterTimeout).toHaveBeenCalled();
    });

    describe('when on slide 0', () => {
      it('sets the slideIndex to the last slide', () => {
        wrapper.setState({ selectedSlideIndex: 0 });
        wrapper.instance().onPreviousClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(2);
      });
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setState({ selectedSlideIndex: 0 });
        wrapper.instance().onPreviousClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(2);
        expect(onSlideChangeSpy).toHaveBeenCalledWith(2, 'previous');
      });
    });
  });

  describe('onNextClick', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
      wrapper.setState({ selectedSlideIndex: 0 });
      wrapper.instance().onNextClick();
    });

    it('increments the selectedSlideIndex', () => {
      expect(wrapper.state().selectedSlideIndex).toEqual(1);
    });

    it('sets the transistion direction to next', () => {
      expect(wrapper.instance().transitionDirection).toEqual('next');
    });

    it('disables the buttons', () => {
      expect(wrapper.state().disabled).toBeTruthy();
    });

    it('calls to re-enable buttons after timeout', () => {
      expect(wrapper.instance().enableButtonsAfterTimeout).toHaveBeenCalled();
    });

    describe('when on the last slide', () => {
      it('sets the slideIndex to the first slide', () => {
        wrapper.setState({ selectedSlideIndex: 2 });
        wrapper.instance().onNextClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(0);
      });
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setState({ selectedSlideIndex: 2 });
        wrapper.instance().onNextClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(0);
        expect(onSlideChangeSpy).toHaveBeenCalledWith(0, 'next');
      });
    });
  });

  describe('onSlideSelection', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
      wrapper.setState({ selectedSlideIndex: 0 });
      const ev = { target: { value: 2 } };
      wrapper.instance().onSlideSelection(ev);
    });

    it('sets the new slideIndex', () => {
      expect(wrapper.state().selectedSlideIndex).toEqual(2);
    });

    it('disables the buttons', () => {
      expect(wrapper.state().disabled).toBeTruthy();
    });

    it('calls to re-enable the buttons', () => {
      expect(wrapper.instance().enableButtonsAfterTimeout).toHaveBeenCalled();
    });

    describe('when new slide index is greater than current', () => {
      it('sets the transistion group to NEXT', () => {
        expect(wrapper.instance().transitionDirection).toEqual('next');
      });
    });

    describe('when new slide index is less than current', () => {
      it('sets the transistion group to PREVIOUS', () => {
        wrapper.setState({ selectedSlideIndex: 2 });
        const ev = { target: { value: 1 } };
        wrapper.instance().onSlideSelection(ev);
        expect(wrapper.instance().transitionDirection).toEqual('previous');
      });
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setState({ selectedSlideIndex: 2 });
        const ev = { target: { value: 1 } };
        wrapper.instance().onSlideSelection(ev);
        expect(wrapper.instance().transitionDirection).toEqual('previous');
        expect(onSlideChangeSpy).toHaveBeenCalledWith(1, 'previous');
      });
    });
  });

  describe('mainClasses', () => {
    it('returns the carousel base class', () => {
      TestUtils.findRenderedDOMComponentWithClass(instance, 'carbon-carousel');
    });

    it('returns any passed prop names', () => {
      TestUtils.findRenderedDOMComponentWithClass(instance, 'foobar');
    });
  });

  describe('nextClasses', () => {
    it('returns the class for the next button area', () => {
      expect(instance.nextClasses()).toEqual('carbon-carousel__navigation carbon-carousel__next');
    });
  });

  describe('previousClasses', () => {
    it('returns the class for the previous button area', () => {
      expect(instance.previousClasses()).toEqual('carbon-carousel__navigation carbon-carousel__previous');
    });
  });

  describe('previousButtonClasses', () => {
    it('returns the class for the previous button', () => {
      expect(instance.previousButtonClasses()).toEqual('carbon-carousel__buttons carbon-carousel__previous-button');
    });
  });

  describe('nextButtonClasses', () => {
    it('returns the class for the next button', () => {
      expect(instance.nextButtonClasses()).toEqual('carbon-carousel__buttons carbon-carousel__next-button');
    });
  });

  describe('slideSelectorClassses', () => {
    it('returns the class for the slide selector', () => {
      expect(instance.slideSelectorClasses()).toEqual('carbon-carousel__selector');
    });
  });

  describe('previousButtonProps', () => {
    it('adds the previous button classNames', () => {
      expect(instance.previousButtonProps().className).toEqual(instance.previousButtonClasses());
    });

    describe('when buttons are disabled', () => {
      it('does not add a onClick', () => {
        instance.setState({ disabled: true });
        expect(instance.previousButtonProps().onClick).toBeUndefined();
      });
    });

    describe('when buttons are not disabled', () => {
      it('adds a onClick', () => {
        instance.setState({ disabled: false });
        expect(instance.previousButtonProps().onClick).toBeDefined();
      });
    });
  });

  describe('numOfSlides', () => {
    describe('when one child', () => {
      it('returns 1', () => {
        instance = TestUtils.renderIntoDocument(
          <Carousel className='foobar'>
            <Slide />
          </Carousel>
        );

        expect(instance.numOfSlides()).toEqual(1);
      });
    });

    describe('when an array of children', () => {
      it('returns the number of children', () => {
        expect(instance.numOfSlides()).toEqual(3);
      });
    });
  });

  describe('visibleSlides', () => {
    let slide, wrapper;

    beforeEach(() => {
      wrapper = shallow(
        <Carousel>
          <Slide />
        </Carousel>
      );

      slide = wrapper.instance().visibleSlide();
    });

    it('returns a slide instance', () => {
      expect(slide.type).toEqual(Slide);
    });

    it('adds an active and a padded classes', () => {
      expect(slide.props.className).toEqual('carbon-slide carbon-slide--active carbon-slide--padded');
    });

    describe('when the previous button is disabled', () => {
      it('adds an active and a padded classes', () => {
        wrapper.setProps({ enablePreviousButton: false });
        slide = wrapper.instance().visibleSlide();

        expect(slide.props.className).toEqual('carbon-slide carbon-slide--active carbon-slide--padded');
      });
    });

    describe('when the next button is disabled', () => {
      it('adds an active and a padded classes', () => {
        wrapper.setProps({ enableNextButton: false });
        slide = wrapper.instance().visibleSlide();

        expect(slide.props.className).toEqual('carbon-slide carbon-slide--active carbon-slide--padded');
      });
    });

    describe('when both buttons are disabled', () => {
      it('adds an active class', () => {
        wrapper.setProps({ enablePreviousButton: false, enableNextButton: false });
        slide = wrapper.instance().visibleSlide();

        expect(slide.props.className).toEqual('carbon-slide carbon-slide--active');
      });
    });
  });

  describe('slideSelector', () => {
    describe('when enableSlideSelector is set to true', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide />
          <Slide />
          <Slide />
        </Carousel>
      );

      it('renders a button for each slide', () => {
        const buttons = wrapper.find('.carbon-carousel__selector-input');

        expect(buttons.exists()).toBeTruthy();
        expect(buttons.length).toEqual(3);
      });
    });

    describe('when enableSlideSelector is set to false', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 } enableSlideSelector={ false }>
          <Slide />
        </Carousel>
      );

      it('does not render the slide selector', () => {
        const buttons = wrapper.find('.carbon-carousel__selector-input');
        expect(buttons.exists()).toBeFalsy();
      });
    });
  });

  describe('previousButton', () => {
    describe('when enablePreviousButton is set to true', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide />
        </Carousel>
      );

      it('renders a previous button', () => {
        const arrow = wrapper.find('.carbon-carousel__previous-arrow');
        expect(arrow.exists()).toBeTruthy();
      });
    });

    describe('when enablePreviousButton is set to false', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 } enablePreviousButton={ false }>
          <Slide />
        </Carousel>
      );

      it('does not render a previous button', () => {
        const arrow = wrapper.find('.carbon-carousel__previous-arrow');
        expect(arrow.exists()).toBeFalsy();
      });
    });
  });

  describe('nextButton', () => {
    describe('when enableNextButton is set to true', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide />
        </Carousel>
      );

      it('renders a next button', () => {
        const arrow = wrapper.find('.carbon-carousel__next-arrow');
        expect(arrow.exists()).toBeTruthy();
      });
    });

    describe('when enableNextButton is set to false', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 } enableNextButton={ false }>
          <Slide />
        </Carousel>
      );

      it('does not render a next button', () => {
        const arrow = wrapper.find('.carbon-carousel__next-arrow');
        expect(arrow.exists()).toBeFalsy();
      });
    });
  });

  describe('tags', () => {
    describe('on component', () => {
      const wrapper = shallow(
        <Carousel
data-element='bar' data-role='baz'
                    initialSlideIndex={ 0 }
        >
          <Slide />
        </Carousel>
      );

      it('include correct component, element and role data tags', () => {
        rootTagTest(wrapper, 'carousel', 'bar', 'baz');
      });
    });

    describe('on internal elements', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide data-element='slide' />
        </Carousel>
      );

      elementsTagTest(wrapper, [
        'next',
        'previous',
        'selector-input',
        'selector-label',
        'visible-slide'
      ]);
    });
  });

  describe('transitionName', () => {
    it('uses a custom name if supplied', () => {
      const wrapper = shallow(
        <Carousel transition='foo'>
          <Slide />
        </Carousel>
      );

      const transitionGroup = wrapper.find(CSSTransitionGroup);
      expect(transitionGroup.props().transitionName).toEqual('carousel-transition-foo');
    });
  });
});
<commit_msg>update tests to be relevant to new version of carousel based on style-components<commit_after>import React from 'react';
import TestUtils from 'react-dom/test-utils';
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
import { shallow } from 'enzyme';
import { Carousel, Slide } from './carousel.component';
import { elementsTagTest, rootTagTest } from '../../utils/helpers/tags/tags-specs/tags-specs';
import { CarouselStyledIconLeft, CarouselSelectorInputStyle, CarouselStyledIconRight } from './carousel.style';
import { SlideStyle } from './slide/slide.style';

/* global jest */

describe('Carousel', () => {
  let instance;

  beforeEach(() => {
    instance = TestUtils.renderIntoDocument(
      <Carousel className='foobar'>
        <Slide />
        <Slide />
        <Slide />
      </Carousel>
    );
  });

  describe('componentWillMount', () => {
    describe('when slideIndex is passed', () => {
      it('sets the intial slide to the prop', () => {
        const wrapper = shallow(
          <Carousel slideIndex={ 1 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

        expect(wrapper.state('selectedSlideIndex')).toEqual(1);
      });
    });

    describe('when initialSlideIndex is passed', () => {
      it('sets the intial slide to the prop', () => {
        const wrapper = shallow(
          <Carousel initialSlideIndex={ 2 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

        expect(wrapper.state('selectedSlideIndex')).toEqual(2);
      });
    });

    describe('when initialSelectedId is not passed', () => {
      it('defaults the initial slide to slide 0', () => {
        const wrapper = shallow(
          <Carousel>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

        expect(wrapper.state('selectedSlideIndex')).toEqual(0);
      });
    });
  });

  describe('componentWillReceiveProps', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
    });

    it('navigates between slides correctly when the slideIndex prop changes', () => {
      // Initial state
      expect(wrapper.state().selectedSlideIndex).toEqual(0);
      expect(wrapper.state().disabled).toBeFalsy();
      expect(enableButtonsAfterTimeoutSpy).not.toHaveBeenCalled();

      // Move to slide 2
      wrapper.setProps({ slideIndex: 2 });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(wrapper.instance().transitionDirection).toEqual('next');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(1);

      // Move to slide 1
      wrapper.setProps({ slideIndex: 1 });

      expect(wrapper.state().selectedSlideIndex).toEqual(1);
      expect(wrapper.instance().transitionDirection).toEqual('previous');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(2);

      // Move to slide 3
      wrapper.setProps({ slideIndex: 3 });

      expect(wrapper.state().selectedSlideIndex).toEqual(0);
      expect(wrapper.instance().transitionDirection).toEqual('previous');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(3);

      // Move to slide -1
      wrapper.setProps({ slideIndex: -1 });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(wrapper.instance().transitionDirection).toEqual('next');
      expect(wrapper.state().disabled).toBeTruthy();
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(4);

      // Move to slide 2
      wrapper.setProps({ slideIndex: 2 });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(4);

      // Undefined slideIndex
      wrapper.setProps({ slideIndex: undefined });

      expect(wrapper.state().selectedSlideIndex).toEqual(2);
      expect(enableButtonsAfterTimeoutSpy.calls.count()).toEqual(4);
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setProps({ slideIndex: 1 });

        expect(onSlideChangeSpy).toHaveBeenCalledWith(1, 'previous');
      });
    });
  });

  describe('enableButtonsAfterTimeout', () => {
    it('sets a timeout', () => {
      spyOn(window, 'setTimeout');
      instance.enableButtonsAfterTimeout();
      expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 750);
    });

    it('sets the disabled state to false', () => {
      jest.useFakeTimers();
      instance.setState({ disabled: true });
      instance.enableButtonsAfterTimeout();
      jest.runTimersToTime(750);

      expect(instance.state.disabled).toBeFalsy();
    });
  });

  describe('onPreviousClick', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
      wrapper.setState({ selectedSlideIndex: 2 });
      wrapper.instance().onPreviousClick();
    });

    it('decrements the selectedSlideIndex', () => {
      expect(wrapper.state().selectedSlideIndex).toEqual(1);
    });

    it('sets the transistion direction to previous', () => {
      expect(wrapper.instance().transitionDirection).toEqual('previous');
    });

    it('disables the buttons', () => {
      expect(wrapper.state().disabled).toBeTruthy();
    });

    it('calls to re-enable buttons after timeout', () => {
      expect(wrapper.instance().enableButtonsAfterTimeout).toHaveBeenCalled();
    });

    describe('when on slide 0', () => {
      it('sets the slideIndex to the last slide', () => {
        wrapper.setState({ selectedSlideIndex: 0 });
        wrapper.instance().onPreviousClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(2);
      });
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setState({ selectedSlideIndex: 0 });
        wrapper.instance().onPreviousClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(2);
        expect(onSlideChangeSpy).toHaveBeenCalledWith(2, 'previous');
      });
    });
  });

  describe('onNextClick', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
      wrapper.setState({ selectedSlideIndex: 0 });
      wrapper.instance().onNextClick();
    });

    it('increments the selectedSlideIndex', () => {
      expect(wrapper.state().selectedSlideIndex).toEqual(1);
    });

    it('sets the transistion direction to next', () => {
      expect(wrapper.instance().transitionDirection).toEqual('next');
    });

    it('disables the buttons', () => {
      expect(wrapper.state().disabled).toBeTruthy();
    });

    it('calls to re-enable buttons after timeout', () => {
      expect(wrapper.instance().enableButtonsAfterTimeout).toHaveBeenCalled();
    });

    describe('when on the last slide', () => {
      it('sets the slideIndex to the first slide', () => {
        wrapper.setState({ selectedSlideIndex: 2 });
        wrapper.instance().onNextClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(0);
      });
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setState({ selectedSlideIndex: 2 });
        wrapper.instance().onNextClick();
        expect(wrapper.state().selectedSlideIndex).toEqual(0);
        expect(onSlideChangeSpy).toHaveBeenCalledWith(0, 'next');
      });
    });
  });

  describe('onSlideSelection', () => {
    const enableButtonsAfterTimeoutSpy = jasmine.createSpy(),
        wrapper = shallow(
          <Carousel initialSlideIndex={ 0 }>
            <Slide />
            <Slide />
            <Slide />
          </Carousel>
        );

    beforeEach(() => {
      wrapper.instance().enableButtonsAfterTimeout = enableButtonsAfterTimeoutSpy;
      wrapper.setState({ selectedSlideIndex: 0 });
      const ev = { target: { value: 2 } };
      wrapper.instance().onSlideSelection(ev);
    });

    it('sets the new slideIndex', () => {
      expect(wrapper.state().selectedSlideIndex).toEqual(2);
    });

    it('disables the buttons', () => {
      expect(wrapper.state().disabled).toBeTruthy();
    });

    it('calls to re-enable the buttons', () => {
      expect(wrapper.instance().enableButtonsAfterTimeout).toHaveBeenCalled();
    });

    describe('when new slide index is greater than current', () => {
      it('sets the transistion group to NEXT', () => {
        expect(wrapper.instance().transitionDirection).toEqual('next');
      });
    });

    describe('when new slide index is less than current', () => {
      it('sets the transistion group to PREVIOUS', () => {
        wrapper.setState({ selectedSlideIndex: 2 });
        const ev = { target: { value: 1 } };
        wrapper.instance().onSlideSelection(ev);
        expect(wrapper.instance().transitionDirection).toEqual('previous');
      });
    });

    describe('when onSlideChange is set', () => {
      it('calls onSlideChange', () => {
        const onSlideChangeSpy = jasmine.createSpy();
        wrapper.setProps({ onSlideChange: onSlideChangeSpy });
        wrapper.setState({ selectedSlideIndex: 2 });
        const ev = { target: { value: 1 } };
        wrapper.instance().onSlideSelection(ev);
        expect(wrapper.instance().transitionDirection).toEqual('previous');
        expect(onSlideChangeSpy).toHaveBeenCalledWith(1, 'previous');
      });
    });
  });

  describe('previousButtonProps', () => {
    describe('when buttons are disabled', () => {
      it('does not add a onClick', () => {
        instance.setState({ disabled: true });
        expect(instance.previousButtonProps().onClick).toBeUndefined();
      });
    });

    describe('when buttons are not disabled', () => {
      it('adds a onClick', () => {
        instance.setState({ disabled: false });
        expect(instance.previousButtonProps().onClick).toBeDefined();
      });
    });
  });

  describe('numOfSlides', () => {
    describe('when one child', () => {
      it('returns 1', () => {
        instance = TestUtils.renderIntoDocument(
          <Carousel className='foobar'>
            <Slide />
          </Carousel>
        );

        expect(instance.numOfSlides()).toEqual(1);
      });
    });

    describe('when an array of children', () => {
      it('returns the number of children', () => {
        expect(instance.numOfSlides()).toEqual(3);
      });
    });
  });

  describe('visibleSlides', () => {
    let slide, wrapper;

    beforeEach(() => {
      wrapper = shallow(
        <Carousel>
          <Slide />
        </Carousel>
      );

      slide = wrapper.instance().visibleSlide();
    });

    it('returns a slide instance', () => {
      expect(slide.type).toEqual(Slide);
    });

    it('adds an active and a padded classes', () => {
      expect(wrapper.find(Slide).props().isPadded).toBe(true);
    });

    describe('when the previous button is disabled', () => {
      it('adds a padded classes', () => {
        wrapper.setProps({ enablePreviousButton: false });

        expect(wrapper.find(Slide).props().isPadded).toBe(true);
      });
    });

    describe('when the next button is disabled', () => {
      it('adds a padded classes', () => {
        wrapper.setProps({ enableNextButton: false });

        expect(wrapper.find(Slide).props().isPadded).toBe(true);
      });
    });
  });

  describe('slideSelector', () => {
    describe('when enableSlideSelector is set to true', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide />
          <Slide />
          <Slide />
        </Carousel>
      );

      it('renders a button for each slide', () => {
        const buttons = wrapper.find(CarouselSelectorInputStyle);

        expect(buttons.exists()).toBeTruthy();
        expect(buttons.length).toEqual(3);
      });
    });

    describe('when enableSlideSelector is set to false', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 } enableSlideSelector={ false }>
          <Slide />
        </Carousel>
      );

      it('does not render the slide selector', () => {
        const buttons = wrapper.find(CarouselSelectorInputStyle);
        expect(buttons.exists()).toBeFalsy();
      });
    });
  });

  describe('previousButton', () => {
    describe('when enablePreviousButton is set to true', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide />
        </Carousel>
      );

      it('renders a previous button', () => {
        const arrow = wrapper.find(CarouselStyledIconLeft);
        expect(arrow.exists()).toBeTruthy();
      });
    });

    describe('when enablePreviousButton is set to false', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 } enablePreviousButton={ false }>
          <Slide />
        </Carousel>
      );

      it('does not render a previous button', () => {
        const arrow = wrapper.find('.carbon-carousel__previous-arrow');
        expect(arrow.exists()).toBeFalsy();
      });
    });
  });

  describe('nextButton', () => {
    describe('when enableNextButton is set to true', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide />
        </Carousel>
      );

      it('renders a next button', () => {
        const arrow = wrapper.find(CarouselStyledIconRight);
        expect(arrow.exists()).toBeTruthy();
      });
    });

    describe('when enableNextButton is set to false', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 } enableNextButton={ false }>
          <Slide />
        </Carousel>
      );

      it('does not render a next button', () => {
        const arrow = wrapper.find(CarouselStyledIconRight);
        expect(arrow.exists()).toBeFalsy();
      });
    });
  });

  describe('tags', () => {
    describe('on component', () => {
      const wrapper = shallow(
        <Carousel
          data-element='bar' data-role='baz'
          initialSlideIndex={ 0 }
        >
          <Slide />
        </Carousel>
      );

      it('include correct component, element and role data tags', () => {
        rootTagTest(wrapper, 'carousel', 'bar', 'baz');
      });
    });

    describe('on internal elements', () => {
      const wrapper = shallow(
        <Carousel initialSlideIndex={ 0 }>
          <Slide data-element='slide' />
        </Carousel>
      );

      elementsTagTest(wrapper, [
        'next',
        'previous',
        'selector-input',
        'selector-label',
        'visible-slide'
      ]);
    });
  });

  describe('transitionName', () => {
    it('uses a custom name if supplied', () => {
      const wrapper = shallow(
        <Carousel transition='foo'>
          <Slide />
        </Carousel>
      );

      const transitionGroup = wrapper.find(CSSTransitionGroup);
      expect(transitionGroup.props().transitionName).toEqual('carousel-transition-foo');
    });
  });
});
<|endoftext|>


<commit_before>//Dependencies.
import builder from 'focus-core/component/builder';
var React = require('react');
import type from 'focus-core/component/types';
var i18nBehaviour = require('../../i18n/mixin');
/**
 * Input text mixin.
 * @type {Object}
 */
var displayCheckboxMixin = {
    mixins: [i18nBehaviour],
  /** @inheritdoc */
    getDefaultProps: function getInputDefaultProps() {
        return {
            value: undefined,
            name: undefined,
            style: {}
        };
    },
  /** @inheritdoc */
    propTypes: {
        type: type('string'),
        value: type('bool'),
        name: type('string'),
        style: type('object')
    },
  /**
   * Render the boolean value.
   */
    renderValue: function renderValueDisplayText() {
        var stringValue = this.props.value === true ? 'true' : 'false';
        return this.i18n(`display.checkbox.${stringValue}`);
    },
  /**
   * Render a display field.
   * @return {DOM} - The dom of an input.
   */
    render: function renderInput() {
        return (

{this.renderValue()}

    );
    }
};

module.exports = builder(displayCheckboxMixin);
<commit_msg>displayCheckbox refactoring<commit_after>import React, {PropTypes} from 'react';
import {translate} from 'focus-core/translation';

/**
* Render the boolean value.
*/
renderValue: function renderValueDisplayText(value) {
    var stringValue = value === true ? 'true' : 'false';
    return translate(`display.checkbox.${stringValue}`);
}

function displayCheckbox({name, value, style}) {
    return(

            {this.renderValue(value)}

    );
}

displayCheckbox.defaultProps = {
    value: undefined,
    name: undefined,
    style: {}
};

displayCheckbox.propTypes = {
    type: PropTypes.string,
    value: PropTypes.bool,
    name: PropTypes.string,
    style: PropTypes.object,
};

displayCheckbox.displayName = 'DisplayCheckbox';

module.exports = displayCheckbox;
<|endoftext|>


<commit_before>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, render, mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';

import Form from '../Form';

const expect = chai.expect;

/* eslint-disable no-unused-vars */
const debug = (component) => {
    console.info('------------------------------------------------------------');
    console.info(component.debug());
    console.info('------------------------------------------------------------');
};
/* eslint-enable no-unused-vars */

/* *****************************************************************************
a Form component containing a SubmitButton
    should include a <Form.SubmitButton> as a child
    should be a button.btn
    should have the label specified by the `label` property
    should have the default label if no `label` property specified

    should be button.btn.btn-default when no style is provided
    should be button.btn.btn-danger when style=danger
    should be button.btn.btn-danger when style=error
    should be button.btn.btn-warning when style=warning
    should be button.btn.btn-warning when style=warn
    should be button.btn.btn-info when style=info
    should be button.btn.btn-success when style=success
    should be button.btn.btn-success when style=ok
*/
describe('a Form component containing a SubmitButton', () => {

    it('should include a <Form.SubmitButton> as a child', () => {
        const component = shallow(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find(Form.SubmitButton)).to.have.length(1);
    });

    it('should be a button.btn', () => {
        const component = render(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn')).to.have.length(1, 'button.btn.btn-default');
    });

    it('should have the label specified by the `label` property', () => {
        const label = 'my label';

        const component = render(
            <Form>
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').text()).to.equal(label);
    });

    it('should have the default label if no `label` property specified', () => {
        const component = render(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find('button.btn').text()).to.equal('Submit');
    });

    it('should be button.btn.btn-default when no style is provided', () => {
        const component = render(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-default')).to.have.length(1, 'button.btn.btn-default');
    });

    it('should be button.btn.btn-danger when style=danger', () => {

        const style = 'danger';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-danger')).to.have.length(1, 'button.btn.btn-danger');
    });

    it('should be button.btn.btn-danger when style=error', () => {

        const style = 'error';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-danger')).to.have.length(1, 'button.btn.btn-danger');
    });

    it('should be button.btn.btn-warning when style=warning', () => {

        const style = 'warning';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-warning')).to.have.length(1, 'button.btn.btn-warning');
    });

    it('should be button.btn.btn-warning when style=warn', () => {

        const style = 'warn';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-warning')).to.have.length(1, 'button.btn.btn-warning');
    });

    it('should be button.btn.btn-info when style=info', () => {

        const style = 'info';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-info')).to.have.length(1, 'button.btn.btn-info');
    });

    it('should be button.btn.btn-success when style=success', () => {

        const style = 'success';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-success')).to.have.length(1, 'button.btn.btn-success');
    });

    it('should be button.btn.btn-success when style=ok', () => {

        const style = 'ok';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-success')).to.have.length(1, 'button.btn.btn-success');
    });
});

/* *****************************************************************************
given a Form containing a required TextInput and a SubmitButton
    after initialization with a valid value, the SubmitButton should be enabled
    after initialization with several valid values, the SubmitButton should be enabled
    after initialization with multiple invalid values, the SubmitButton should be disabled
    after initialization with a mix of valid & invalid values, the SubmitButton should be disabled
    after changing from invalid to valid, the SubmitButton should be enabled
    after changing from valid to invalid, the SubmitButton should be disabled
*/
describe('given a Form containing a required TextInput and a SubmitButton', () => {

    it('after initialization with a valid value, the SubmitButton should be enabled', () => {
        const label = 'my label';

        const value = 'a valid value';

        const component = mount(
            <Form>
                <Form.TextInput required value={value} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(false);
    });

    it('after initialization with several valid values, the SubmitButton should be enabled', () => {
        const label = 'my label';

        const value = 'a valid value';

        const component = mount(
            <Form>
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(false);
    });

    it('after initialization with multiple invalid values, the SubmitButton ' +
        'should be disabled', () => {
        const label = 'my label';

        const value = '';

        const component = mount(
            <Form>
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(true);
    });

    it('after initialization with a mix of valid & invalid values, the ' +
        'SubmitButton should be disabled', () => {
        const label = 'my label';

        const invalid = '';

        const valid = 'triceratops';

        const component = mount(
            <Form>
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={valid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(true);
    });

    it('after changing from invalid to valid, the SubmitButton should be enabled', () => {
        const label = 'my label';

        const initialValue = '';

        const finalValue = 'I wish I were an Oscar Meyer weiner';

        const component = mount(
            <Form>
                <Form.TextInput required value={initialValue} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(true);

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        component.find('input').simulate('blur');

        expect(component.find('button.btn').props().disabled).to.equal(false);
    });

    it('after changing from valid to invalid, the SubmitButton should be disabled', () => {
        const label = 'my label';

        const initialValue = 'I wish I were an Oscar Meyer weiner';

        const finalValue = '';

        const component = mount(
            <Form>
                <Form.TextInput required value={initialValue} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(false);

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        component.find('input').simulate('blur');

        expect(component.find('button.btn').props().disabled).to.equal(true);
    });

});

/* *****************************************************************************
a SubmitButton
    should call onClick when the button in a form is clicked
*/
describe('a SubmitButton', () => {

    it('should call onClick when the button in a form is clicked', () => {

        const onClick = sinon.spy();

        const label = 'my label';

        const component = mount(
            <Form>
                <Form.SubmitButton label={label} onClick={onClick} />
            </Form>
        );

        component.find('button').simulate('click');

        expect(onClick.callCount).to.equal(1);
    });
});
<commit_msg>code cleanup<commit_after>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, render, mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';

import Form from '../Form';

const expect = chai.expect;

/* eslint-disable no-unused-vars */
const debug = (component) => {
    console.info('------------------------------------------------------------');
    console.info(component.debug());
    console.info('------------------------------------------------------------');
};
/* eslint-enable no-unused-vars */

/* *****************************************************************************
a Form component containing a SubmitButton
    should include a <Form.SubmitButton> as a child
    should be a button.btn
    should have the label specified by the `label` property
    should have the default label if no `label` property specified

    should be button.btn.btn-default when no style is provided
    should be button.btn.btn-danger when style=danger
    should be button.btn.btn-danger when style=error
    should be button.btn.btn-warning when style=warning
    should be button.btn.btn-warning when style=warn
    should be button.btn.btn-info when style=info
    should be button.btn.btn-success when style=success
    should be button.btn.btn-success when style=ok
*/
describe('a Form component containing a SubmitButton', () => {

    it('should include a <Form.SubmitButton> as a child', () => {
        const component = shallow(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find(Form.SubmitButton)).to.have.length(1);
    });

    it('should be a button.btn', () => {
        const component = render(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn')).to.have.length(1, 'button.btn.btn-default');
    });

    it('should have the label specified by the `label` property', () => {
        const label = 'my label';

        const component = render(
            <Form>
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').text()).to.equal(label);
    });

    it('should have the default label if no `label` property specified', () => {
        const component = render(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find('button.btn').text()).to.equal('Submit');
    });

    it('should be button.btn.btn-default when no style is provided', () => {
        const component = render(
            <Form>
                <Form.SubmitButton />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-default'))
            .to.have.length(1, 'button.btn.btn-default');
    });

    it('should be button.btn.btn-danger when style=danger', () => {

        const style = 'danger';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-danger')).to.have.length(1, 'button.btn.btn-danger');
    });

    it('should be button.btn.btn-danger when style=error', () => {

        const style = 'error';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-danger')).to.have.length(1, 'button.btn.btn-danger');
    });

    it('should be button.btn.btn-warning when style=warning', () => {

        const style = 'warning';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-warning'))
            .to.have.length(1, 'button.btn.btn-warning');
    });

    it('should be button.btn.btn-warning when style=warn', () => {

        const style = 'warn';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-warning'))
            .to.have.length(1, 'button.btn.btn-warning');
    });

    it('should be button.btn.btn-info when style=info', () => {

        const style = 'info';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-info')).to.have.length(1, 'button.btn.btn-info');
    });

    it('should be button.btn.btn-success when style=success', () => {

        const style = 'success';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-success'))
            .to.have.length(1, 'button.btn.btn-success');
    });

    it('should be button.btn.btn-success when style=ok', () => {

        const style = 'ok';

        const component = render(
            <Form>
                <Form.SubmitButton style={style} />
            </Form>
        );

        expect(component.find('button')).to.have.length(1, 'button');
        expect(component.find('button.btn.btn-success'))
            .to.have.length(1, 'button.btn.btn-success');
    });
});

/* *****************************************************************************
given a Form containing a required TextInput and a SubmitButton
    after initialization with a valid value, the SubmitButton should be enabled
    after initialization with several valid values, the SubmitButton should be enabled
    after initialization with multiple invalid values, the SubmitButton should be disabled
    after initialization with a mix of valid & invalid values, the SubmitButton should be disabled
    after changing from invalid to valid, the SubmitButton should be enabled
    after changing from valid to invalid, the SubmitButton should be disabled
*/
describe('given a Form containing a required TextInput and a SubmitButton', () => {

    it('after initialization with a valid value, the SubmitButton should be enabled', () => {
        const label = 'my label';

        const value = 'a valid value';

        const component = mount(
            <Form>
                <Form.TextInput required value={value} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(false);
    });

    it('after initialization with several valid values, the SubmitButton should be enabled', () => {
        const label = 'my label';

        const value = 'a valid value';

        const component = mount(
            <Form>
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(false);
    });

    it('after initialization with multiple invalid values, the SubmitButton ' +
        'should be disabled', () => {
        const label = 'my label';

        const value = '';

        const component = mount(
            <Form>
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.TextInput required value={value} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(true);
    });

    it('after initialization with a mix of valid & invalid values, the ' +
        'SubmitButton should be disabled', () => {
        const label = 'my label';

        const invalid = '';

        const valid = 'triceratops';

        const component = mount(
            <Form>
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={valid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(true);
    });

    it('after changing from invalid to valid, the SubmitButton should be enabled', () => {
        const label = 'my label';

        const initialValue = '';

        const finalValue = 'I wish I were an Oscar Meyer weiner';

        const component = mount(
            <Form>
                <Form.TextInput required value={initialValue} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(true);

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        component.find('input').simulate('blur');

        expect(component.find('button.btn').props().disabled).to.equal(false);
    });

    it('after changing from valid to invalid, the SubmitButton should be disabled', () => {
        const label = 'my label';

        const initialValue = 'I wish I were an Oscar Meyer weiner';

        const finalValue = '';

        const component = mount(
            <Form>
                <Form.TextInput required value={initialValue} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('button.btn').props().disabled).to.equal(false);

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        component.find('input').simulate('blur');

        expect(component.find('button.btn').props().disabled).to.equal(true);
    });

});

/* *****************************************************************************
a SubmitButton
    should call onClick when the button in a form is clicked
*/
describe('a SubmitButton', () => {

    it('should call onClick when the button in a form is clicked', () => {

        const onClick = sinon.spy();

        const label = 'my label';

        const component = mount(
            <Form>
                <Form.SubmitButton label={label} onClick={onClick} />
            </Form>
        );

        component.find('button').simulate('click');

        expect(onClick.callCount).to.equal(1);
    });
});
<|endoftext|>


<commit_before>// DateUtil

// 比较年月日时分秒，大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareDateTime = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setSeconds(0, 0)
  date2.setSeconds(0, 0)
  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 比较年月日,大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareDate = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setHours(0, 0, 0, 0)
  date2.setHours(0, 0, 0, 0)
  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 比较时分,大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareTime = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setYear(0)
  date1.setMonth(0, 0)
  date2.setYear(0)
  date2.setMonth(0, 0)

  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 年
window.Date.prototype.year = function () {
  return this.getFullYear()
}
// 月
window.Date.prototype.month = function () {
  var monthNum = this.getMonth() + 1
  if (monthNum < 10) {
    monthNum = '0' + monthNum
  }
  return monthNum
}
// 日
window.Date.prototype.date = function () {
  var dayNum = this.getDate()
  if (dayNum < 10) {
    dayNum = '0' + dayNum
  }
  return dayNum
}
// 返回当月共多少天
window.Date.prototype.days = function (year, month) {
  if (month && year) {
    return new Date(year, month, 0).getDate()
  }
  return new Date(this.year(), this.month(), 0).getDate()
}
// 时
window.Date.prototype.hour = function () {
  var hourNum = this.getHours()
  if (hourNum < 10) {
    hourNum = '0' + hourNum
  }
  return hourNum
}
// 分
window.Date.prototype.minute = function () {
  var minuteNum = this.getMinutes()
  if (minuteNum < 10) {
    minuteNum = '0' + minuteNum
  }
  return minuteNum
}
// 周,参数:zh_cn
window.Date.prototype.week = function (language) {
  var chinaWeek = { 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 0: '日' }
  if (language === 'zh_cn') {
    return chinaWeek[this.getDay()]
  }
  return this.getDay()
}
// 季
window.Date.prototype.quarter = function () {
  return Math.floor((this.getMonth() + 3) / 3)
}
// 获得当前日期的周数
window.Date.prototype.getWeeksCount = function () {
  var dayMilliSecond = 24 * 60 * 60 * 1000

  var startDate = new Date(this.getFullYear(), 0, 1)
  var startDay = startDate.getDay()
  if (startDay === 0) startDay = 7

  this.setHours(0, 0, 0, 0)
  var currentDay = this.getDay()
  if (currentDay === 0) currentDay = 7

  var dateNum = Math.round((this.getTime() - startDate.getTime() + (startDay - currentDay) * dayMilliSecond) / dayMilliSecond)
  return Math.ceil(dateNum / 7) + 1
}

// Date对象,返回相差天数等
window.Date.prototype.diff = function (date) {
  var dateStart = this // 开始时间
  var dateEnd = date // 结束时间

  var secondMilli = 1000 // 一分钟的毫秒数
  var minuteMilli = 60 * secondMilli // 一分钟的毫秒数
  var hourMilli = 60 * minuteMilli // 一小时的毫秒数
  var dayMilli = 24 * hourMilli // 一天的毫秒数

  var timeDiff = dateEnd.getTime() - dateStart.getTime() // 毫秒差

  // 计算出相差天数
  var daysDiff = Math.floor(timeDiff / dayMilli)
  // 计算出剩余小时数
  var dayMilliRemainder = timeDiff % dayMilli
  var hoursDiff = Math.floor(dayMilliRemainder / hourMilli)
  // 计算剩余分钟数
  var minuteMilliRemainder = dayMilliRemainder % hourMilli
  var minutesDiff = Math.floor(minuteMilliRemainder / minuteMilli)
  // 计算剩余秒数
  var secondMilliRemainder = minuteMilliRemainder % minuteMilli
  var secondsDiff = Math.round(secondMilliRemainder / secondMilli)

  // 计算相差小时数
  var hoursAllDiff = Math.floor(timeDiff / hourMilli)
  // 计算相差分钟数
  var minutesAllDiff = Math.floor(timeDiff / minuteMilli)
  // 计算相差秒数
  var secondsAllDiff = Math.floor(timeDiff / secondMilli)

  return {
    days: daysDiff,
    hours: hoursDiff,
    minutes: minutesDiff,
    seconds: secondsDiff,
    hoursAll: hoursAllDiff,
    minutesAll: minutesAllDiff,
    secondsAll: secondsAllDiff
  }
}
// 减天数
window.Date.prototype.minusDate = function (num) {
  var numMilli = num * 1000 * 60 * 60 * 24
  this.setTime(this.getTime() - numMilli)
  return this
}
// 加天数
window.Date.prototype.plusDate = function (num) {
  var numMilli = num * 1000 * 60 * 60 * 24
  this.setTime(this.getTime() + numMilli)
  return this
}
// 减分钟
window.Date.prototype.minusMinute = function (num) {
  var numMilli = num * 1000 * 60
  this.setTime(this.getTime() - numMilli)
  return this
}
// 加分钟
window.Date.prototype.plusMinute = function (num) {
  var numMilli = num * 1000 * 60
  this.setTime(this.getTime() + numMilli)
  return this
}
// 整数时间，返回日期的档位时间
window.Date.prototype.setMinuteCeil = function (space) {
  /* eslint-disable */
  var space = space ? space : 5 // 间隔
  /* eslint-enable */
  var minute = this.getMinutes() // 分钟
  var hasRemainder = minute % space === 0 // 是否有余数

  var percentNum = Math.ceil(minute / space) // 档位
  percentNum = hasRemainder ? parseInt(percentNum, 10) + 1 : percentNum

  var result = percentNum * space // 根据档位计算结果
  this.setMinutes(result)
  return this
}
// 整数时间，返回日期的档位时间
window.Date.prototype.setMinuteFloor = function (space) {
  /* eslint-disable */
  var space = space ? space : 5 // 间隔
  /* eslint-enable */
  var minute = this.getMinutes() // 分钟
  var hasRemainder = minute % space === 0 // 是否有余数

  var percentNum = Math.floor(minute / space) // 档位
  percentNum = hasRemainder ? parseInt(percentNum, 10) - 1 : percentNum

  var result = percentNum * space // 根据档位计算结果
  this.setMinutes(result)
  return this
}
// 时效性比较,以当前时间为基准,支持比较'日期对象' / '小时数' / 'today'
window.Date.prototype.expires = function (expiresTime) {
  if (!expiresTime) return
  var endTime = new Date(this)
  // 如果参数是日期
  if (expiresTime instanceof Date === true) {
    if (endTime.compareDateTime(expiresTime) === -1) {
      return expiresTime
    } else {
      endTime.setHours(0, 0, 0, 0)
      return endTime.plusDay(1)
    }
  }

  // 如果参数是小时
  if (!isNaN(expiresTime)) {
    var numMilli = expiresTime * 1000 * 60 * 60
    endTime = new Date(endTime.getTime() + numMilli)
    return endTime
  }

  // 如果参数是今天
  if (expiresTime === 'today') {
    endTime.setHours(0, 0, 0, 0)
    return endTime.plusDay(1)
  }
}
// 格式化日期,参数:yyyy-MM-dd hh:mm:ss WW EE
window.Date.prototype.format = function (fmtModel) {
  var fmt = typeof fmtModel === 'string' ? fmtModel : 'yyyy-MM-dd hh:mm:ss'
  var year = this.getFullYear()
  var month = this.getMonth() + 1
  var date = this.getDate()
  var hour = this.getHours()
  var minute = this.getMinutes()
  var second = this.getSeconds()
  var weeksCount = this.getWeeksCount()
  var week = this.week('zh_cn')

  var dateJson = {
    'M+': month,
    'd+': date,
    'h+': hour,
    'm+': minute,
    's+': second,
    'W+': weeksCount,
    'E+': week
  }
  if (/(y+)/.test(fmt)) { // 匹配年
    fmt = fmt.replace(RegExp.$1, (year + '').substr(4 - RegExp.$1.length))
  }
  for (var k in dateJson) { // 逐个匹配
    // '('+ k +')'=(M+)、(d+)、(h+)...
    if (new RegExp('(' + k + ')').test(fmt)) {
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (dateJson[k]) : (('00' + dateJson[k]).substr(('' + dateJson[k]).length)))
    }
  }
  return fmt
}
// 获取月头和月尾
window.Date.prototype.monthStartEnd = function () {
  var year = this.year()
  var month = this.month()
  var firstDay = '01'
  var lastDay = this.days()
  if (lastDay < 10) lastDay = '0' + lastDay
  return {
    start: new Date(year + '-' + month + '-' + firstDay),
    end: new Date(year + '-' + month + '-' + lastDay)
  }
}
<commit_msg>增强日期控件<commit_after>// DateUtil

// 比较年月日时分秒，大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareDateTime = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setSeconds(0, 0)
  date2.setSeconds(0, 0)
  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 比较年月日,大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareDate = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setHours(0, 0, 0, 0)
  date2.setHours(0, 0, 0, 0)
  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 比较年月,大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareMonth = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setDate(0)
  date1.setHours(0, 0, 0, 0)
  date2.setDate(0)
  date2.setHours(0, 0, 0, 0)
  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 比较时分,大于返回1,等于返回0,小于返回-1
window.Date.prototype.compareTime = function (date) {
  var date1 = new Date(this)
  var date2 = new Date(date)
  date1.setYear(0)
  date1.setMonth(0, 0)
  date2.setYear(0)
  date2.setMonth(0, 0)

  var t1 = date1.getTime()
  var t2 = date2.getTime()

  if (t1 === t2) return 0
  return t1 > t2 ? 1 : -1
}
// 年
window.Date.prototype.year = function () {
  return this.getFullYear()
}
// 月
window.Date.prototype.month = function () {
  var monthNum = this.getMonth() + 1
  if (monthNum < 10) {
    monthNum = '0' + monthNum
  }
  return monthNum
}
// 日
window.Date.prototype.date = function () {
  var dayNum = this.getDate()
  if (dayNum < 10) {
    dayNum = '0' + dayNum
  }
  return dayNum
}
// 返回当月共多少天
window.Date.prototype.days = function (year, month) {
  if (month && year) {
    return new Date(year, month, 0).getDate()
  }
  return new Date(this.year(), this.month(), 0).getDate()
}
// 时
window.Date.prototype.hour = function () {
  var hourNum = this.getHours()
  if (hourNum < 10) {
    hourNum = '0' + hourNum
  }
  return hourNum
}
// 分
window.Date.prototype.minute = function () {
  var minuteNum = this.getMinutes()
  if (minuteNum < 10) {
    minuteNum = '0' + minuteNum
  }
  return minuteNum
}
// 周,参数:zh_cn
window.Date.prototype.week = function (language) {
  var chinaWeek = { 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 0: '日' }
  if (language === 'zh_cn') {
    return chinaWeek[this.getDay()]
  }
  return this.getDay()
}
// 季
window.Date.prototype.quarter = function () {
  return Math.floor((this.getMonth() + 3) / 3)
}
// 获得当前日期的周数
window.Date.prototype.getWeeksCount = function () {
  var dayMilliSecond = 24 * 60 * 60 * 1000

  var startDate = new Date(this.getFullYear(), 0, 1)
  var startDay = startDate.getDay()
  if (startDay === 0) startDay = 7

  this.setHours(0, 0, 0, 0)
  var currentDay = this.getDay()
  if (currentDay === 0) currentDay = 7

  var dateNum = Math.round((this.getTime() - startDate.getTime() + (startDay - currentDay) * dayMilliSecond) / dayMilliSecond)
  return Math.ceil(dateNum / 7) + 1
}

// Date对象,返回相差天数等
window.Date.prototype.diff = function (date) {
  var dateStart = this // 开始时间
  var dateEnd = date // 结束时间

  var secondMilli = 1000 // 一分钟的毫秒数
  var minuteMilli = 60 * secondMilli // 一分钟的毫秒数
  var hourMilli = 60 * minuteMilli // 一小时的毫秒数
  var dayMilli = 24 * hourMilli // 一天的毫秒数

  var timeDiff = dateEnd.getTime() - dateStart.getTime() // 毫秒差

  // 计算出相差天数
  var daysDiff = Math.floor(timeDiff / dayMilli)
  // 计算出剩余小时数
  var dayMilliRemainder = timeDiff % dayMilli
  var hoursDiff = Math.floor(dayMilliRemainder / hourMilli)
  // 计算剩余分钟数
  var minuteMilliRemainder = dayMilliRemainder % hourMilli
  var minutesDiff = Math.floor(minuteMilliRemainder / minuteMilli)
  // 计算剩余秒数
  var secondMilliRemainder = minuteMilliRemainder % minuteMilli
  var secondsDiff = Math.round(secondMilliRemainder / secondMilli)

  // 计算相差小时数
  var hoursAllDiff = Math.floor(timeDiff / hourMilli)
  // 计算相差分钟数
  var minutesAllDiff = Math.floor(timeDiff / minuteMilli)
  // 计算相差秒数
  var secondsAllDiff = Math.floor(timeDiff / secondMilli)

  return {
    days: daysDiff,
    hours: hoursDiff,
    minutes: minutesDiff,
    seconds: secondsDiff,
    hoursAll: hoursAllDiff,
    minutesAll: minutesAllDiff,
    secondsAll: secondsAllDiff
  }
}
// 减天数
window.Date.prototype.minusDate = function (num) {
  var numMilli = num * 1000 * 60 * 60 * 24
  this.setTime(this.getTime() - numMilli)
  return this
}
// 加天数
window.Date.prototype.plusDate = function (num) {
  var numMilli = num * 1000 * 60 * 60 * 24
  this.setTime(this.getTime() + numMilli)
  return this
}
// 减分钟
window.Date.prototype.minusMinute = function (num) {
  var numMilli = num * 1000 * 60
  this.setTime(this.getTime() - numMilli)
  return this
}
// 加分钟
window.Date.prototype.plusMinute = function (num) {
  var numMilli = num * 1000 * 60
  this.setTime(this.getTime() + numMilli)
  return this
}
// 整数时间，返回日期的档位时间
window.Date.prototype.setMinuteCeil = function (space) {
  /* eslint-disable */
  var space = space ? space : 5 // 间隔
  /* eslint-enable */
  var minute = this.getMinutes() // 分钟
  var hasRemainder = minute % space === 0 // 是否有余数

  var percentNum = Math.ceil(minute / space) // 档位
  percentNum = hasRemainder ? parseInt(percentNum, 10) + 1 : percentNum

  var result = percentNum * space // 根据档位计算结果
  this.setMinutes(result)
  return this
}
// 整数时间，返回日期的档位时间
window.Date.prototype.setMinuteFloor = function (space) {
  /* eslint-disable */
  var space = space ? space : 5 // 间隔
  /* eslint-enable */
  var minute = this.getMinutes() // 分钟
  var hasRemainder = minute % space === 0 // 是否有余数

  var percentNum = Math.floor(minute / space) // 档位
  percentNum = hasRemainder ? parseInt(percentNum, 10) - 1 : percentNum

  var result = percentNum * space // 根据档位计算结果
  this.setMinutes(result)
  return this
}
// 时效性比较,以当前时间为基准,支持比较'日期对象' / '小时数' / 'today'
window.Date.prototype.expires = function (expiresTime) {
  if (!expiresTime) return
  var endTime = new Date(this)
  // 如果参数是日期
  if (expiresTime instanceof Date === true) {
    if (endTime.compareDateTime(expiresTime) === -1) {
      return expiresTime
    } else {
      endTime.setHours(0, 0, 0, 0)
      return endTime.plusDay(1)
    }
  }

  // 如果参数是小时
  if (!isNaN(expiresTime)) {
    var numMilli = expiresTime * 1000 * 60 * 60
    endTime = new Date(endTime.getTime() + numMilli)
    return endTime
  }

  // 如果参数是今天
  if (expiresTime === 'today') {
    endTime.setHours(0, 0, 0, 0)
    return endTime.plusDay(1)
  }
}
// 格式化日期,参数:yyyy-MM-dd hh:mm:ss WW EE
window.Date.prototype.format = function (fmtModel) {
  var fmt = typeof fmtModel === 'string' ? fmtModel : 'yyyy-MM-dd hh:mm:ss'
  var year = this.getFullYear()
  var month = this.getMonth() + 1
  var date = this.getDate()
  var hour = this.getHours()
  var minute = this.getMinutes()
  var second = this.getSeconds()
  var weeksCount = this.getWeeksCount()
  var week = this.week('zh_cn')

  var dateJson = {
    'M+': month,
    'd+': date,
    'h+': hour,
    'm+': minute,
    's+': second,
    'W+': weeksCount,
    'E+': week
  }
  if (/(y+)/.test(fmt)) { // 匹配年
    fmt = fmt.replace(RegExp.$1, (year + '').substr(4 - RegExp.$1.length))
  }
  for (var k in dateJson) { // 逐个匹配
    // '('+ k +')'=(M+)、(d+)、(h+)...
    if (new RegExp('(' + k + ')').test(fmt)) {
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (dateJson[k]) : (('00' + dateJson[k]).substr(('' + dateJson[k]).length)))
    }
  }
  return fmt
}
// 获取月头和月尾
window.Date.prototype.monthStartEnd = function () {
  var year = this.year()
  var month = this.month()
  var firstDay = '01'
  var lastDay = this.days()
  if (lastDay < 10) lastDay = '0' + lastDay
  return {
    start: new Date(year + '-' + month + '-' + firstDay),
    end: new Date(year + '-' + month + '-' + lastDay)
  }
}
<|endoftext|>