2

我知道这已经被问过很多次了,我已经查看了其他问题并关注了它们,但我似乎无法解决这个问题。

基本上,我在 Service 中有一个函数可以将数据放入 pouchDB。该函数addTask将返回一个promise,当数据库插入成功时,该promise 将解析为结果值。

这在浏览器环境中的手动测试期间工作正常,但在 Jasmine 测试期间由于超时而失败。

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

似乎在then规范中作为参数传递的回调永远不会运行。

JSBin

app = angular.module 'testApp', ['ngMock']

app.service 'Pouch', ($q) ->
  db = new PouchDB 'tasks'

  return {
    addTask : (task) ->
        deferred = $q.defer()
        db.put task, (task.title + task.due), (err, res) ->
          console.log res # Both prints fine
          console.log err
          deferred.resolve res
        return deferred.promise
  }

describe 'Service: Pouch', ->
  Pouch = {}
  $rootScope = {}

  beforeEach () ->
    module 'testApp'
    PouchDB.destroy 'tasks'
    inject (_Pouch_, _$rootScope_) ->
      Pouch = _Pouch_
      $rootScope = _$rootScope_

  value = undefined

  testTask =
    type: 'TASK'
    title: 'Feed the kitten'
    due: 201120141900
    group: ['TODAY', 'TOMORROW']

  it 'should add task upon request', (done) ->
    promise = Pouch.addTask testTask
    promise.then (result) ->
      # Never reached here
      expect(result.ok).toBe(true)
      done()
    $rootScope.$apply() # I don't think this is neccessary.

我该怎么办?我也试过用$timeout,但没有用。

4

3 回答 3

2

这看起来是我能想到的两件事之一:

  1. 要么:您似乎不是孤立地测试您的 Pouch 服务。那个异步调用是怎么回事?它在做什么?有什么可以模拟和注入的东西,以便您可以使用$q.when()$timeout.$flush()测试吗?
  2. ...或...您的意思是这是一个集成测试,在这种情况下,您可以jasmine. DEFAULT_TIMEOUT_INTERVAL使用beforeEachafterEach

编辑:您在帖子中所写的服务和接受的答案不能单独测试。

如果你想单独测试它,你需要将 PouchDB 作为依赖注入。您不需要测试Pouch,只需您自己的代码:

# Create a service that gets PouchDB from $window
app.service 'PouchDB', ($window) ->
    return $window.PouchDB

# Now you can inject it as a dependency!
app.service 'Pouch', ($q, $rootScope, PouchDB) -> 
    # *now* new it up.
    db = new PouchDB 'tasks'

    return addTask: (task) ->
        deferred = $q.defer()

        db.put task, (task.title + task.due), (err, res) ->
          $rootScope.$apply ->  deferred.resolve res

        deferred.promise

你的测试现在被隔离了:

describe 'Service: Pouch', ->
  Pouch = undefined
  $rootScope = undefined
  PouchDBMock = undefined
  $timeout = undefined
  value = undefined

  beforeEach () ->
    module 'testApp', ($provide) -> 
      # create your mock
      PouchDBMock = jasmine.createSpyObj('PouchDB', ['put', 'get', 'etc']);

      # provide it to the container
      $provide.value 'PouchDB', PouchDBMock


    # No longer necessary, because you're isolated!
    # ---> PouchDB.destroy 'tasks' <---

    # Now when you inject your Pouch service, it will have
    # our PouchDBMock being used inside of it.
    # also inject $timeout so you can flush() later
    inject (_Pouch_, _$rootScope_, _$timeout_) ->
      Pouch = _Pouch_
      $rootScope = _$rootScope_
      $timeout = _$timeout_

    # MOVED: this should be initialized in your beforeEach or your it, not in the body
    # of define... that's bad. Every new `it` test could mutate this and it won't reset
    # in the beforeEach where you had it.
    testTask =
      type: 'TASK'
      title: 'Feed the kitten'
      due: 201120141900
      group: ['TODAY', 'TOMORROW']




  it 'should add task upon request', (done) ->
    # tell the spy on `put` to return something distinct
    PouchDBMock.put.andReturn('something special');

    # call the method
    promise = Pouch.addTask testTask

    # handle the promise
    promise.then (result) ->
      # assert put was called on your mock
      expect(PouchDBMock.put).toHaveBeenCalledWith(testTask)
      # assert the result was what you expected (the return from the spy)
      expect(result).toBe('something special')
      # and you're done... even though this wasn't asynchronous
      done()

    # flush all unresolved promises
    $timeout.flush()
于 2014-08-01T16:24:00.517 回答
1

问题在于,由于 pouchdb 回调发生在 Angular 的摘要周期之外,因此您必须$rootScope.$apply()在 pouchdb 回调函数内部调用。

  app.service 'Pouch', ($q, $rootScope) -> db = new PouchDB 'tasks'
    return {
      addTask : (task) ->
      deferred = $q.defer()
      db.put task, (task.title + task.due), (err, res) ->
      deferred.resolve res
      $rootScope.$apply()
      return deferred.promise
    }
于 2014-08-01T17:40:11.940 回答
0

很可能问题出在 PhantomJS 上,它需要一个 shimFunction.prototype.bind才能与 PouchDB 一起正常工作。您可以从https://github.com/es-shims/es5-shim获得这样的 shim 。

于 2014-08-01T02:32:44.027 回答