Skip to content

Commit

Permalink
feat(): support async await for onComplete
Browse files Browse the repository at this point in the history
  • Loading branch information
edbzn committed Jun 13, 2020
1 parent 40b4de5 commit 0ca4d80
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 9 deletions.
57 changes: 52 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ In order to test observables, you can use an `ObserverSpy` instance to "record"

You can also spy on the `error` or `complete` states of the observer.

You can use `done` or `async` / `await` to wait for `onComplete` to be called as well.

**Example:**

```js
// ... other imports
import { ObserverSpy } from '@hirez_io/observer-spy';

it('should spy on Observable values', () => {

const observerSpy = new ObserverSpy();
// BTW, if you're using TypeScript you can declare it with a generic:
// const observerSpy: ObserverSpy<string> = new ObserverSpy();
Expand Down Expand Up @@ -108,6 +109,17 @@ it('should spy on Observable values', () => {
}));
});

it('should support async await for onComplete()', async ()=>{
const observerSpy = new ObserverSpy();
const fakeObservable = of('first', 'second', 'third');

fakeObservable.subscribe(observerSpy);

await observerSpy.onComplete();

expect(observerSpy.receivedComplete()).toBe(true);
});

it('should spy on Observable errors', () => {
const observerSpy = new ObserverSpy();

Expand Down Expand Up @@ -161,28 +173,63 @@ it('should test Angular code with delay', fakeAsync(() => {
}));
```

### ▶ For only _promises_ (no timeouts / intervals) - just use `done`
### ▶ For microtasks related code (promises, but no timeouts / intervals) - just use `async` `await` or `done()`

You can use the `onComplete` method of the ObserverSpy to run the expectation and call `done`.
You can use the `onComplete` method to wait for a completion before checking the outcome.
Chose between `async` + `await` or `done`, both work.

Example:

```js
// ... other imports
import { ObserverSpy } from '@hirez_io/observer-spy';

it('should work with promises', (done) => {
it('should work with observables', async () => {
const observerSpy: ObserverSpy<string> = new ObserverSpy();

const fakeService = {
getData() {
return Promise.resolve('fake data');
return defer(() => of('fake data'));
},
};
const fakeObservable = of('').pipe(switchMap(() => fakeService.getData()));

fakeObservable.subscribe(observerSpy);

await observerSpy.onComplete();

expect(observerSpy.getLastValue()).toEqual('fake data');
});

it('should work with promises', async () => {
const observerSpy: ObserverSpy<string> = new ObserverSpy();

const fakeService = {
getData() {
return Promise.resolve('fake data');
},
};
const fakeObservable = defer(() => fakeService.getData());

fakeObservable.subscribe(observerSpy);

await observerSpy.onComplete();

expect(observerSpy.getLastValue()).toEqual('fake data');
});

it('should work with promises and "done()"', (done) => {
const observerSpy: ObserverSpy<string> = new ObserverSpy();

const fakeService = {
getData() {
return Promise.resolve('fake data');
},
};
const fakeObservable = defer(() => fakeService.getData());

fakeObservable.subscribe(observerSpy);

observerSpy.onComplete(() => {
expect(observerSpy.getLastValue()).toEqual('fake data');
done();
Expand Down
14 changes: 14 additions & 0 deletions src/fake-time.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,18 @@ describe('fakeTime', () => {
});
})
);

it(
'should support async await functionality',
fakeTime(async (flush) => {
const { observerSpy, delayedObservable, VALUES } = getDelayedObservable();

const sub = delayedObservable.subscribe(observerSpy);
flush();
sub.unsubscribe();

await observerSpy.onComplete();
expect(observerSpy.getValues()).toEqual(VALUES);
})
);
});
20 changes: 19 additions & 1 deletion src/observer-spy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('ObserverSpy', () => {
expect(observerSpy.receivedComplete()).toBe(true);
});

it('should be able to call a callback when it completes synchronously ', (done) => {
it('should be able to call a callback when it completes synchronously', (done) => {
const { observerSpy, fakeObservable } = getObservableWith3Values();

fakeObservable.subscribe(observerSpy);
Expand All @@ -84,6 +84,15 @@ describe('ObserverSpy', () => {
});
});

it('should return a resolved promise when it completes synchronously', async () => {
const { observerSpy, fakeObservable } = getObservableWith3Values();

fakeObservable.subscribe(observerSpy);

await observerSpy.onComplete();
expect(observerSpy.receivedComplete()).toBe(true);
});

it('should be able to call a callback when it completes asynchronously', (done) => {
const { observerSpy, fakeObservable } = getObservableWith3Values();

Expand All @@ -94,6 +103,15 @@ describe('ObserverSpy', () => {
done();
});
});

it('should return a resolved promise when it completes asynchronously', async () => {
const { observerSpy, fakeObservable } = getObservableWith3Values();

fakeObservable.pipe(delay(1)).subscribe(observerSpy);

await observerSpy.onComplete();
expect(observerSpy.receivedComplete()).toBe(true);
});
});

describe('GIVEN observable throws WHEN subscribing', () => {
Expand Down
15 changes: 12 additions & 3 deletions src/observer-spy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,21 @@ export class ObserverSpy<T> implements Observer<T> {
}
}

onComplete(callback: () => void) {
onComplete(): Promise<void>;
onComplete(callback: () => void): void;
onComplete(callback?: () => void) {
if (this.observerState.completeCalled) {
callback();
return callback ? callback() : Promise.resolve();
}

if (callback) {
this.observerState.onCompleteCallback = callback;
return;
}
this.observerState.onCompleteCallback = callback;

return new Promise((resolve) => {
this.observerState.onCompleteCallback = resolve;
});
}

getValuesLength(): number {
Expand Down

0 comments on commit 0ca4d80

Please sign in to comment.