Skip to content

Instantly share code, notes, and snippets.

@ianjamieson
Last active October 8, 2018 13:47
Show Gist options
  • Save ianjamieson/85e64524737df6d6eb85ce39945ff894 to your computer and use it in GitHub Desktop.
Save ianjamieson/85e64524737df6d6eb85ce39945ff894 to your computer and use it in GitHub Desktop.
Observables Testing
describe('Observables Example', () => {
// set up observable
let observable: Observable<any>;
// mock the return value from the form
const formValue: string = 'United Kingdom';
it('should match observable', () => {
// create a mock observable, which triggers once and returns the formValue. This is effectively
// like triggering a form change
observable = of(formValue, 'testing');
// you can check that the observable is of Observable type
// see here for marble syntax, https://github.com/ReactiveX/rxjs/blob/master/doc/marble-testing.md
// this example uses of, where all the values are triggered at the same time
// the a matches the a property in the object, the b matches the b and the pipe shows observable complete
expect(observable).toBeObservable(cold('(ab|)', {a: formValue, b: 'testing'}));
});
it('should match observable', () => {
// I could mock a hot observable, like below:
// see more on hot vs. cold observables https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339
// "-" represents a hypothetical period of time
observable = hot('--a-b', {a: formValue, b: 'testing'});
// and now we can test that this works
expect(observable).toBeObservable(cold('--a-b', {a: formValue, b: 'testing' }));
});
it('should match observable with a map', () => {
// so, if I want to pipe my hot observable, with a map
// now each time a and b events are triggered, we map our values...
observable = hot('--a-b|', {a: formValue, b: 'testing'}).pipe(
// map each value, append "mapped"
map(originalValue => originalValue + 'mapped')
);
// I can test for this, I'd expect the values to have mapped at the end!
expect(observable).toBeObservable(cold('--a-b|', { a: formValue + 'mapped', b: 'testingmapped'}));
});
it('should test actual code', () => {
/**
* If there was an example like:
this.filteredCountries$ = this.subscriptionGroup.controls.clientCountry.valueChanges
.pipe(
startWith(''),
map(value => AccountDetailsComponent.autocompleteFilter(this.countries, value))
);
* We could mock the valueChanges observable, so you could spyOn
spyOn(instance.subscriptionGroup.controls.clientCountry, 'valueChanges').and.returnValue(hot('--a--'))
* Alternatively you could trigger a form change
fixture.nativeElement.querySelector('#formField').dispatchEvent(new Event('change'));
*/
// I will use the mocking example, we can consider what I am doing on the next line
// as mocking the form change obseravble, over an arbritraty length of time, trigger
// two form change events, (a and b) and on each of those, return the values
const formChangeObservable$: Observable<any> = hot('-a-b', {a: 'UK', b: 'Germany'});
// set up some sort of filter
function filter(v: string): string {
return v + 'filtered';
}
// pipe as per code example
const filteredCountries$: Observable<any> = formChangeObservable$.pipe(
// startWith operator forces a value to the beginning
startWith(''),
// in this map, we only return one value type
map(value => filter(value))
);
// i have added "s" as we have used the startWith operator
// the letters used are arbitrary, but they should have a matching object key
// otherwise it wil return the key as the value (eg. s)
expect(filteredCountries$).toBeObservable(cold('sa-b', {s: filter(''), a: filter('UK'), b: filter('Germany')}));
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment