@hirez_io/observer-spy
Advanced tools
Comparing version 2.0.0 to 2.1.0
@@ -41,4 +41,16 @@ # Contribution Guidelines | ||
Make your changes in a new git branch: | ||
* Hit that "Fork" button above (in this repo's github page). | ||
 | ||
* git clone your fork | ||
`git clone YOUR_FORK_URL` | ||
Get your url by from here 👇 | ||
 | ||
* Create a new branch locally in your fork's repo | ||
```shell | ||
@@ -84,2 +96,6 @@ git checkout -b my-fix-branch master | ||
Make sure you check the following checkbox "Allow edits from maintainers" - | ||
 | ||
If you need to update your PR for some reason - | ||
@@ -86,0 +102,0 @@ |
@@ -9,2 +9,3 @@ import { Observer } from 'rxjs'; | ||
onCompleteCallback: (() => void) | undefined; | ||
onErrorCallback: (() => void) | undefined; | ||
} | ||
@@ -23,2 +24,3 @@ export interface ObserverSpyConfig { | ||
onComplete(callback: () => void): void; | ||
onError(): Promise<void>; | ||
expectErrors(): void; | ||
@@ -25,0 +27,0 @@ getValuesLength(): number; |
@@ -12,2 +12,3 @@ "use strict"; | ||
onCompleteCallback: undefined, | ||
onErrorCallback: undefined, | ||
errorIsExpected: false, | ||
@@ -29,2 +30,5 @@ }; | ||
this.state.errorWasCalled = true; | ||
if (this.state.onErrorCallback) { | ||
this.state.onErrorCallback(); | ||
} | ||
}; | ||
@@ -50,2 +54,11 @@ ObserverSpy.prototype.complete = function () { | ||
}; | ||
ObserverSpy.prototype.onError = function () { | ||
var _this = this; | ||
if (this.state.errorWasCalled) { | ||
return Promise.resolve(); | ||
} | ||
return new Promise(function (resolve) { | ||
_this.state.onErrorCallback = resolve; | ||
}); | ||
}; | ||
ObserverSpy.prototype.expectErrors = function () { | ||
@@ -52,0 +65,0 @@ this.state.errorIsExpected = true; |
{ | ||
"name": "@hirez_io/observer-spy", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"repository": { | ||
@@ -5,0 +5,0 @@ "type": "git", |
103
README.md
@@ -13,11 +13,2 @@ # @hirez_io/observer-spy 👀💪 | ||
<div align="center"> | ||
<a href="http://testangular.com/?utm_source=github&utm_medium=link&utm_campaign=observer-spy"> | ||
<img src="for-readme/test-angular.jpg" | ||
alt="TestAngular.com - Free Angular Testing Workshop - The Roadmap to Angular Testing Mastery" | ||
width="600" | ||
/> | ||
</a> | ||
</div> | ||
<br/> | ||
@@ -38,2 +29,3 @@ | ||
- [Spying on Errors (`expectErrors`)](#spy-on-errors-with-receivederror-and-geterror) | ||
- [`onError` (using `async` + `await`)](#wait-for-onerror-before-expecting-the-result-using-async--await) | ||
- [Manually Creating Spies](#manually-using-new-observerspy) | ||
@@ -44,8 +36,8 @@ - [Auto Unsubscribing](#auto-unsubscribing) | ||
- [Testing Async Logic](#testing-async-logic) | ||
- [▶ RxJS + Angular: use `fakeAsync`](#%E2%96%B6-rxjs---angular-use-fakeasync) | ||
- [▶ RxJS + Angular: use `fakeAsync`](#-rxjs---angular-use-fakeasync) | ||
- [▶ RxJS + Promises: use `async` + `await`](#%E2%96%B6-rxjs--promises-use-async--await) | ||
- [▶ RxJS + Promises: use `async` + `await`](#-rxjs--promises-use-async--await) | ||
- [▶ RxJS Timers / Animations: use `fakeTime`](#%E2%96%B6-rxjs-timers--animations-use-faketime) | ||
- [▶ RxJS + _AJAX_ calls:](#%E2%96%B6-rxjs--_ajax_-calls) | ||
- [▶ RxJS Timers / Animations: use `fakeTime`](#-rxjs-timers--animations-use-faketime) | ||
- [▶ RxJS + _AJAX_ calls:](#-rxjs--ajax-calls) | ||
@@ -110,2 +102,15 @@ | ||
### Here's what people had to say: | ||
 | ||
--- | ||
 | ||
--- | ||
<br/> | ||
## Why Observer-Spy is easier? | ||
@@ -235,2 +240,3 @@ | ||
// 👇 | ||
await observerSpy.onComplete(); // <-- the test will pause here until the observable is complete | ||
@@ -273,2 +279,22 @@ | ||
### Wait for `onError` before expecting the result (using `async` + `await`) | ||
```js | ||
it('should support async await for onError()', async () => { | ||
const fakeObservable = throwError('FAKE ERROR'); | ||
const observerSpy = subscribeSpyTo(fakeObservable, {expectErrors: true}); | ||
// 👇 | ||
await observerSpy.onError(); // <-- the test will pause here until the observer receive the error | ||
expect(observerSpy.getError()).toEqual('FAKE ERROR'); | ||
}); | ||
``` | ||
<br/> | ||
## Manually using `new ObserverSpy()` | ||
@@ -329,15 +355,22 @@ | ||
In order to save you the trouble of calling `unsubscribe` in each test, you can configure the library to auto unsubscribe from every observer you create with `subscribeSpyTo()`. | ||
### ⚠ PAY ATTENTION: | ||
* You should only call `autoUnsubscribe()` once per environment **(not manually after each test!)**. You do it in your testing environment setup files (like `jest.config.js` or `test.ts` in Angular). | ||
* This works **only with subscriptions created** using either `subscribeSpyTo()` or `queueForAutoUnsubscribe()`. | ||
* Requires a global `afterEach` function, so **it only works** with frameworks like **Jasmine**, **Mocha** and **Jest**. | ||
* Currently **it only works** with frameworks like **Jasmine**, **Mocha** and **Jest** (because they have a global `afterEach` function) | ||
## `autoUnsubscribe()` | ||
This library provide helper functions to help you configure this behavior - | ||
In order to save you the trouble of calling `unsubscribe` in each test, you can configure the library to auto unsubscribe from every observer you create with `subscribeSpyTo()`. | ||
<br/> | ||
### Configuring Jest with `autoUnsubscribe` | ||
### ⚒ Configuring Jest with `setup-auto-unsubscribe.js` | ||
This requires Jest to be loaded and then calls `autoUnsubscribe()` which sets up a global / root `afterEach` function that unsubscribes from your observer spies. | ||
Add this to your jest configuration (i.e `jest.config.js`): | ||
@@ -351,7 +384,14 @@ | ||
### Configuring Angular with `autoUnsubscribe` | ||
<br/> | ||
Add this to your `test.ts` | ||
### ⚒ Configuring Angular with `autoUnsubscribe` | ||
This will add a root level `afterEach()` once that auto unsubscribes observer spies. | ||
Add this to your `test.ts` - | ||
```ts | ||
// test.ts | ||
// ~~~~~~~ | ||
import { autoUnsubscribe } from '@hirez_io/observer-spy'; | ||
@@ -363,7 +403,7 @@ | ||
### Manually adding a subscription with `queueForAutoUnsubscribe` | ||
<br/> | ||
## | ||
### ⚒ Manually adding a subscription with `queueForAutoUnsubscribe` | ||
If you configured `autoUnsubscribe()` in your environment and want your manually created spies (via `new ObserverSpy()`) to be "auto unsubscribed" you can use `queueForAutoUnsubscribe(subscription)`. | ||
If you configured your environment to "autoUnsubscribe" and want your manually created spies (via `new ObserverSpy()`) to be "auto unsubscribed" as well, you can use `queueForAutoUnsubscribe(subscription)`. | ||
@@ -391,2 +431,4 @@ It accepts any `Unsubscribable` object which has an `unsubscribe()` method - | ||
``` | ||
This will ensure your manually created spies are auto unsubscribed at the end of each test. | ||
<br/> | ||
@@ -536,5 +578,18 @@ | ||
# Learn More: | ||
<div align="center"> | ||
<a href="https://learn.hirez.io/?utm_source=github&utm_medium=link&utm_campaign=observer-spy"> | ||
<img src="for-readme/test-angular.jpg" | ||
alt="TestAngular.com - Free Angular Testing Workshop - The Roadmap to Angular Testing Mastery" | ||
width="600" | ||
/> | ||
</a> | ||
</div> | ||
<br/> | ||
# 🧠 Wanna become a PRO Observables tester? | ||
In [Angular Class Testing In action](http://testangular.com/?utm_source=github&utm_medium=link&utm_campaign=observer-spy) course Shai Reznik goes over all the differences and show you how to use observer spies to test complex Observable chains with `switchMap`, `interval` etc... | ||
In [Angular Class Testing In action](https://learn.hirez.io/?utm_source=github&utm_medium=link&utm_campaign=observer-spy) course Shai Reznik goes over all the differences and show you how to use observer spies to test complex Observable chains with `switchMap`, `interval` etc... | ||
@@ -587,4 +642,2 @@ <br/> | ||
## License | ||
@@ -591,0 +644,0 @@ |
@@ -1,3 +0,3 @@ | ||
import { Observable, of, throwError } from 'rxjs'; | ||
import { delay } from 'rxjs/operators'; | ||
import { Observable, of, throwError, timer } from 'rxjs'; | ||
import { delay, switchMap } from 'rxjs/operators'; | ||
import { ObserverSpy } from './observer-spy'; | ||
@@ -158,3 +158,37 @@ | ||
}); | ||
it('should be able to await "onError" if error already received', async () => { | ||
const observerSpy: ObserverSpy<string> = new ObserverSpy({ expectErrors: true }); | ||
const { throwingObservable } = getThrowingObservable(); | ||
throwingObservable.subscribe(observerSpy).unsubscribe(); | ||
await observerSpy.onError(); | ||
expect(observerSpy.getError()).toEqual(FAKE_ERROR_MESSAGE); | ||
}); | ||
}); | ||
describe('GIVEN observable is throwing with delay', () => { | ||
const FAKE_ERROR_MESSAGE = 'FAKE ERROR'; | ||
function getThrowingObservableWithDelay() { | ||
const throwingObservable: Observable<string> = timer(1).pipe( | ||
switchMap(() => throwError(FAKE_ERROR_MESSAGE)) | ||
); | ||
return { | ||
throwingObservable, | ||
}; | ||
} | ||
it('should be able to await "onError" and check the error', async () => { | ||
const observerSpy: ObserverSpy<string> = new ObserverSpy({ expectErrors: true }); | ||
const { throwingObservable } = getThrowingObservableWithDelay(); | ||
throwingObservable.subscribe(observerSpy); | ||
await observerSpy.onError(); | ||
expect(observerSpy.getError()).toEqual(FAKE_ERROR_MESSAGE); | ||
}); | ||
}); | ||
}); |
@@ -10,2 +10,3 @@ import { Observer } from 'rxjs'; | ||
onCompleteCallback: (() => void) | undefined; | ||
onErrorCallback: (() => void) | undefined; | ||
} | ||
@@ -26,2 +27,3 @@ | ||
onCompleteCallback: undefined, | ||
onErrorCallback: undefined, | ||
errorIsExpected: false, | ||
@@ -47,2 +49,5 @@ }; | ||
this.state.errorWasCalled = true; | ||
if (this.state.onErrorCallback) { | ||
this.state.onErrorCallback(); | ||
} | ||
} | ||
@@ -74,2 +79,11 @@ | ||
onError(): Promise<void> { | ||
if (this.state.errorWasCalled) { | ||
return Promise.resolve(); | ||
} | ||
return new Promise((resolve) => { | ||
this.state.onErrorCallback = resolve; | ||
}); | ||
} | ||
expectErrors() { | ||
@@ -76,0 +90,0 @@ this.state.errorIsExpected = true; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
295483
58
835
636