jest-marbles
jest-marbles copied to clipboard
Bug: does not compare error object
it('should not pass, but it is', () => {
const foo$ = cold('#', {}, { foo: 1 });
const bar$ = cold('#', {}, { bar: 1 });
expect(foo$).toBeObservable(bar$);
});
The test above should fail. Tested with version 2.5.1.
The erroneous behavior seems to lie in the toBeNotifications
matcher.
Here both actual
and expected
are converted to their marble strings which are then matched for equality. The error value is discarded at this point.
The error occurs if the observable only yields an error. It does not occur if there are more values. So a quick fix in that setup would be to prepend an arbitrary value to the observable.
The following test would fail as intended:
it('should test error with jest-marbles', () => {
const testObs$ = throwError('someError').pipe(startWith('asdf'));
expect(testObs$).toBeObservable(cold('(a#)', {a: 'asdf'}, 'someOtherError'));
});
One thing to note here is that the prepended value must not be a single character string since it would then be interpreted as a marble. So this
it('should test error with jest-marbles', () => {
const testObs$ = throwError('someError').pipe(startWith('a'));
expect(testObs$).toBeObservable(cold('(a#)', {a: 'a'}, 'someOtherError'));
});
would wrongfully pass.
The error originates from this piece of code:
function canMarblize(...messages: TestMessage[][]) {
return messages.every(message => message.filter(({ notification: { kind } }) => kind === 'N').every(isCharacter)); // <-- this is where the error with single character values originates from
}
function isCharacter({ notification: { value } }: TestMessage): boolean {
return (
(typeof value === 'string' && value.length === 1) || (value !== undefined && JSON.stringify(value).length === 1)
);
}
export const customTestMatchers = {
toBeNotifications(actual: TestMessage[], expected: TestMessage[]) {
let actualMarble: string | TestMessage[] = actual;
let expectedMarble: string | TestMessage[] = expected;
if (canMarblize(actual, expected)) {
actualMarble = Marblizer.marblize(actual);
expectedMarble = Marblizer.marblize(expected);
}
const pass = equals(actualMarble, expectedMarble);
...
May I ask why the values are marbelized here anyway? As far as I can tell it should always be possible to just compare them for equality without comparing their marble-strings?