describe 'TextInput 2', ->
  React = require 'react'
  TextInput = React.createFactory require('../../src/components/text_input_2')
  TestUtils = require 'react-addons-test-utils'
  ReactDOM = require 'react-dom'
  dispatcher = require('../../src/dispatcher')

  afterEach -> dispatcher.dispatch 'clear-all'

  #--------------------------------------------------------------------- Default Props
  it 'Should have default props', ->
    input = TestUtils.renderIntoDocument TextInput({})
    
    defaultProps = input.props
    expect(defaultProps.type).to.equal('text')
    expect(defaultProps.loading).to.equal(no)
    expect(defaultProps.className).to.equal('text-input')
    expect(defaultProps.placeholder).to.equal('')
    expect(defaultProps.validation).to.equal(off)
    expect(defaultProps.disabled).to.equal(no)
    expect(defaultProps.showClear).to.equal(no)
    expect(defaultProps.autoComplete).to.equal(no)
    expect(defaultProps.isInPopover).to.equal(no)
    expect(defaultProps.spellCheck).to.equal(no)
    expect(defaultProps.focusOnMount).to.equal(no)

  #--------------------------------------------------------------------- Spinner
  it 'Should show a spinner when the loading prop is true', ->

    input = TestUtils.renderIntoDocument TextInput {
        loading: yes
      }

    inputSpinner = TestUtils.scryRenderedDOMComponentsWithClass input, 'input-spinner'

    expect(inputSpinner.length).to.equal(1)

  #--------------------------------------------------------------------- Validation
  it 'Should not show an error when the validation is off', ->
    
    input = TestUtils.renderIntoDocument TextInput {
        loading: no
        validation: off
      }

    el = ReactDOM.findDOMNode input

    expect(el.className).to.equal('field-wrap')

  it 'Should NOT show an error before a change has ocurred', ->
    node = document.createElement('div')
    document.body.appendChild(node)
    input = ReactDOM.render TextInput({
      key: 'test'
      loading: no
      validation: null
      value: ''
    }), node

    el = ReactDOM.findDOMNode input

    expect(el.className).to.equal('field-wrap')

  it 'Should set valueHasChanged to true after a change occurs', ->
    textInput = TestUtils.renderIntoDocument TextInput {
      key: 'test'
      loading: no
      validation: null
      value: ''
    }

    expect(textInput.state.valueHasChanged).to.equal(no)

    input = TestUtils.findRenderedDOMComponentWithClass textInput, 'text-input'
    TestUtils.Simulate.change input, {
      key: 'Enter'
      type: 'keyup'
    }

    expect(textInput.state.valueHasChanged).to.equal(yes)


  it 'Should show an error before a change has ocurred and forceShowAllErrors is on', () ->
    node = document.createElement('div')
    document.body.appendChild(node)
    input = ReactDOM.render TextInput({
      key: 'test'
      loading: no
      validation: []
      value: ''
    }), node

    dispatcher.dispatch 'force-show-all'
    
    el = ReactDOM.findDOMNode input
    expect(el.className).to.equal('field-wrap invalid')
  
  it 'Should show an error when the validation is static non null value and a change occurs', ->
    textInput = TestUtils.renderIntoDocument TextInput {
      key: 'test'
      loading: no
      validation:
        messages: ['fail']
      value: ''
    }

    input = TestUtils.findRenderedDOMComponentWithClass textInput, 'text-input'
    TestUtils.Simulate.change input, {
      key: 'Enter'
      type: 'keyup'
    }

    el = ReactDOM.findDOMNode textInput

    expect(el.className).to.equal('field-wrap invalid')

  it 'Should show an error when the validation is a method that returns a non null value', ->   
    textInput = TestUtils.renderIntoDocument TextInput {
      key: 'test'
      loading: no
      validation: (value) ->
        [
          {
            messages: ['fail']
          }
        ]
      value: ''
    }

    input = TestUtils.findRenderedDOMComponentWithClass textInput, 'text-input'
    TestUtils.Simulate.change input, {
      key: 'Enter'
      type: 'keyup'
    }

    el = ReactDOM.findDOMNode textInput

    expect(el.className).to.equal('field-wrap invalid')

  it 'Should show an error when the validation changes, but not the value', (done) ->
    
    node = document.createElement('div')
    document.body.appendChild(node)
    input = ReactDOM.render TextInput({
      key: 'test'
      loading: no
      validation: null
      value: 'one'
    }), node

    input.setState {valueHasChanged: yes}, ->
      input = ReactDOM.render TextInput({
        key: 'test'
        loading: no
        validation: 
          messages: ['fail']
        value: 'two'
      }), node, ->
        el = ReactDOM.findDOMNode input

        expect(el.className).to.equal('field-wrap invalid')
        done()

  it 'Should not show an error when the validation fails, but loading is on', ->
    
    input = TestUtils.renderIntoDocument TextInput {
        loading: yes
        validation: -> []
      }

    errorBtn = TestUtils.findRenderedDOMComponentWithClass input, 'field-errors-show'
    el = ReactDOM.findDOMNode errorBtn

    expect(el.className).to.equal('field-errors-show is-hidden')

  #--------------------------------------------------------------------- Delayed action
  it 'Should fire a delayed action after a set number of milliseconds', (cb) ->

    actionFn = sinon.spy()

    input = TestUtils.renderIntoDocument TextInput {
      delayedActionOnChange:
        action: actionFn
        interval: 10
    }

    expect(typeof input.props.delayedActionOnChange.action).to.equal('function')
    expect(typeof input.props.delayedActionOnChange.interval).to.equal('number')

    # Fire the action to make sure it's executing
    input.fireDelayedAction()

    setTimeout ->
      expect(actionFn.calledOnce).to.equal(true)
      cb()
    , 20

  #--------------------------------------------------------------------- Text change
  it 'Should set the value of the input to the value prop, and return it with getValue method', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    inputValue = ReactDOM.findDOMNode(subInput).value

    returnedValue = input.getValue()

    expect(inputValue).to.equal('new value')
    expect(returnedValue).to.equal('new value')

  #--------------------------------------------------------------------- DOM State
  it 'Should disable the input when disabled is true', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      disabled: yes
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.disabled).to.equal(yes)

  it 'Should set the tab index', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      tabIndex: 34
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.getAttribute('tabindex')).to.equal('34')

  it 'Should set the DOM id', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      id: 'theOneAndOnly'
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.getAttribute('id')).to.equal('theOneAndOnly')

  it 'Should set the DOM spellcheck attr', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      spellCheck: yes
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.getAttribute('spellcheck')).to.equal('true')


  it 'Should set the DOM autoComplete attr', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      autoComplete: "on"
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.getAttribute('autocomplete')).to.equal('on')

  it 'Should set the DOM max length attr', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      maxLength: 4
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.getAttribute('maxlength')).to.equal('4')


  it 'Should set the DOM placeholder attr', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      placeholder: 'type something here'
    }

    subInput = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'
    el = ReactDOM.findDOMNode(subInput)

    expect(el.getAttribute('placeholder')).to.equal('type something here')

  it 'Should apply the wrapper class to the outer div', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      wrapperClass: 'blanket'
    }

    matches = TestUtils.scryRenderedDOMComponentsWithClass input, 'blanket'

    expect(matches.length).to.equal(1)

  it 'Should apply arbitrary inline styles to the wrapper div passed in a style prop', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      style: 
        width: 239
    }

    el = ReactDOM.findDOMNode(input)

    expect(el.style.width).to.equal("239px")

  it 'Should wrap the input component in a label element when wrapperLabel is passed', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      wrapperLabel: 'First Name'
    }

    matches = TestUtils.scryRenderedDOMComponentsWithTag input, 'label'

    expect(matches.length).to.equal(1)

  #--------------------------------------------------------------------- Clear button
  it 'Should show a clear button when text is entered and showClear is on', ->

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      showClear: on
    }

    clear = TestUtils.scryRenderedDOMComponentsWithClass input, 'search-clear'

    expect(clear.length).to.equal(1)

  it 'Should clear the input when clear button is clicked', (cb) ->

    method = sinon.spy()

    input = TestUtils.renderIntoDocument TextInput {
      value: 'new value'
      showClear: on
      onChange: method
    }

    clear = TestUtils.findRenderedDOMComponentWithClass input, 'search-clear'

    TestUtils.Simulate.click clear

    setTimeout ->
      expect(method.calledWith('')).to.equal(true)
      cb()
    , 10

  
  #--------------------------------------------------------------------- handlers
  it 'Should fire a passed onKeyUp handler on key up', (cb) ->

    method = sinon.spy()

    input = TestUtils.renderIntoDocument TextInput {
      onKeyUp: method
      value: 'test'
    }

    input = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'

    TestUtils.Simulate.keyUp input, {
      key: 'Enter'
      type: 'keyup'
    }

    setTimeout ->
      expect(method.calledOnce).to.equal(true)
      cb()
    , 10

  it 'Should fire a passed onChange handler, passing the input value as the param, on change', (cb) ->

    method = sinon.spy()

    input = TestUtils.renderIntoDocument TextInput {
      onChange: method
      value: 'test'
    }

    input = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'

    TestUtils.Simulate.change input, {
      key: 'Enter'
      type: 'keyup'
    }

    setTimeout ->
      expect(method.calledOnce).to.equal(true)
      expect(method.calledWith('test')).to.equal(true)
      cb()
    , 10

   it 'Should fire a passed onEnterKey handler on enter press', (cb) ->

    method = sinon.spy()

    input = TestUtils.renderIntoDocument TextInput {
      onEnterKey: method
      value: 'test'
    }

    input = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'

    e = 
      key: 'Enter'
      type: 'keyup'
      keyCode: 13

    TestUtils.Simulate.keyUp input, e

    setTimeout ->
      expect(method.calledOnce).to.equal(true)
      cb()
    , 10

  it 'Should fire all other passed handlers: focus, blur, key press, key down', (cb) ->

    blur = sinon.spy()
    focus = sinon.spy()
    keyPress = sinon.spy()
    keyDown = sinon.spy()

    input = TestUtils.renderIntoDocument TextInput {
      onFocus: focus
      onBlur: blur
      onKeyDown: keyDown
      onKeyPress: keyPress
      value: 'test'
    }

    input = TestUtils.findRenderedDOMComponentWithClass input, 'text-input'

    e = 
      key: 'Enter'
      type: 'keyup'
      keyCode: 13

    TestUtils.Simulate.focus input
    TestUtils.Simulate.blur input
    TestUtils.Simulate.keyDown input
    TestUtils.Simulate.keyPress input

    setTimeout ->
      expect(focus.calledOnce).to.equal(true)
      expect(blur.calledOnce).to.equal(true)
      expect(keyPress.calledOnce).to.equal(true)
      expect(keyDown.calledOnce).to.equal(true)
      cb()
    , 10