import { shallow } from 'enzyme';
import React from 'react';
import { Input } from 'semantic-ui-react';

import createInputComponent from './createInputComponent';

describe('createInputComponent function', () => {
  const STATE_FIXTURE = {
    testName: 'testName value',
    handleChange: jest.fn(),
  };

  const Context = React.createContext();

  let Component;

  let wrapper;

  beforeEach(() => {
    Component = createInputComponent(
      'DisplayName',
      Context,
      'testName',
      { extra: 'prop' }
    );
    wrapper = shallow(<Component />);
  });

  const getInput = () => {
    const children = wrapper.find(Context.Consumer).prop('children');
    return shallow(<div>{ children(STATE_FIXTURE) }</div>).find('Input');
  };

  it('renders', () => {
    expect(wrapper).toExist();
  });

  it('renders a Consumer to retrieve the context', () => {
    expect(wrapper.find(Context.Consumer)).toExist();
  });

  it('renders an Input', () => {
    expect(getInput()).toExist();
  });

  it('passes props down to the Input', () => {
    const placeholder = 'test placeholder';
    wrapper.setProps({ placeholder });
    expect(getInput()).toHaveProp('placeholder', placeholder);
  });

  it('copies propTypes from the Input', () => {
    expect(Component.propTypes).toBe(Input.propTypes);
  });

  it('sets the name', () => {
    expect(getInput()).toHaveProp('name', 'testName');
  });

  it('ignores attempts to change the name', () => {
    wrapper.setProps({ name: 'other' });
    expect(getInput()).toHaveProp('name', 'testName');
  });

  it('propagates changes to the Context', () => {
    STATE_FIXTURE.handleChange.mockClear();
    getInput().simulate('change', 'event', 'data');
    expect(STATE_FIXTURE.handleChange).toHaveBeenCalled();
    expect(STATE_FIXTURE.handleChange).toHaveBeenCalledWith('event', 'data');
  });

  it('can propagate changes to an onChange handler', () => {
    const onChange = jest.fn();
    wrapper.setProps({ onChange });

    getInput().simulate('change', 'event', 'data');

    expect(onChange).toHaveBeenCalled();
    expect(onChange).toHaveBeenCalledWith('event', 'data');
  });

  it('adds extra props', () => {
    expect(getInput()).toHaveProp('extra', 'prop');
  });

  it('ignores attempts to change the extra props', () => {
    wrapper.setProps({ extra: 'other' });
    expect(getInput()).toHaveProp('extra', 'prop');
  });

  it('copes if no extra props are supplied', () => {
    Component = createInputComponent('DisplayName', Context, 'testName', { });
    // Test succeeds if no errors
  });

  it('sets the value from the Context', () => {
    expect(getInput()).toHaveProp('value', 'testName value');
  });

  it('ignores attempts to change the value', () => {
    wrapper.setProps({ value: 'other' });
    expect(getInput()).toHaveProp('value', 'testName value');
  });

  it('sets the component display name', () => {
    expect(Component.displayName).toBe('DisplayName');
  });
});
