import { shallow } from 'enzyme';
import React from 'react';

import PasswordStrength from '../../modules/PasswordStrength';
import createPasswordStrengthComponent from './createPasswordStrengthComponent';

describe('createPasswordStrengthComponent function', () => {
  const STATE_FIXTURE = {
    password: 'p@55w0rd',
    handlePasswordValidation: jest.fn(),
  };

  const Context = React.createContext();

  let Component;

  let wrapper;

  beforeEach(() => {
    Component = createPasswordStrengthComponent('DisplayName', Context);
    wrapper = shallow(<Component />);
  });

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

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

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

  it('renders a PasswordStrength meter', () => {
    expect(getPasswordStrength()).toExist();
  });

  it('passes props down to the PasswordStrength', () => {
    wrapper.setProps({ minCharacters: 10 });
    expect(getPasswordStrength()).toHaveProp('minCharacters', 10);
  });

  it('copies propTypes from the PasswordStrength', () => {
    // Check a representative prop
    expect(Component.propTypes.minCharacters)
      .toBe(PasswordStrength.propTypes.minCharacters);
  });

  it('does not define a password prop', () => {
    expect(Component.propTypes).not.toHaveProperty('password');
  });

  it('propagates changes to the Context', () => {
    STATE_FIXTURE.handlePasswordValidation.mockClear();
    getPasswordStrength().simulate('validate', 'status');
    expect(STATE_FIXTURE.handlePasswordValidation).toHaveBeenCalled();
    expect(STATE_FIXTURE.handlePasswordValidation)
      .toHaveBeenCalledWith('status');
  });

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

    getPasswordStrength().simulate('validate', 'status');

    expect(onValidate).toHaveBeenCalled();
    expect(onValidate).toHaveBeenCalledWith('status');
  });

  it('sets the password', () => {
    expect(getPasswordStrength()).toHaveProp('password', 'p@55w0rd');
  });

  it('ignores attempts to change the password', () => {
    wrapper.setProps({ password: 'other' });
    expect(getPasswordStrength()).toHaveProp('password', 'p@55w0rd');
  });
});
