jest-marbles
Version:
Marble testing helpers library for RxJs and Jest
124 lines (102 loc) • 3.97 kB
text/typescript
import { ColdObservable } from './src/rxjs/cold-observable';
import { HotObservable } from './src/rxjs/hot-observable';
import { Scheduler } from './src/rxjs/scheduler';
import { stripAlignmentChars } from './src/rxjs/strip-alignment-chars';
import { Observable, Subscription } from 'rxjs';
export type ObservableWithSubscriptions = ColdObservable<any> | HotObservable<any>;
export { Scheduler } from './src/rxjs/scheduler';
export { marbleTest } from './src/marble-test';
export { animate } from './src/animate';
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
interface Matchers<R extends void | Promise<void>> {
toBeObservable(observable: ObservableWithSubscriptions): R;
toHaveSubscriptions(marbles: string | string[]): R;
toHaveNoSubscriptions(): R;
toBeMarble(marble: string): R;
toSatisfyOnFlush(func: () => void): R;
}
}
}
declare module 'expect' {
interface Matchers<R extends void | Promise<void>> {
toBeObservable(observable: ObservableWithSubscriptions): R;
toHaveSubscriptions(marbles: string | string[]): R;
toHaveNoSubscriptions(): R;
toBeMarble(marble: string): R;
toSatisfyOnFlush(func: () => void): R;
}
}
export function hot<T = unknown>(marbles: string, values?: Record<string, T>, error?: any): HotObservable<T> {
return new HotObservable<T>(stripAlignmentChars(marbles), values, error);
}
export function cold<T = unknown>(marbles: string, values?: Record<string, T>, error?: any): ColdObservable<T> {
return new ColdObservable<T>(stripAlignmentChars(marbles), values, error);
}
export function time(marbles: string): number {
return Scheduler.get().createTime(stripAlignmentChars(marbles));
}
export function schedule(work: () => void, delay: number): Subscription {
return Scheduler.get().schedule(work, delay);
}
const dummyPass = {
message: () => '',
pass: true,
};
const dummyFail = {
message: () => '',
pass: false,
};
expect.extend({
toHaveSubscriptions(actual: ObservableWithSubscriptions, marbles: string | string[]) {
const sanitizedMarbles = Array.isArray(marbles) ? marbles.map(stripAlignmentChars) : stripAlignmentChars(marbles);
if (this.isNot) {
Scheduler.get().expectSubscriptions(actual.getSubscriptions()).toBe(sanitizedMarbles);
Scheduler.markLastNegated();
return dummyFail;
}
Scheduler.get().expectSubscriptions(actual.getSubscriptions()).toBe(sanitizedMarbles);
return dummyPass;
},
toHaveNoSubscriptions(actual: ObservableWithSubscriptions) {
if (this.isNot) {
throw new Error('toHaveNoSubscriptions cannot be negated — use toHaveSubscriptions instead');
}
Scheduler.get().expectSubscriptions(actual.getSubscriptions()).toBe([]);
return dummyPass;
},
toBeObservable(actual: Observable<unknown>, expected: ObservableWithSubscriptions) {
if (this.isNot) {
Scheduler.get().expectObservable(actual).toBe(expected.marbles, expected.values, expected.error);
Scheduler.markLastNegated();
return dummyFail;
}
Scheduler.get().expectObservable(actual).toBe(expected.marbles, expected.values, expected.error);
return dummyPass;
},
toBeMarble(actual: ObservableWithSubscriptions, marbles: string) {
if (this.isNot) {
Scheduler.get().expectObservable(actual).toBe(stripAlignmentChars(marbles));
Scheduler.markLastNegated();
return dummyFail;
}
Scheduler.get().expectObservable(actual).toBe(stripAlignmentChars(marbles));
return dummyPass;
},
toSatisfyOnFlush(actual: ObservableWithSubscriptions, func: () => void) {
if (this.isNot) {
throw new Error('toSatisfyOnFlush cannot be negated');
}
Scheduler.get().expectObservable(actual);
Scheduler.markLastReady();
Scheduler.queueOnFlush(func);
return dummyPass;
},
});
beforeEach(() => {
Scheduler.init();
});
afterEach(() => {
Scheduler.teardown();
});