javascript 在 Jasmine 2.0 中测试 AngularJS 承诺

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23131838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 00:23:25  来源:igfitidea点击:

Testing AngularJS promises in Jasmine 2.0

javascriptangularjsjasmine

提问by Tyler Eich

I've been trying to wrap my head around Jasmine 2.0 and AngularJS promises. I know that:

我一直在努力思考 Jasmine 2.0 和 AngularJS 的承诺。我知道:

How can I test AngularJS promises using the new async syntax in Jasmine 2.0?

如何使用 Jasmine 2.0 中的新异步语法测试 AngularJS 承诺?

回答by Tyler Eich

After your call to promise.resolve():

在您致电后promise.resolve()

  • Call $timeout.flush(). This will force a digest cycle and propagate the promise resolution
  • Call done(). This tells Jasmine the async tests have completed
  • 打电话$timeout.flush()。这将强制消化循环并传播承诺解决方案
  • 打电话done()。这告诉 Jasmine 异步测试已经完成

Here's an example (Demo on Plunker):

这是一个示例(Plunker 上的演示):

describe('AngularJS promises and Jasmine 2.0', function() {
    var $q, $timeout;

    beforeEach(inject(function(_$q_, _$timeout_) {
        // Set `$q` and `$timeout` before tests run
        $q = _$q_;
        $timeout = _$timeout_;
    }));

    // Putting `done` as argument allows async testing
    it('Demonstrates asynchronous testing', function(done) {
        var deferred = $q.defer();

        $timeout(function() {
            deferred.resolve('I told you I would come!');
        }, 1000); // This won't actually wait for 1 second.
                  // `$timeout.flush()` will force it to execute.

        deferred.promise.then(function(value) {
            // Tests set within `then` function of promise
            expect(value).toBe('I told you I would come!');
        })
        // IMPORTANT: `done` must be called after promise is resolved
        .finally(done);

        $timeout.flush(); // Force digest cycle to resolve promises
    });
});

回答by mariowise

For me the $timeout.flush()didn't work very well, but I've multiple async calls in my spec. I found the $rootScope.$apply(), as a method to force the digeston each async call.

对我来说,$timeout.flush()效果不是很好,但我的规范中有多个异步调用。我发现$rootScope.$apply(), 作为强制digest每个异步调用的方法。

describe('AngularJS promises and Jasmine 2.0', function () {
  beforeEach(inject(function (_$q_, _$timeout_, _$rootScope_) {
    $q = _$q_
    $timeout = _$timeout_
    $rootScope = _$rootScope_
  }))

  it('demonstrates asynchronous testing', function (done) {
    var defer = $q.defer()

    Async.call()
    .then(function (response) {
      // Do something

      var d = $q.defer()
      Async.call()
      .then(function (response) {
        d.resolve(response)
        $rootScope.$apply() // Call the first digest 
      })
      return d.promise
    })
    .then(function (response) {
      // Do something after the first digest

      Async.call()
      .then(function (response) {
        defer.resolve(response) // The original defer
        $rootScope.$apply() // Call the second digest
      })
    })

    defer.promise.then(function(value) {
      // Do something after the second digest
      expect(value).toBe('I told you I would come!')
    })
    .finally(done)

    if($timeout.verifyNoPendingTasks())
      $timeout.flush() 
  })
})

It is like a chained async calls thing. Hope it helps the conversation. Regards

这就像一个链式异步调用的东西。希望对对话有所帮助。问候

回答by Rustam

This answer won't add anything new to those of above, it is only intended to articulate the answer in more detailed way, as it worked for me. When I occurred the issue described in a question above, I spent much time tryng to find a way to make sure all promises had their time to finish and all assertions were asserted.

这个答案不会为上述答案添加任何新内容,它只是为了以更详细的方式阐明答案,因为它对我有用。当我遇到上面问题中描述的问题时,我花了很多时间试图找到一种方法来确保所有承诺都有时间完成并且所有断言都被断言。

In my case I had a chain of promises, and after each of them I need to ensure the results do match my expectation. I did not create any promise using deferred, I rather invoked the existing ones.

就我而言,我有一系列承诺,在每一项之后,我都需要确保结果符合我的预期。我没有使用 来创建任何承诺deferred,而是调用了现有的承诺。

So, the thing is that $timeout.flush()was completely enough for me. My working test looks like this:

所以,问题是这$timeout.flush()对我来说已经足够了。我的工作测试如下所示:

describe("Plain command without side-effects", function() {
    it("All usecases", inject(function($timeout) {
        console.log("All together");
        expect(state.number).toEqual(1);
        cmdHistory
            .execute(increaseState, decreaseState)
            .then(function() {
                console.log("Execute works");
                expect(state.number).toEqual(2);
                return cmdHistory.redo(); // can't redo, nothing's undone
            })
            .then(function() {
                console.log("Redo would not work");
                expect(state.number).toEqual(2);
                return cmdHistory.undo();
            })
            .then(function() {
                console.log("Undo undoes");
                expect(state.number).toEqual(1);
                return cmdHistory.undo();
            })
            .then(function() {
                console.log("Next undo does nothing");
                expect(state.number).toEqual(1);
                return cmdHistory.redo(); // but still able to redo

            })
            .then(function() {
                console.log("And redo redoes neatly");
                expect(state.number).toEqual(2);
            });

        $timeout.flush();
    }));

This test is dedicated to make sure that commandHistory object works fine, it has to actions: executeand unExecute, and three methods: execute, undo, redo, all of which return promises.

此测试致力于确保 commandHistory 对象正常工作,它必须执行 actions:executeunExecute,以及三个方法:executeundoredo,所有这些都返回承诺。

Without $timeout.flush(), all I had in log output was All together, and no further log messages. Adding $timeout.flush()has fixed everything up, and now I have all messages shown and all assertions executed

没有$timeout.flush(),我在日志输出中只有All together,并且没有进一步的日志消息。添加$timeout.flush()已修复所有问题,现在我显示了所有消息并执行了所有断言

UPDATEThere's another option: you can write your test suite without chaining promises with then, but simply flushing after each promise has been called, so that to make sure it completes:

更新还有另一种选择:您可以编写测试套件,而无需将 Promise 链接到then,而只需在调用每个 Promise 后刷新,以确保它完成:

    it("All usecases 2", inject(function($timeout) {
        console.log("All usecases 2");
        expect(state.number).toEqual(1);

        console.log("Execute works");
        cmdHistory.execute(increaseState, decreaseState);
        $timeout.flush();
        expect(state.number).toEqual(2);

        console.log("Redo would not work");
        cmdHistory.redo(); // can't redo, nothing's undone
        $timeout.verifyNoPendingTasks();
        expect(state.number).toEqual(2);

        console.log("Undo undoes");
        cmdHistory.undo();
        $timeout.flush();
        expect(state.number).toEqual(1);

        console.log("Next undo does nothing");
        cmdHistory.undo();
        $timeout.verifyNoPendingTasks();
        expect(state.number).toEqual(1);

        console.log("And redo redoes neatly");
        cmdHistory.redo(); // but still able to redo
        $timeout.flush();
        expect(state.number).toEqual(2);
    }));

Please pay attention to the fact in some cases, when my methods like undoand redodo not return promise, I call $timeout.verifyNoPendingTasks()instead of flush. Which is hard to say if it's good or bad.

请注意,在某些情况下,当我的方法喜欢undo并且redo不返回 promise 时,我会调用$timeout.verifyNoPendingTasks()而不是flush. 这很难说是好是坏。

Yet in this case test looks more reasonable and much simpler.

然而在这种情况下,测试看起来更合理也更简单。