0%

jest-test-async-functions

Test promise

How many ways to test an async function which has a promise with jest in an angular app? suppose you have the following function

1
2
3
4
5
6
7
getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10);
}, 0);
});
}

To test this function, you can use the following ways:

1. Using async/await

1
2
3
4
it('should return 10', async () => {
const result = await getData();
expect(result).toBe(10);
});

2. By returning promise

In jest, when you return a promise in your test, jest will wait for the promise to resolve. see here for details.

1
2
3
4
5
it('should return 10', () => {
return getData().then(result => {
expect(result).toBe(10);
});
});

3. By a done callback

This one works fine when promise is resolved. but if the promise is rejected, the test will wait for a maximum of 5 seconds timeout, and then fail. while others will fail immediately.

1
2
3
4
5
6
it('should return 10', (done) => {
getData().then(result => {
expect(result).toBe(10);
done();
});
});

4. By waitForAsync in angular

In angular, you can use waitForAsync to test async functions. Note that you don’t need await in this case.

1
2
3
4
5
it('should return 10', waitForAsync(() => {
getData().then(result => {
expect(result).toBe(10);
});
}));

5. Using fakeAsync in angular

In angular, you can use fakeAsync to test async functions. Note that you don’t need flush or tick in this case.

1
2
3
4
5
6
it('should return 10', fakeAsync(() => {
getData().then(res => {
expect(result).toBe(10);
});
flush();
}));

6. This one not work!

Since we have a setTimeout in the getData function, the following test will fail.

1
2
3
4
5
it('should return 10', () => {
getData().then(result => {
expect(result).toBe(10);
});
});

if getData() doesn’t have a setTimeout, the above test will work.

1
2
3
4
5
getData() {
return new Promise((resolve, reject) => {
resolve(10);
});
}

Test observable

How many ways to test an async function which returns an observable with jest in an angular app? suppose you have the following function

1
2
3
4
5
6
7
getData() {
return new Observable((observer) => {
setTimeout(() => {
observer.next(10);
}, 1000);
});
}

1. Test with done callback

1
2
3
4
5
6
it('should complete with value 10', (done) => {
component.getData().subscribe((result) => {
expect(result).toBe(10);
done();
});
});

2. Test by convert observable to promise

1
2
3
it('should complete with value 10', async () => {
await expect(firstValueFrom(component.getData())).resolves.toBe(10);
});

3. Convert to promise manually

This one is not recommended, Please use firstValueFrom or lastValueFrom from rxjs to convert observable to promise.

1
2
3
4
5
6
7
8
it('should complete with value 10', () => {
return new Promise((resolve, reject) => {
component.getData().subscribe((result) => {
expect(result).toBe(10);
resolve(true);
});
});
});