0

I have a service that needs to call the database through AJAX and this is the test for it:

describe 'Cep service', ->
  cep = undefined
  $timeout = undefined

  beforeEach(module('cep'))
  beforeEach(inject(($cep, $injector)->
    cep = $cep
    $timeout = $injector.get('$timeout')
  ))

  afterEach(->
    $timeout.verifyNoPendingTasks()
  )

  it 'should fail', (done) ->
    cep(
      '00000000' 
      (data) ->
        expect(->
          throw new Error('Shouldnt succeed')
        ).to.not.throwError()
        return
      (err) ->
        expect(err).to.be.ok()
        expect(err).to.be('CEP inválido')
        done()
        return
    )

    try
      $timeout.flush()
    catch e
      console.log e

    return

  it 'should work with dashes', (done) ->
    cep(
      '91010-000'
      (data) ->
        expect(data).to.be.ok()
        expect(data).to.have.property('resultado')
        expect(data).to.have.property('uf')
        expect(data).to.have.property('cidade')
        expect(data).to.have.property('bairro')
        expect(data).to.have.property('tipo_logradouro')
        expect(data).to.have.property('logradouro')
        done()
        return
      (err) ->
        expect(->
          throw new Error('Shouldnt fail')
        ).to.not.throwError()
        done()
        return
    )
    try
      $timeout.flush()
    catch e
      console.log e

    return


  it 'should work without dashes', (done) ->
    cep(
      '91010000'
      (data) ->
        expect(data).to.be.ok()
        expect(data).to.have.property('resultado')
        expect(data).to.have.property('uf')
        expect(data).to.have.property('cidade')
        expect(data).to.have.property('bairro')
        expect(data).to.have.property('tipo_logradouro')
        expect(data).to.have.property('logradouro')
        done()
        return
      (err) ->
        expect(->
          throw new Error('Shouldnt fail')
        ).to.not.throwError()
        done()
        return
    )

    try
      $timeout.flush()
    catch e
      console.log e

    return

fails with error (since mocha's done is never called):

Chrome 33.0.1750 (Windows 7) Cep service should fail FAILED             
    Error: timeout of 2000ms exceeded
        at C:/project/node_modules/mocha/mocha.js:4290:14

it doesn't matter if I call $timeout.flush or not. When I call $timeout.flush after my call (since the AJAX hasn't returned yet), it throws an error and logs to console No deferred tasks to flush.

I'm already loading angular-mocks.js in my karma.conf.js and they are the same version (angular and mock, kept up to date using bower update).

Inside the CEP service, after the ajax is called, the callback is executed inside a $timeout(-> cb(data)) and is never called for whatever reason. I'm stumped.

All issues I saw here in SO are related to e2e, jasmine and synchronous tests with $httpBackend mocks. I need to actually call the PHP script for the test. Also, I've set the "proxy" on karma.conf.js

proxies       : {
  '/planos': 'http://local.gap/planos',
  '/ajax'  : 'http://local.gap/ajax'
},

that the dev tools console show that the requests are being done but it's stopping on $timeout

angular.module('cep', ['pheryResource'])
  .factory(
    '$cep'
    ['$pheryResource', (ajax) ->
      (cep, cb, err) ->
        cep = cep?.replace /[^0-9]*/g, ''

        if not cep? or cep.length < 8
          err?('CEP inválido')
          return

        ajax('cep', '/ajax').get(
          {cep: cep}
          (data) ->
            if not data? or not data.resultado?
              err?('CEP inválido')
            else
              cb(data)

            return
          (error) ->
            err?(error)

            return
        )

        return
    ]
  )

angular.module('pheryResource', [])
  .factory(
    '$pheryResource'
    ['$timeout', ($timeout) ->
      phery_remote = (remote, url) ->
        @element = phery.element(remote, if url then {target: url} else undefined)
        angular.extend @, @element.phery()
        return

      event = (element, cb, err) ->
        element.off('phery:json phery:fail').on(
          'phery:json': (event, data) ->
            $timeout(->
              cb?(data)
              return
            )
            return

          'phery:fail': (event, error) ->
            $timeout(->
              err?(error)
              return
            )
            return
        )

      phery_remote::get = (data, cb, err) ->
        @element.phery('data', 'method', 'GET')
        event(@element, cb, err)
        @element.phery('one', data)

      phery_remote::post = (data, cb, err) ->
        @element.phery('data', 'method', 'POST')
        event(@element, cb, err)
        @element.phery('one', data)

      phery_remote::put = (data, cb, err) ->
        @element.phery('data', 'method', 'PUT')
        event(@element, cb, err)
        @element.phery('one', data)

      phery_remote::delete = (data, cb, err) ->
        @element.phery('data', 'method', 'DELETE')
        event(@element, cb, err)
        @element.phery('one', data)

      (remote, url) ->
        new phery_remote(remote, url)
    ]
  )
pocesar
  • 6,860
  • 6
  • 56
  • 88
  • Could you please add where the `$timeout` is called? – hassassin Mar 10 '14 at 22:45
  • @hassassin updated the post. notice that the code WORKS on the page, but not in the tests – pocesar Mar 11 '14 at 00:36
  • Yeah, so you point out the problem, ajax hasn't responded when you call the flush, so you need to either mock out that call so that it responds right away or try to use waitsFor and run. – hassassin Mar 11 '14 at 00:44
  • I'm using Mocha and not jasmine. Mocha uses the `done` callback to indicate that it's an assynchronous test and it's done... – pocesar Mar 11 '14 at 01:01

0 Answers0