Skip to content

Commit

Permalink
feat: add toEmitValue matchers
Browse files Browse the repository at this point in the history
Closes: #526
  • Loading branch information
MillerSvt committed Jul 18, 2024
1 parent f54bca7 commit f3a9a07
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 15 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,33 @@ But got:
["----^------------!"]
```

## toEmitValueFirst
Verifies that the first emitted value from observable matches expected value.
```js
it('Should verify first emitted value', () => {
const x = cold('--a---b---c--|');
expect(x).toEmitValueFirst('a');
});
```

## toEmitValueLast
Verifies that the last emitted value from observable matches expected value.
```js
it('Should verify last emitted value', () => {
const x = cold('--a---b---c--|');
expect(x).toEmitValueLast('c');
});
```

## toEmitValueNth
Verifies that the N emitted value from observable matches expected value.
```js
it('Should verify second emitted value', () => {
const x = cold('--a---b---c--|');
expect(x).toEmitValueNth('b', 1);
});
```

## toSatisfyOnFlush
Allows you to assert on certain side effects/conditions that should be satisfied when the observable has been flushed (finished)
```js
Expand Down
41 changes: 31 additions & 10 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ 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 { Subscription } from 'rxjs';
import { Observable, skip, Subscription, take, takeLast } from 'rxjs';
import { toEmitValue } from './src/to-emit-value';

export type ObservableWithSubscriptions = ColdObservable | HotObservable;

Expand All @@ -21,6 +22,12 @@ declare global {
toBeMarble(marble: string): R;

toSatisfyOnFlush(func: () => void): R;

toEmitValueFirst(value: unknown): R;

toEmitValueLast(value: unknown): R;

toEmitValueNth(value: unknown, index: number): R;
}
}
}
Expand All @@ -32,6 +39,9 @@ declare module 'expect' {
toHaveNoSubscriptions(): R;
toBeMarble(marble: string): R;
toSatisfyOnFlush(func: () => void): R;
toEmitValueFirst(value: unknown): R;
toEmitValueLast(value: unknown): R;
toEmitValueNth(value: unknown, index: number): R;
}
}

Expand Down Expand Up @@ -83,21 +93,32 @@ expect.extend({
// tslint:disable:no-string-literal
const flushTests = Scheduler.get()['flushTests'];
flushTests[flushTests.length - 1].ready = true;
onFlush.push(func);
Scheduler.onFlush(func);
return dummyResult;
},
});

let onFlush: (() => void)[] = [];
toEmitValueFirst(observable: Observable<unknown>, expectedValue: unknown) {
toEmitValue(observable.pipe(take(1)), expectedValue);

return dummyResult;
},

toEmitValueLast(observable: Observable<unknown>, expectedValue: unknown) {
toEmitValue(observable.pipe(takeLast(1)), expectedValue);

return dummyResult;
},

toEmitValueNth(observable: Observable<unknown>, expectedValue: unknown, index: number) {
toEmitValue(observable.pipe(skip(index), take(1)), expectedValue);

return dummyResult;
},
});

beforeEach(() => {
Scheduler.init();
onFlush = [];
});
afterEach(() => {
Scheduler.get().run(() => {});
while (onFlush.length > 0) {
onFlush.shift()?.();
}
Scheduler.reset();
Scheduler.flush();
});
51 changes: 51 additions & 0 deletions spec/__snapshots__/to-emit-value-first.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`toEmitValueFirst matcher test negative cases Should fail if no values emitted 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"(a|)"
But got:
""
Difference:
- Expected
+ Received
- (a|)"
`;

