问题
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. In the initial source code, I used ES2017 async/await in the controller. That seemed to work fine as long as I added $apply of $digest manually at the end. 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
. 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
. I tried adding $digest/$apply in the tests itself but could not fix it. 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...
回答1:
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.
In our tests, I was trying to mock out services that would return promises. I found that returning
$q.when
didn't work. Instead, I had to return actual A+ standard Promises. My guess is that Angular's $q promises aren't fully complaint with the standard and wouldn't work as a substitute.Note that since we use PhantomJS for our tests, I had to add polyfills to get those Promises.
Many times in my tests I would have to wrap some of the expect statements in a
setTimeout
block. Again, my assumption is that the promises need an additional "tick" to process.
回答2:
So the reason why there is no result is because nothing after await
is executed. I had a similar issue when I was testing async/await
inside react components.
I found somewhere that a testing method for this is as follows:
- You have to use something similar to https://www.npmjs.com/package/jasmine-async-suite - this is what I used. 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.
- So you have to manually call the method, in your case
DataService.getData()
, and use the.then()
method, where you can put yourexpect
statements - because of this step, your test is waiting for resolving the promise.
Here is an example of my code (I am also using async
functions in tests):
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 :)
回答3:
You can use the library 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);
});
});
来源:https://stackoverflow.com/questions/41028434/angular-1-5-async-await-jasmine-tests