Reputation: 1718
I am trying to test a simple function in angular using karma and jasmine.
class
export class Acl {
async caller() {
console.log("first statement");
const calledMe = await this.callMe().toPromise();
return calledMe;
}
callMe() {
return new Observable((observer) => observer.next({ something: "key" }));
}
}
test file
import { Acl } from "./main";
import { fakeAsync, tick } from "@angular/core/testing";
import { Observable } from "rxjs";
describe("Hello world", () => {
it("test the async", fakeAsync(() => {
const t = new Acl();
spyOn(t, "callMe").and.returnValue(
new Observable((observer) => observer.next({ something: "key" }))
);
const cl = t.caller();
console.log("a print ", cl);
tick();
}));
});
the output for the print statement in the test case is
How to test such functions.
Upvotes: 1
Views: 811
Reputation: 27294
The test shown in the other answer is correctly written and should work -- the expect
statement should fire and pass.
If it's not passing, it could be due to this Zone.js issue. If your tests are running as native async/await
(target ES2017 or higher), Zone cannot hook your await
statement, so tick()
will not cause it to proceed. You can test this by putting logging statements immediately before and after the await
line and the tick()
line:
async caller() {
console.log("before await");
const calledMe = await this.callMe().toPromise();
console.log("after await");
return calledMe;
}
// ...
it("test the async", fakeAsync(() => {
const t = new Acl();
const spy = spyOn(t, "callMe").and.returnValue(
new Observable((observer) => observer.next({ something: "key" }))
);
t.caller();
console.log("before tick");
tick();
console.log("after tick");
expect(spy).toHaveBeenCalled()
}));
If you run this with target: "es2015"
in your tsconfig, you should see "before await", "before tick", "after await", "after tick", then your test should pass. If you run it with target: "es2017"
or later, like 2018/2020/esnext, you should see "before await", "before tick", "after tick", then your test should fail, then "after await" will probably log after the test body function has totally finished executing.
As an aside, this drove me crazy for about 2 days. Users of the ng
CLI get a warning when they try to go past es2015
, but not if you compile your project using the AngularCompilerPlugin
webpack plugin directly, though that should be fixed soon.
Upvotes: 0
Reputation: 14189
Your test should be made up of at least one expectation, else you aren't testing for a specific result but just that the code runs without errors.
In your case I think you could store the spy as a constant and then expect that it has been called after tick
, like that:
describe("Hello world", () => {
it("test the async", fakeAsync(() => {
const t = new Acl();
const spy = spyOn(t, "callMe").and.returnValue(
new Observable((observer) => observer.next({ something: "key" }))
);
t.caller();
tick();
expect(spy).toHaveBeenCalled()
}));
});
Upvotes: 1