Browse Source

feat: add a subscription service

pull/4838/head
Arman Ozak 6 years ago
parent
commit
c19a986858
  1. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  2. 50
      npm/ng-packs/packages/core/src/lib/services/subscription.service.ts
  3. 95
      npm/ng-packs/packages/core/src/lib/tests/subscription.service.spec.ts

1
npm/ng-packs/packages/core/src/lib/services/index.ts

@ -11,4 +11,5 @@ export * from './profile.service';
export * from './rest.service';
export * from './routes.service';
export * from './session-state.service';
export * from './subscription.service';
export * from './track-by.service';

50
npm/ng-packs/packages/core/src/lib/services/subscription.service.ts

@ -0,0 +1,50 @@
import { Injectable } from '@angular/core';
import type { OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import type { Observable, PartialObserver } from 'rxjs';
@Injectable()
export class SubscriptionService implements OnDestroy {
private subscription = new Subscription();
get isClosed() {
return this.subscription.closed;
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
reset() {
this.subscription.unsubscribe();
this.subscription = new Subscription();
}
subscribe<T extends unknown>(
source$: Observable<T>,
next?: (value: T) => void,
error?: (error: any) => void,
): Subscription;
subscribe<T extends unknown>(source$: Observable<T>, observer?: PartialObserver<T>): Subscription;
subscribe<T extends unknown>(
source$: Observable<T>,
nextOrObserver?: PartialObserver<T> | Next<T>,
error?: (error: any) => void,
): Subscription {
const subscription = source$.subscribe(nextOrObserver as Next<T>, error);
this.subscription.add(subscription);
return subscription;
}
unsubscribe(subscription: Subscription | undefined | null) {
if (!subscription) return;
this.subscription.remove(subscription);
subscription.unsubscribe();
}
unsubscribeAll() {
this.subscription.unsubscribe();
}
}
type Next<T> = (value: T) => void;

95
npm/ng-packs/packages/core/src/lib/tests/subscription.service.spec.ts

@ -0,0 +1,95 @@
import { of, Subscription, timer } from 'rxjs';
import { SubscriptionService } from '../services/subscription.service';
describe('SubscriptionService', () => {
let service: SubscriptionService;
beforeEach(() => {
service = new SubscriptionService();
});
afterEach(() => {
service['subscription'].unsubscribe();
});
describe('#subscribe', () => {
it('should subscribe to given observable with next and error functions and return the Subscription instance', () => {
const next = jest.fn();
const error = jest.fn();
const subscription = service.subscribe(of(null), next, error);
expect(subscription).toBeInstanceOf(Subscription);
expect(next).toHaveBeenCalledWith(null);
expect(next).toHaveBeenCalledTimes(1);
expect(error).not.toHaveBeenCalled();
});
it('should subscribe to given observable with observer and return the Subscription instance', () => {
const observer = { next: jest.fn(), complete: jest.fn() };
const subscription = service.subscribe(of(null), observer);
expect(subscription).toBeInstanceOf(Subscription);
expect(observer.next).toHaveBeenCalledWith(null);
expect(observer.next).toHaveBeenCalledTimes(1);
expect(observer.complete).toHaveBeenCalledTimes(1);
});
});
describe('#isClosed', () => {
it('should return true if subscriptions are alive and false if not', () => {
service.subscribe(timer(1000), () => {});
expect(service.isClosed).toBe(false);
service['subscription'].unsubscribe();
expect(service.isClosed).toBe(true);
});
});
describe('#unsubscribeAll', () => {
it('should close all subscriptions and the parent subscription', () => {
const sub1 = service.subscribe(timer(1000), () => {});
const sub2 = service.subscribe(timer(1000), () => {});
expect(sub1.closed).toBe(false);
expect(sub2.closed).toBe(false);
expect(service.isClosed).toBe(false);
service.unsubscribeAll();
expect(sub1.closed).toBe(true);
expect(sub2.closed).toBe(true);
expect(service.isClosed).toBe(true);
});
});
describe('#reset', () => {
it('should close all subscriptions but not the parent subscription', () => {
const sub1 = service.subscribe(timer(1000), () => {});
const sub2 = service.subscribe(timer(1000), () => {});
expect(sub1.closed).toBe(false);
expect(sub2.closed).toBe(false);
expect(service.isClosed).toBe(false);
service.reset();
expect(sub1.closed).toBe(true);
expect(sub2.closed).toBe(true);
expect(service.isClosed).toBe(false);
});
});
describe('#unsubscribe', () => {
it('should unsubscribe from given subscription only', () => {
const sub1 = service.subscribe(timer(1000), () => {});
const sub2 = service.subscribe(timer(1000), () => {});
expect(service.isClosed).toBe(false);
service.unsubscribe(sub1);
expect(sub1.closed).toBe(true);
expect(service.isClosed).toBe(false);
service.unsubscribe(sub2);
expect(sub2.closed).toBe(true);
expect(service.isClosed).toBe(false);
});
});
});
Loading…
Cancel
Save