Skip to content

Instantly share code, notes, and snippets.

@joeskeen
Last active January 25, 2023 14:02
Show Gist options
  • Save joeskeen/9594ce9642bc2166b8e21cec93725763 to your computer and use it in GitHub Desktop.
Save joeskeen/9594ce9642bc2166b8e21cec93725763 to your computer and use it in GitHub Desktop.
Different ways to use Jest to test error cases in Observable streams
import { Observable, firstValueFrom, timer, isObservable, of } from "rxjs";
import { first, timeout, catchError } from "rxjs/operators";
import { TestScheduler } from "rxjs/testing";
describe("testing error cases in Jest", () => {
describe("with RxJS", () => {
/**
* A test utility function for converting an Observable into a Promise for unit tests
* Uses a TestScheduler to make things like the passage of time (timeouts, debounce, etc.)
* happen instantaneously.
*
* @param action the action to perform (usually returning an Observable)
* @returns a Promise that will resolve on the first emitted value of the Observable
*/
function schedule(action: Function): Promise<any> {
const scheduler = new TestScheduler((actual, expected) =>
expect(actual).toEqual(expected)
);
return new Promise<void>((resolve, reject) => {
scheduler.run((helpers) => {
try {
let result = action();
if (isObservable(result)) {
// if using newer versions of RxJS:
result = firstValueFrom(result);
// if using older versions of RxJS:
// result = result.pipe(first()).toPromise();
}
helpers.flush();
resolve(result);
} catch (err) {
reject(err);
}
});
});
}
describe("when timeout expires", () => {
function failsTimeout() {
return timer(1000000).pipe(timeout(10000));
}
it("should throw", () => {
const promise = schedule(() => failsTimeout());
expect(promise).rejects.toThrow();
});
});
describe("when some error handling occurs", () => {
function failsTimeout(errorHandler: (err: any) => Observable<any>) {
return timer(1000000).pipe(
timeout(10000),
catchError((err) => errorHandler(err))
);
}
let expectedResult: any;
let actualResult: any;
let handler: jest.Mock;
beforeEach(async () => {
expectedResult = {};
handler = jest.fn(() => of(expectedResult));
actualResult = await schedule(() => failsTimeout(handler));
});
it("should call the error handler", () => {
expect(handler).toHaveBeenCalled();
});
it("should get the result of the error handling", () => {
expect(actualResult).toEqual(expectedResult);
});
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment