简体   繁体   English

Angular 1.5 && Async / Await && jasmine测试

[英]Angular 1.5 && Async/Await && jasmine tests

I already looked everywhere but could not find a solution yet for my particular case. 我已经到处寻找,但在我的特定情况下找不到解决方案。

We are using angular 1.5 and a Karma/Jasmine setup for unit tests. 我们使用angular 1.5和Karma / Jasmine设置进行单元测试。 In the initial source code, I used ES2017 async/await in the controller. 在初始源代码中,我在控制器中使用了ES2017 async / await。 That seemed to work fine as long as I added $apply of $digest manually at the end. 只要我最后手动添加$ apply of $ digest,这似乎工作得很好。 So for example: 例如:

async function loadData() {
  try {
    vm.isLoading = true;
    vm.data = await DataService.getData();
    $scope.$apply();
  }
  catch (ex) {
    vm.isLoading = false;
  }
}

To write an automated test for this particular function, I tried to mock DataService.getData with Jasmine's spyOn . 为了编写这个特定函数的自动化测试,我尝试用Jasmine的spyOn模拟DataService.getData。 So, I did something like this: 所以,我做了这样的事情:

spyOn(DataService, 'getData').and.returnValue($q.when(fakeResult));

Adding the spy worked, but when running a test, the code seems to get struck and not resolve with fakeResult . 添加间谍工作,但在运行测试时,代码似乎被触发,而不是使用fakeResult解决。 I tried adding $digest/$apply in the tests itself but could not fix it. 我尝试在测试中添加$ digest / $ apply但无法修复它。 I also did a lot of research, but still have no clue. 我也做了很多研究,但仍然没有任何线索。

Does somebody have a clue? 有人有线索吗?

Edit: testing the same method with $q promises works fine, but I would really like to use async/await... 编辑:使用$q promises测试相同的方法工作正常,但我真的想使用async / await ...

I don't know if your setup is similar, but in our environment I had to do a couple of things to get transpiled async/await statements to resolve in jasmine tests. 我不知道你的设置是否相似,但在我们的环境中,我必须做一些事情才能在茉莉花测试中解析async / await语句来解决。

  • In our tests, I was trying to mock out services that would return promises. 在我们的测试中,我试图模拟可以返回承诺的服务。 I found that returning $q.when didn't work. 我发现返回$q.when不起作用。 Instead, I had to return actual A+ standard Promises. 相反,我必须返回实际的A +标准承诺。 My guess is that Angular's $q promises aren't fully complaint with the standard and wouldn't work as a substitute. 我的猜测是,Angular的$ q承诺并没有完全投诉该标准,也无法作为替代品。

  • Note that since we use PhantomJS for our tests, I had to add polyfills to get those Promises. 请注意,由于我们使用PhantomJS进行测试,因此我必须添加polyfill来获取这些Promise。

  • Many times in my tests I would have to wrap some of the expect statements in a setTimeout block. 在我的测试中,我不得不在setTimeout块中包含一些expect语句。 Again, my assumption is that the promises need an additional "tick" to process. 同样,我的假设是承诺需要额外的“滴答”来处理。

So the reason why there is no result is because nothing after await is executed. 所以没有结果的原因是因为await执行后没有任何结果。 I had a similar issue when I was testing async/await inside react components. 当我在反应组件中测试async/await时,我遇到了类似的问题。 I found somewhere that a testing method for this is as follows: 我发现某个地方的测试方法如下:

  1. You have to use something similar to https://www.npmjs.com/package/jasmine-async-suite - this is what I used. 你必须使用类似于https://www.npmjs.com/package/jasmine-async-suite的东西 - 这就是我使用的东西。 It is for asynchronous tests where you are expecting a promise. 它适用于您期望承诺的异步测试。
    • There could be also an other problem, that after the promise is resolved, the test stops, because there is nothing to wait for :). 可能还有另一个问题,在承诺解决后,测试停止,因为没有什么可以等待:)。 It could be very tricky. 这可能非常棘手。
  2. So you have to manually call the method, in your case DataService.getData() , and use the .then() method, where you can put your expect statements - because of this step, your test is waiting for resolving the promise. 因此,您必须手动调用方法,在您的情况下使用DataService.getData() ,并使用.then()方法,您可以在其中放置您的expect语句 - 由于此步骤,您的测试正在等待解析promise。

Here is an example of my code (I am also using async functions in tests): 这是我的代码示例(我也在测试中使用async函数):

it.async('should call `mySpecialMethod`', async () => {
    const arrayToResolve = [ { data: 'data' } ];
    const SomeService = context.SomeService;

    spyOn(props, 'mySpecialMethod');
    spyOn(SomeService, 'myMethodReturningPromise');
      .and.returnValue(Promise.resolve(arrayToResolve));

    //the method `myMethodReturningPromise` is called in componentDidMount
    const wrapper = mount(<MyReactComponent {...props} />, context);
    expect(SomeService.myMethodReturningPromise).toHaveBeenCalled();

    //now I am calling the method again
    await SomeService.myMethodReturningPromise();

    //`mySpecialMethod` is calling after the `await` in my code
    expect(props.mySpecialMethod).toHaveBeenCalled();
    //after that I am changing the state
    expect(wrapper.state().arrayToResolve).toEqual(arrayToResolve);
});

I hope this helps you :) 我希望这可以帮助你 :)

You can use the library async-await-jasmine : 您可以使用库async-await-jasmine

import * as angular from 'angular';
import 'angular-mocks';
import {yourModule} from "./your-module-path";
import {LoadDataService} from './load-data';
import {$it} from "async-await-jasmine";
import {IRootScopeService} from "angular";


describe('Calculator', () => {
  let $httpBackend: angular.IHttpBackendService;

  beforeEach(() => {
    angular.mock.module(calculatorModule.name);
    angular.mock.inject((_$httpBackend_) => {
      $httpBackend = _$httpBackend_;
    });
  });

  $it('should loadData', async () => {
    $httpBackend.when('GET', '/loadData').respond('{"value": 5}');
    let sum = loadData(1, 4);
    $httpBackend.flush();

    expect(await sum).toBe(10);
  });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM