// @flow
import React from 'react';
import { mount } from 'enzyme';
import { mountWrappedComponent, itIsAccessible } from '../../../../utils/tests';

import type { ClickOutsideProps } from './click-outside.proptypes';
import { ClickOutside } from './index';

const DEFAULT_PROPS: ClickOutsideProps = {
  children: <div>Test Child</div>,
  onClickOutside: jest.fn(),
};

describe('ClickOutside', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it('onClickOutside is called if clicked outside', () => {
    const map = {};
    global.document.addEventListener = jest.fn((event, callback) => {
      map[event] = callback;
    });

    const clickOutside = mountWrappedComponent(
      <div>
        <button type="button">OUTSIDE</button>
        <ClickOutside {...DEFAULT_PROPS}>
          <b>INSIDE</b>
        </ClickOutside>
      </div>,
    );

    expect(DEFAULT_PROPS.onClickOutside).toHaveBeenCalledTimes(0);
    map.click({ target: clickOutside.find('button').instance() });
    expect(DEFAULT_PROPS.onClickOutside).toHaveBeenCalledTimes(1);
  });

  it('onClickOutside does not get called if clicked inside', () => {
    const map = {};
    global.document.addEventListener = jest.fn((event, callback) => {
      map[event] = callback;
    });

    const clickOutside = mountWrappedComponent(
      <div>
        <button type="button">OUTSIDE</button>
        <ClickOutside {...DEFAULT_PROPS}>
          <b>INSIDE</b>
        </ClickOutside>
      </div>,
    );

    expect(DEFAULT_PROPS.onClickOutside).toHaveBeenCalledTimes(0);
    map.click({ target: clickOutside.find('b').instance() });
    expect(DEFAULT_PROPS.onClickOutside).toHaveBeenCalledTimes(0);
  });

  it('adds a click event listener when mounted', () => {
    global.document.addEventListener = jest.fn();

    const clickOutside = mount(
      <div>
        <button type="button">OUTSIDE</button>
        <ClickOutside {...DEFAULT_PROPS}>
          <b>INSIDE</b>
        </ClickOutside>
      </div>,
    );

    expect(global.document.addEventListener).toHaveBeenCalledTimes(1);
    expect(global.document.addEventListener).toHaveBeenCalledWith(
      'click',
      expect.any(Function),
      true,
    );

    clickOutside.unmount();

    expect(global.document.addEventListener).toHaveBeenCalledTimes(1);
  });

  it('removes a click event listener when unmounted', () => {
    global.document.removeEventListener = jest.fn();

    const clickOutside = mount(
      <div>
        <button type="button">OUTSIDE</button>
        <ClickOutside {...DEFAULT_PROPS}>
          <b>INSIDE</b>
        </ClickOutside>
      </div>,
    );

    expect(global.document.removeEventListener).toHaveBeenCalledTimes(0);

    clickOutside.unmount();

    expect(global.document.removeEventListener).toHaveBeenCalledTimes(1);
    expect(global.document.removeEventListener).toHaveBeenCalledWith(
      'click',
      expect.any(Function),
      true,
    );
  });

  itIsAccessible(
    <div>
      <button type="button">OUTSIDE</button>
      <ClickOutside {...DEFAULT_PROPS}>
        <b>INSIDE</b>
      </ClickOutside>
    </div>,
  );
});
