text: const babel = require('babel-core/register')
  babel({plugins: ['babel-plugin-rewire']})
  
  import packageJson from '../package.json'
  import conformToMask from '../src/conformToMask'
  import {placeholderChar} from '../src/constants'
  
  const createTextMaskInputElement = (isVerify()) ?
    require(`../${packageJson.main}`).createTextMaskInputElement :
    require('../src/createTextMaskInputElement.js').default
  
  describe('createTextMaskInputElement', () => {
    let inputElement
  
    beforeEach(() => {
      inputElement = document.createElement('input')
    })
  
    it('takes an inputElement and other Text Mask parameters and returns an object which ' +
       'allows updating and controlling the masking of the input element', () => {
      const maskedInputElementControl = createTextMaskInputElement({
        inputElement,
        mask: ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
      })
  
      expect(maskedInputElementControl.update).to.be.a('function')
    })
  
    it('works with mask functions', () => {
      const mask = () => [/\d/, /\d/, /\d/, /\d/]
  
      expect(() => createTextMaskInputElement({inputElement, mask})).to.not.throw()
    })
  
    it('displays mask when showMask is true', () => {
      const textMaskControl = createTextMaskInputElement({
        showMask: true,
        inputElement,
        mask: ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
      })
      textMaskControl.update()
      expect(inputElement.value).to.equal('(___) ___-____')
    })
  
    it('does not display mask when showMask is false', () => {
      const textMaskControl = createTextMaskInputElement({
        showMask: false,
        inputElement,
        mask: ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
      })
      textMaskControl.update()
      expect(inputElement.value).to.equal('')
    })
  
    describe('`update` method', () => {
      it('conforms whatever value is in the input element to a mask', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        inputElement.value = '2'
        textMaskControl.update()
        expect(inputElement.value).to.equal('(2__) ___-____')
      })
  
      it('works after multiple calls', () => {
        const mask = ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        inputElement.value = '2'
        textMaskControl.update()
        expect(inputElement.value).to.equal('+1 (2__) ___-____')
  
        inputElement.value = '+1 (23__) ___-____'
        inputElement.selectionStart = 6
        textMaskControl.update()
        expect(inputElement.value).to.equal('+1 (23_) ___-____')
  
        inputElement.value = '+1 (2_) ___-____'
        inputElement.selectionStart = 5
        textMaskControl.update()
        expect(inputElement.value).to.equal('+1 (2__) ___-____')
  
        inputElement.value = '+1 (__) ___-____'
        inputElement.selectionStart = 4
        textMaskControl.update()
        expect(inputElement.value).to.equal('')
      })
  
      it('accepts a string to conform and overrides whatever value is in the input element', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        inputElement.value = '2'
        textMaskControl.update('123')
        expect(inputElement.value).to.equal('(123) ___-____')
      })
  
      it('accepts an empty string and overrides whatever value is in the input element', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        textMaskControl.update(123)
        expect(inputElement.value).to.equal('(123) ___-____')
  
        textMaskControl.update('')
        expect(inputElement.value).to.equal('')
      })
  
      it('accepts an empty string after reinitializing text mask', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        let textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        textMaskControl.update(123)
        expect(inputElement.value).to.equal('(123) ___-____')
  
        //reset text mask
        textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        // now clear the value
        textMaskControl.update('')
        expect(inputElement.value).to.equal('')
      })
  
      if (!isVerify()) {
        it('does not conform given parameter if it is the same as the previousConformedValue', () => {
          const conformToMaskSpy = sinon.spy(conformToMask)
          const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
          const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
          createTextMaskInputElement.__Rewire__('defaultConformToMask', conformToMaskSpy)
  
          inputElement.value = '2'
          textMaskControl.update()
  
          expect(inputElement.value).to.equal('(2__) ___-____')
          expect(conformToMaskSpy.callCount).to.equal(1)
  
          textMaskControl.update('(2__) ___-____')
          expect(conformToMaskSpy.callCount).to.equal(1)
  
          createTextMaskInputElement.__ResetDependency__('defaultConformToMask')
        })
      }
  
      it('works with a string', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        textMaskControl.update('2')
  
        expect(inputElement.value).to.equal('(2__) ___-____')
      })
  
      it('works with a number by coercing it into a string', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        textMaskControl.update(2)
  
        expect(inputElement.value).to.equal('(2__) ___-____')
      })
  
      it('works with `undefined` and `null` by treating them as empty strings', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        textMaskControl.update(undefined)
        expect(inputElement.value).to.equal('')
  
        textMaskControl.update(null)
        expect(inputElement.value).to.equal('')
      })
  
      it('throws if given a value that it cannot work with', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        expect(() => textMaskControl.update({})).to.throw()
        expect(() => textMaskControl.update(() => 'howdy')).to.throw()
        expect(() => textMaskControl.update([])).to.throw()
      })
  
      it('adjusts the caret position', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask, placeholderChar})
  
        inputElement.focus()
        inputElement.value = '2'
        inputElement.selectionStart = 1
  
        textMaskControl.update()
        expect(inputElement.selectionStart).to.equal(2)
      })
  
      it('does not adjust the caret position if the input element is not focused', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        inputElement.value = '2'
        inputElement.selectionStart = 1
  
        textMaskControl.update()
        expect(inputElement.selectionStart).to.equal(0)
      })
  
      it('calls the mask function before every update', () => {
        const maskSpy = sinon.spy(() => [/\d/, /\d/, /\d/, /\d/])
        const textMaskControl = createTextMaskInputElement({inputElement, mask: maskSpy})
  
        inputElement.value = '2'
        textMaskControl.update()
        expect(inputElement.value).to.equal('2___')
  
        inputElement.value = '24'
        textMaskControl.update()
        expect(inputElement.value).to.equal('24__')
  
        expect(maskSpy.callCount).to.equal(2)
      })
  
      it('can be disabled with `false` mask', () => {
        const mask = false
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        inputElement.value = 'a'
        textMaskControl.update()
        expect(inputElement.value).to.equal('a')
      })
  
      it('can be disabled by returning `false` from mask function', () => {
        const mask = () => false
        const textMaskControl = createTextMaskInputElement({inputElement, mask})
  
        inputElement.value = 'a'
        textMaskControl.update()
        expect(inputElement.value).to.equal('a')
      })
  
      it('can pass in a config object to the update method', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement()
  
        let inputElement = {value: '2'}
  
        textMaskControl.update(inputElement.value, {inputElement, mask})
        expect(inputElement.value).to.equal('(2__) ___-____')
      })
  
      it('can change the mask passed to the update method', () => {
        const textMaskControl = createTextMaskInputElement()
  
        let inputElement = {value: '2'}
  
        textMaskControl.update(inputElement.value, {
          inputElement,
          mask: ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        })
        expect(inputElement.value).to.equal('(2__) ___-____')
  
        textMaskControl.update('2', {
          inputElement,
          mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        })
        expect(inputElement.value).to.equal('+1 (2__) ___-____')
      })
  
      it('can change the guide passed to the update method', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement()
  
        let inputElement = {value: '2'}
  
        textMaskControl.update(inputElement.value, {inputElement, mask, guide: true})
        expect(inputElement.value).to.equal('(2__) ___-____')
  
        textMaskControl.update('2', {inputElement, mask, guide: false})
        expect(inputElement.value).to.equal('(2')
      })
  
      it('can change the placeholderChar passed to the update method', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement()
  
        let inputElement = {value: '2'}
  
        textMaskControl.update(inputElement.value, {inputElement, mask, placeholderChar: '_'})
        expect(inputElement.value).to.equal('(2__) ___-____')
  
        textMaskControl.update('2', {inputElement, mask, placeholderChar: '*'})
        expect(inputElement.value).to.equal('(2**) ***-****')
      })
  
      it('can change the inputElement passed to the update method', () => {
        const mask = ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement()
  
        let firstInputElement = {value: '1'}
        let secondInputElement = {value: '2'}
  
        textMaskControl.update('1', {inputElement: firstInputElement, mask})
        expect(firstInputElement.value).to.equal('(1__) ___-____')
  
        textMaskControl.update('2', {inputElement: secondInputElement, mask})
        expect(secondInputElement.value).to.equal('(2__) ___-____')
      })
  
      it('can change the config passed to createTextMaskInputElement', () => {
        const config = {
          inputElement,
          mask: ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
          guide: true,
          placeholderChar: '_'
        }
        const textMaskControl = createTextMaskInputElement(config)
  
        inputElement.value = '2'
        textMaskControl.update()
        expect(inputElement.value).to.equal('(2__) ___-____')
  
        // change the mask
        config.mask = ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
        inputElement.value = '23' // <- you have to change the value
        textMaskControl.update()
        expect(inputElement.value).to.equal('+1 (23_) ___-____')
  
        // change the placeholderChar
        config.placeholderChar = '*'
        inputElement.value = '4' // <- you have to change the value
        textMaskControl.update()
        expect(inputElement.value).to.equal('+1 (4**) ***-****')
  
        // change the guide
        config.guide = false
        inputElement.value = '45' // <- you have to change the value
        textMaskControl.update()
        expect(inputElement.value).to.equal('+1 (45')
      })
  
      it('can override the config passed to createTextMaskInputElement', () => {
        const textMaskControl = createTextMaskInputElement({
          inputElement,
          mask: ['(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
          guide: true
        })
  
        inputElement.value = '2'
        textMaskControl.update()
        expect(inputElement.value).to.equal('(2__) ___-____')
  
        // pass in a config to the update method
        textMaskControl.update('23', {
          inputElement,
          mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
          guide: false
        })
        expect(inputElement.value).to.equal('+1 (23')
  
        // use original config again
        inputElement.value = '234' // <- you have to change the value
        textMaskControl.update()
        expect(inputElement.value).to.equal('(234) ___-____')
      })
  
      it('custon conformMask passed to createTextMaskInputElement', () => {
        const conformToMaskSpy = sinon.spy((rawValue, mask, config = {}) => { return {conformedValue: '12345'} })
        const mask = [/\d/, /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask, conformToMask: conformToMaskSpy})
  
        inputElement.value = '2'
        textMaskControl.update()
  
        expect(inputElement.value).to.equal('12345')
        expect(conformToMaskSpy.callCount).to.equal(1)
      })
  
      it('custon adjustCaretPosition passed to createTextMaskInputElement', () => {
        const adjustCaretPositionSpy = sinon.spy(() => { return 3 })
        const mask = [/\d/, /\d/, /\d/, /\d/, /\d/]
        const textMaskControl = createTextMaskInputElement({inputElement, mask,
          adjustCaretPosition: adjustCaretPositionSpy})
  
        inputElement.value = '2'
        textMaskControl.update()
  
        expect(adjustCaretPositionSpy.callCount).to.equal(1)
      })
    })
  })
  