Reputation: 61724
In my TypeScript app I have a method that return an rxjs Observable which, in a certain case, can return throwError:
import { throwError } from 'rxjs';
// ...
getSomeData(inputValue): Observable<string> {
if (!inputValue) {
return throwError('Missing inputValue!');
}
// ...
}
how can I write a test to cover this specific case?
Upvotes: 15
Views: 9876
Reputation: 61724
I bumped into my own old question and solved it this way:
it('should throw error if ...', (done) => {
const { service } = setup();
service.myObs$().subscribe({
error: (err) => {
expect(err).toEqual(new Error(`Some error`))
done();
},
});
// some code making myObs$ throwing a new error
});
Upvotes: 2
Reputation: 2210
You can test it using RxJS Marble diagram tests. Here's how:
const getSomeData = (inputValue: string): Observable<string> => {
if (!inputValue) {
return throwError('Missing inputValue!');
}
// e.g.
return of(inputValue);
};
describe('Error test', () => {
let scheduler: TestScheduler;
beforeEach(() => {
scheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});
it('should throw an error if an invalid value has been sent', () => {
scheduler.run(({ expectObservable }) => {
const expectedMarbles = '#'; // # indicates an error terminal event
const result$ = getSomeData(''); // an empty string is falsy
expectObservable(result$).toBe(expectedMarbles, null, 'Missing inputValue!');
});
});
it('should emit an inputValue and immediately complete', () => {
scheduler.run(({ expectObservable }) => {
const expectedMarbles = '(a|)';
const result$ = getSomeData('Some valid string');
expectObservable(result$).toBe(expectedMarbles, { a: 'Some valid string' });
});
});
});
For more info on how to write these tests, please take a look at this link.
Upvotes: 11
Reputation: 2068
Another way is to check that the operator thows an error is to pipe it like below. I assume that you are using Chai.
import { catchError } from 'rxjs/operators';
it('must throw an error', done => {
getSomeData().pipe(catchError((e) => [e])).subscribe(e => {
expect(e).to.be.an.instanceof(Error);
done();
})
})
Source How to test an RxJS operation that throws an error
Upvotes: 2
Reputation: 111
In addition to lagoman's answer. You could simplify the way to get the testScheduler.
describe('Error test', () => {
it('should throw an error if an invalid value has been sent', () => {
getTestScheduler().run(({ expectObservable }) => { // getTestScheduler from jasmine-marbles package
const expectedMarbles = '#'; // # indicates an error terminal event
const result$ = getSomeData(''); // an empty string is falsy
expectObservable(result$).toBe(expectedMarbles, null, 'Missing inputValue!');
});
});
it('should emit an inputValue and immediately complete', () => {
getTestScheduler().run(({ expectObservable }) => {
const expectedMarbles = '(a|)';
const result$ = getSomeData('Some valid string');
expectObservable(result$).toBe(expectedMarbles, { a: 'Some valid string' });
});
});
});
Upvotes: 1
Reputation: 17752
I imagine your full case resembles something like this
// first there is something that emits an Observable
export function doSomethingThatReturnsAnObservable() {
return createSomehowFirstObservable()
.pipe(
// then you take the data emitted by the first Observable
// and try to do something else which will emit another Observable
// therefore you have to use an operator like concatMap or switchMap
// this something else is where your error condition can occur
// and it is where we use your getSomeData() function
switchMap(inputValue => getSomeData(inputValue))
);
}
}
// eventually, somewhere else, you subscribe
doSomethingThatReturnsAnObservable()
.subscribe(
data => doStuff(data),
error => handleError(error),
() => doSomethingWhenCompleted()
)
A test for the error condition could look something like this
it('test error condition'), done => {
// create the context so that the call to the code generates an error condition
.....
doSomethingThatReturnsAnObservable()
.subscribe(
null, // you are not interested in the case something is emitted
error => {
expect(error).to.equal(....);
done();
},
() => {
// this code should not be executed since an error condition is expected
done('Error, the Observable is expected to error and not complete');
}
)
})
Upvotes: 6