Reputation: 427
I'm having some problems testing the following class.
interface Connector {
connect: () => Promise<void>;
}
class Unit {
private connector: Connector;
constructor(connector: Connector) {
this.connector = connector;
}
public attemptConnect(iteration: number, max: number): void {
console.log("attempt" + iteration);
this.connector.connect()
.then(() => {
console.log("connected");
})
.catch((error) => {
if (iteration < max) {
this.attemptConnect(iteration + 1, max);
}
});
}
}
I would like to test that the Connector.connect() function is called the right amount of times. I'm trying to achieve that with jest as follows:
describe("Unit", () => {
it("fails to record more than one recursion", async () => {
const connector: Connector = {
connect: jest.fn().mockRejectedValue(new Error("foo")),
};
const unit: Unit = new Unit(connector);
await unit.attemptConnect(1, 4);
expect((connector.connect as jest.Mock).mock.calls.length).toBe(4);
});
});
Unfortunately the expect() call fails, saying
Error: expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 1
If I use a debugger and watch the value of
(connector.connect as jest.Mock).mock.calls.length
I can see the calls being correctly recorded. Only when the test finishes the number is wrong.
Thank you for any help!
Upvotes: 2
Views: 1270
Reputation: 45830
Solution 1
Return the promise in attemptConnect()
:
public attemptConnect(iteration: number, max: number): Promise<void> {
console.log("attempt" + iteration);
return this.connector.connect()
.then(() => {
console.log("connected");
})
.catch((error) => {
if (iteration < max) {
return this.attemptConnect(iteration + 1, max);
}
});
}
Solution 2
await
for the required number of event loop cycles in the test:
describe("Unit", () => {
it("fails to record more than one recursion", async () => {
const connector: Connector = {
connect: jest.fn().mockRejectedValue(new Error("foo")),
};
const unit: Unit = new Unit(connector);
unit.attemptConnect(1, 4);
// await enough event loop cycles for all the callbacks queued
// by then() and catch() to run, in this case 5:
await Promise.resolve().then().then().then().then();
expect((connector.connect as jest.Mock).mock.calls.length).toBe(4);
});
});
Details
The test awaits attemptConnect()
but since it is not returning anything there is nothing to await
and the synchronous test continues executing. The expect()
runs and fails before the callbacks queued by then()
and catch()
have a chance to run.
Upvotes: 2