import AsyncSearch from '../asyncSearch'

describe('AsyncSearch', () => {
  const onSelectionChange = sinon.stub()
  const promiseStub = sinon.stub()
  const debounceDelay = 500

  const props = {
    search: () => ({ then: promiseStub }),
    onSelectionChange,
    selectedOption: [],
    debounceDelay
  }

  const testbed = createTestbed(AsyncSearch, props)

  let clock = null
  beforeEach(() => {
    clock = sinon.useFakeTimers()
  })

  afterEach(() => {
    clock.restore()
    onSelectionChange.resetHistory()
    promiseStub.resetHistory()
  })

  shouldRenderComponent(testbed, {}, AsyncSearch)

  it('clears search results when empty input', () => {
    const subject = testbed.render()
    sinon.spy(subject, 'setState')
    subject.handleSearchInputChange({}, 'new search value')
    subject.handleSearchInputChange({}, '')
    expect(subject.setState).to.have.been.calledWith({
      emptyOption: 'Write to search',
      searchResult: []
    })
  })

  it('clears seach results when the menu closes if empty input', () => {
    const subject = testbed.render()
    sinon.spy(subject, 'setState')
    subject.handleClose()
    expect(subject.setState).to.have.been.calledWith({
      emptyOption: 'Write to search',
      searchResult: []
    })
  })

  it('should delay the search call', () => {
    const shallowTestbed = testbed.renderShallowly()
    const change = shallowTestbed.find('Select').at(0).props().onInputChange
    change({}, 'new search value')

    clock.tick(debounceDelay - 1)
    expect(promiseStub).to.not.be.called()
    clock.tick(1)
    expect(promiseStub).to.be.calledOnce()
  })

  it('should call search with a debounce', () => {
    const shallowTestbed = testbed.renderShallowly()
    const change = shallowTestbed.find('Select').at(0).props().onInputChange
    change({}, 'new search value')

    clock.tick(debounceDelay - 1)
    expect(promiseStub).to.not.be.called()

    change({}, 'haha! foiled!')
    clock.tick(debounceDelay - 1)
    expect(promiseStub).to.not.be.called()
    clock.tick(1)
    expect(promiseStub).to.be.calledOnce()
  })

  it('should populate the search results once they arrive', () => {
    const shallowTestbed = testbed.renderShallowly({
      search: () => {
        return {then: (fn) => fn([{
          uuid: '0',
          fullName: 'first fullName',
          avatar: 'http://avatars.com/avatar1'
        }, {
          uuid: '1',
          fullName: 'second fullName',
          avatar: 'http://avatars.com/avatar2'
        }])}
      }
    })
    const change = shallowTestbed.find('Select').at(0).props().onInputChange
    change({}, 'new search value')
    clock.tick(100)
    expect(shallowTestbed.find('Select').at(0).props().children.length).to.equal(0)
    clock.tick(debounceDelay)
    expect(shallowTestbed.find('Select').at(0).props().children.length).to.equal(2)
  })
})
