Skip to content

Commit ac9abb7

Browse files
authored
Merge pull request #15 from cloudnc/test/improve-code-coverage
2 parents 962329e + ca69e25 commit ac9abb7

File tree

3 files changed

+62
-9
lines changed

3 files changed

+62
-9
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ jobs:
3232
- name: Test
3333
run: yarn lib:test:ci
3434
- name: Coverage
35-
run: yarn codecov
35+
uses: codecov/codecov-action@v1
36+
with:
37+
fail_ci_if_error: true # optional (default = false)
3638
- name: Rebuild for release
3739
if: contains('refs/heads/master refs/heads/next', github.ref)
3840
run: |

projects/ngx-observable-lifecycle/src/lib/ngx-observable-lifecycle.spec.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, OnDestroy } from '@angular/core';
1+
import { Component, OnDestroy, OnInit } from '@angular/core';
22
import { isObservable } from 'rxjs';
33
import { getObservableLifecycle } from './ngx-observable-lifecycle';
44

@@ -37,5 +37,52 @@ describe('ngx-observable-lifecycle', () => {
3737

3838
expect(() => unobservedInstance.ngOnDestroy()).not.toThrowError();
3939
});
40+
41+
it('should re-use observer subjects when a hook is observed multiple times', () => {
42+
const { ngOnInit: firstObservable } = getObservableLifecycle(componentInstance);
43+
const { ngOnInit: secondObservable } = getObservableLifecycle(componentInstance);
44+
45+
expect(firstObservable.source).toBe(secondObservable.source);
46+
});
47+
48+
it('invokes the original method if present', () => {
49+
const originalOnDestroySpy = jasmine.createSpy();
50+
51+
class TestClass implements OnDestroy {
52+
public ngOnDestroy(): void {
53+
originalOnDestroySpy();
54+
}
55+
}
56+
57+
const instance = new TestClass();
58+
59+
const { ngOnDestroy } = getObservableLifecycle(instance);
60+
61+
expect(originalOnDestroySpy).not.toHaveBeenCalled();
62+
63+
instance.ngOnDestroy();
64+
65+
expect(originalOnDestroySpy).toHaveBeenCalled();
66+
});
67+
68+
it('does not need the original hook(s) to be defined', () => {
69+
const onInitSpy = jasmine.createSpy();
70+
71+
class TestClass {}
72+
73+
const instance = new TestClass();
74+
75+
const { ngOnInit } = getObservableLifecycle(instance);
76+
77+
ngOnInit.subscribe(onInitSpy);
78+
79+
expect(onInitSpy).not.toHaveBeenCalled();
80+
81+
(instance as OnInit).ngOnInit();
82+
83+
expect(onInitSpy).toHaveBeenCalled();
84+
85+
(instance as OnDestroy).ngOnDestroy();
86+
});
4087
});
4188
});

projects/ngx-observable-lifecycle/src/lib/ngx-observable-lifecycle.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ type DecorateHookOptions = Partial<AllHookOptions>;
2929
export type DecoratedHooks = Record<LifecycleHookKey, Observable<void>>;
3030
export type DecoratedHooksSub = Record<LifecycleHookKey, Subject<void>>;
3131

32-
type ComponentInstance = Partial<AllHooks> & {
33-
[hookSubject]: Partial<DecoratedHooksSub>;
34-
[hooksPatched]: Partial<DecorateHookOptions>;
32+
type PatchedComponentInstance<K extends LifecycleHookKey> = Pick<AllHooks, K> & {
33+
[hookSubject]: Pick<DecoratedHooksSub, K>;
34+
constructor: {
35+
prototype: {
36+
[hooksPatched]: Pick<DecorateHookOptions, K>;
37+
};
38+
};
3539
};
3640

37-
function getSubjectForHook(componentInstance: ComponentInstance, hook: LifecycleHookKey): Subject<void> {
41+
function getSubjectForHook(componentInstance: PatchedComponentInstance<any>, hook: LifecycleHookKey): Subject<void> {
3842
if (!componentInstance[hookSubject]) {
3943
componentInstance[hookSubject] = {};
4044
}
@@ -51,13 +55,13 @@ function getSubjectForHook(componentInstance: ComponentInstance, hook: Lifecycle
5155
if (!proto[hooksPatched][hook]) {
5256
const originalHook = proto[hook];
5357

54-
proto[hook] = function (this: ComponentInstance) {
58+
proto[hook] = function (this: PatchedComponentInstance<typeof hook>) {
5559
(originalHook as () => void)?.call(this);
56-
this[hookSubject]?.[hook]?.next();
60+
this[hookSubject][hook].next();
5761
};
5862

5963
const originalOnDestroy = proto.ngOnDestroy;
60-
proto.ngOnDestroy = function (this: ComponentInstance) {
64+
proto.ngOnDestroy = function (this: PatchedComponentInstance<typeof hook>) {
6165
originalOnDestroy?.call(this);
6266
this[hookSubject]?.[hook]?.complete();
6367
delete this[hookSubject]?.[hook];

0 commit comments

Comments
 (0)