Reputation: 3182
I have a component which behaviour looks like this one:
@Component
export default class MyComponent extends Vue {
public result: number = 0;
public ready: boolean = false;
// for test purpose only. In the real code, this promise is the result of a call to a dependency service.
public promise!: Promise<void>;
private myMethod(): void {
this.promise
.then(() => {
this.result = 1;
})
.catch(() => {
this.result = 2;
})
.finally(() => {
this.ready = true;
// setTimeout(() => {
// this.finallyExecuted = true;
// }, 50);
});
}
}
The execution of a method, triggered from a click on the following button, depends from the resolution of a promise.
<button id="myButton" type="button" @click="myMethod()">My button</button>
I want to unit test this behaviour, using Jest.
// variable 'wrapper' contains the result of a shallow mount of the component, using vue-test-utils
// variable 'component' contains 'wrapper.vm', after the component has been shallow mounted
it('should set the result to 1 and be ready', async () => {
// Given
component.promise = Promise.resolve();
// When
wrapper.find('#myButton').trigger('click');
await expect(component.promise).resolves.toBeUndefined();
// Then
expect(component.result).toBe(1);
expect(component.ready).toBe(true);
});
it('should set the result to 2 and be ready', async () => {
// Given
component.promise = Promise.reject();
// When
wrapper.find('#myButton').trigger('click');
await expect(component.promise).rejects.toBeUndefined();
// Then
expect(component.result).toBe(2);
expect(component.ready).toBe(true);
});
These 2 unit tests fail because Jest does not wait for the finally
clause to be executed before performing the last assertion: the assertion on result
passes, but ready
is seen as false
in both cases.
How can I order Jest to wait for the promise to be fully handled, including the finally
clause? If possible, without the use of an additional library.
Upvotes: 0
Views: 1510
Reputation: 138246
The promise
call inside myMethod
is not awaited, so your test is checking for the results of the call before it's actually occurred.
The solution is for myMethod
to return the result of the promise
call:
public myMethod(promise: Promise<void>) {
return promise
.then(() => {
this.result = 1;
})
.catch(() => {
this.result = 2;
})
.finally(() => {
this.ready = true;
});
}
Then your tests could await the result:
await component.myMethod(promise);
Upvotes: 1