exports[`toEmitValueFirst matcher test negative cases Should fail if no values emitted and completed 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"---(a|)"
But got:
"---|"
Difference:
- Expected
+ Received
- ---(a|)
+ ---|"
`;

exports[`toEmitValueFirst matcher test negative cases Should fail if other value emits 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"---(a|)"
But got:
"---(b|)"
Difference:
- Expected
+ Received
- ---(a|)
+ ---(b|)"
`;
67 changes: 67 additions & 0 deletions spec/__snapshots__/to-emit-value-last.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`toEmitValueLast matcher test negative cases Should fail if no values emitted 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"(a|)"
But got:
""
Difference:
- Expected
+ Received
- (a|)"
`;

exports[`toEmitValueLast matcher test negative cases Should fail if no values emitted and completed 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"---(a|)"
But got:
"---|"
Difference:
- Expected
+ Received
- ---(a|)
+ ---|"
`;

exports[`toEmitValueLast matcher test negative cases Should fail if observable never completes 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"(b|)"
But got:
""
Difference:
- Expected
+ Received
- (b|)"
`;

exports[`toEmitValueLast matcher test negative cases Should fail if other value emits 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"-------(b|)"
But got:
"-------(a|)"
Difference:
- Expected
+ Received
- -------(b|)
+ -------(a|)"
`;
51 changes: 51 additions & 0 deletions spec/__snapshots__/to-emit-value-nth.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`toEmitValueNth matcher test negative cases Should fail if no values emitted 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"(a|)"
But got:
""
Difference:
- Expected
+ Received
- (a|)"
`;

exports[`toEmitValueNth matcher test negative cases Should fail if no values emitted and completed 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"---(a|)"
But got:
"---|"
Difference:
- Expected
+ Received
- ---(a|)
+ ---|"
`;

exports[`toEmitValueNth matcher test negative cases Should fail if other value emits 1`] = `
"expect(received).toBeNotifications(expected)
Expected notifications to be:
"--(a|)"
But got:
"--(b|)"
Difference:
- Expected
+ Received
- --(a|)
+ --(b|)"
`;
54 changes: 54 additions & 0 deletions spec/to-emit-value-first.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { cold, Scheduler } from '../index';

describe('toEmitValueFirst matcher test', () => {
describe('positive cases', () => {
it('Should pass if observable completes', () => {
const a$ = cold('a-|');

expect(a$).toEmitValueFirst('a');
});

it('Should pass if observable not completes', () => {
const a$ = cold('a---');

expect(a$).toEmitValueFirst('a');
});

it('Should pass if value emits later', () => {
const a$ = cold('---a---');

expect(a$).toEmitValueFirst('a');
});

it('Should pass if multiple value emits later', () => {
const a$ = cold('---a--b---');

expect(a$).toEmitValueFirst('a');
});
});

describe('negative cases', () => {
it('Should fail if other value emits', () => {
const a$ = cold('---b---');

expect(a$).toEmitValueFirst('a');
});

it('Should fail if no values emitted', () => {
const a$ = cold('---');

expect(a$).toEmitValueFirst('a');
});

it('Should fail if no values emitted and completed', () => {
const a$ = cold('---|');

expect(a$).toEmitValueFirst('a');
});

afterEach(() => {
expect(() => Scheduler.flush()).toThrowErrorMatchingSnapshot();
Scheduler.init();
});
});
});
54 changes: 54 additions & 0 deletions spec/to-emit-value-last.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { cold, Scheduler } from '../index';

describe('toEmitValueLast matcher test', () => {
describe('positive cases', () => {
it('Should pass if observable completes', () => {
const a$ = cold('b-|');

expect(a$).toEmitValueLast('b');
});

it('Should pass if value emits later', () => {
const a$ = cold('---b---|');

expect(a$).toEmitValueLast('b');
});

it('Should pass if multiple value emits later', () => {
const a$ = cold('---a--b---|');

expect(a$).toEmitValueLast('b');
});
});

describe('negative cases', () => {
it('Should fail if other value emits', () => {
const a$ = cold('---a---|');

expect(a$).toEmitValueLast('b');
});

it('Should fail if observable never completes', () => {
const a$ = cold('---b---');

expect(a$).toEmitValueLast('b');
});

it('Should fail if no values emitted', () => {
const a$ = cold('---');

expect(a$).toEmitValueLast('a');
});

it('Should fail if no values emitted and completed', () => {
const a$ = cold('---|');

expect(a$).toEmitValueLast('a');
});

afterEach(() => {
expect(() => Scheduler.flush()).toThrowErrorMatchingSnapshot();
Scheduler.init();
});
});
});
Loading

0 comments on commit f3a9a07

Please sign in to comment.