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')
  ValidationContext = require '../../src/context_wrapper'

  afterEach -> dispatcher.dispatch 'clear-all'

  ###
  
  Note About ValidationContext

  The input validation uses context to gain access to the app level validation methods
  Because context is only present when the component is a child of the application, it is not present in tests
  The ValidationContext component, simply wraps the input component, and adds the validation context methods so they are present in the tests
  
  ###

  #--------------------------------------------------------------------- Default Props
  it 'Should have default props', ->
    
    
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps: 
        value: ''
    })

    input = wrapper.getInput()
    
    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', ->

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        loading: yes
        value: ''
    })

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

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

  # #--------------------------------------------------------------------- Validation
  it 'Should not show an error when the validation is off', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        loading: no
        validation: off
        value: ''
    })
    
    el = TestUtils.scryRenderedDOMComponentsWithClass wrapper, 'field-wrap'

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

  it 'Should NOT show an error before a change has ocurred', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        key: 'test'
        loading: no
        validation: null
        value: ''
    })

    el = TestUtils.scryRenderedDOMComponentsWithClass wrapper, 'field-wrap'

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

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

    input = wrapper.getInput()

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

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

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


  it 'Should show an error before a change has ocurred and forceShowAllErrors is on', () ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        key: 'test'
        loading: no
        validation: []
        value: ''
    })

    dispatcher.dispatch 'force-show-all', {autoHideAfter: no, isInPopover: no}
    
    el = wrapper.getInputEl()
    
    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', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        key: 'test'
        loading: no
        validation:
          messages: ['fail']
        value: ''
    })

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

    el = wrapper.getInputEl()

    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', ->   
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        key: 'test'
        loading: no
        validation: (value) ->
          [
            {
              messages: ['fail']
            }
          ]
        value: ''
    })

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

    el = wrapper.getInputEl()

    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)
    
    wrapper = ReactDOM.render ValidationContext({
      factory: TextInput
      childProps:
        key: 'test'
        loading: no
        validation: null
        value: 'one'
    }), node
    
    input = wrapper.getInput()

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

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

  it 'Should not show an error when the validation fails, but loading is on', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: ''
        loading: yes
        validation: -> []
    })

    input = wrapper.getInput()

    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()

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: ''
        delayedActionOnChange:
          action: actionFn
          interval: 10
    })

    input = wrapper.getInput()

    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', ->

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
    })

    input = wrapper.getInput()

    subInput = TestUtils.findRenderedDOMComponentWithClass wrapper, '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', ->

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        disabled: yes
    })

    input = wrapper.getInput()

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

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

  it 'Should set the tab index', ->

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        tabIndex: 34
    })

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

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

  it 'Should set the DOM id', ->

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        id: 'theOneAndOnly'
    })


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

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

  it 'Should set the DOM spellcheck attr', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        spellCheck: yes
    })

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

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


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

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        autoComplete: "on"
    })

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

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

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

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        maxLength: 4
    })

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

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


  it 'Should set the DOM placeholder attr', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        placeholder: 'type something here'
    })

    subInput = TestUtils.findRenderedDOMComponentWithClass wrapper, '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', ->
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        wrapperClass: 'blanket'
    })

    matches = TestUtils.scryRenderedDOMComponentsWithClass wrapper, 'blanket'

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

  it 'Should apply arbitrary inline styles to the wrapper div passed in a style prop', ->
    
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        style: 
          width: 239
    })

    input = wrapper.getInput()

    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', ->

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        wrapperLabel: 'First Name'
    })

    matches = TestUtils.scryRenderedDOMComponentsWithTag wrapper, 'label'

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

  #--------------------------------------------------------------------- Clear button
  it 'Should show a clear button when text is entered and showClear is on', ->
    
    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        showClear: on
    })

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

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

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

    method = sinon.spy()

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        value: 'new value'
        showClear: on
        onChange: method
    })

    clear = TestUtils.findRenderedDOMComponentWithClass wrapper, '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()

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        onKeyUp: method
        value: 'test'
    })

    input = TestUtils.findRenderedDOMComponentWithClass wrapper, '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()

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        onChange: method
        value: 'test'
    })

    input = TestUtils.findRenderedDOMComponentWithClass wrapper, '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()

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        onEnterKey: method
        value: 'test'
    })

    input = TestUtils.findRenderedDOMComponentWithClass wrapper, '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()

    wrapper = TestUtils.renderIntoDocument(ValidationContext {
      factory: TextInput
      childProps:
        onFocus: focus
        onBlur: blur
        onKeyDown: keyDown
        onKeyPress: keyPress
        value: 'test'
    })

    input = TestUtils.findRenderedDOMComponentWithClass wrapper, '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