From 1fdef68b902bc014d7dd02192b1faa9af31e12d0 Mon Sep 17 00:00:00 2001 From: Enea Jahollari Date: Mon, 11 Sep 2023 16:52:28 +0200 Subject: [PATCH 1/2] feat: added inject-destroy --- libs/ngxtension/inject-destroy/README.md | 3 ++ .../ngxtension/inject-destroy/ng-package.json | 5 ++ libs/ngxtension/inject-destroy/src/index.ts | 1 + .../inject-destroy/src/inject-destroy.spec.ts | 51 +++++++++++++++++++ .../inject-destroy/src/inject-destroy.ts | 44 ++++++++++++++++ libs/ngxtension/project.json | 4 +- tsconfig.base.json | 3 ++ 7 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 libs/ngxtension/inject-destroy/README.md create mode 100644 libs/ngxtension/inject-destroy/ng-package.json create mode 100644 libs/ngxtension/inject-destroy/src/index.ts create mode 100644 libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts create mode 100644 libs/ngxtension/inject-destroy/src/inject-destroy.ts diff --git a/libs/ngxtension/inject-destroy/README.md b/libs/ngxtension/inject-destroy/README.md new file mode 100644 index 00000000..43d9fece --- /dev/null +++ b/libs/ngxtension/inject-destroy/README.md @@ -0,0 +1,3 @@ +# ngxtension/inject-destroy + +Secondary entry point of `ngxtension`. It can be used by importing from `ngxtension/inject-destroy`. diff --git a/libs/ngxtension/inject-destroy/ng-package.json b/libs/ngxtension/inject-destroy/ng-package.json new file mode 100644 index 00000000..b3e53d69 --- /dev/null +++ b/libs/ngxtension/inject-destroy/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/libs/ngxtension/inject-destroy/src/index.ts b/libs/ngxtension/inject-destroy/src/index.ts new file mode 100644 index 00000000..134d92a9 --- /dev/null +++ b/libs/ngxtension/inject-destroy/src/index.ts @@ -0,0 +1 @@ +export * from './inject-destroy'; diff --git a/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts b/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts new file mode 100644 index 00000000..b5eea845 --- /dev/null +++ b/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts @@ -0,0 +1,51 @@ +import { Component, OnInit } from '@angular/core'; +import { + ComponentFixture, + TestBed, + fakeAsync, + tick, +} from '@angular/core/testing'; +import { interval, takeUntil } from 'rxjs'; +import { injectDestroy } from './inject-destroy'; + +describe(injectDestroy.name, () => { + describe('emits when the component is destroyed', () => { + @Component({ standalone: true, template: '' }) + class TestComponent implements OnInit { + destroy$ = injectDestroy(); + count = 0; + + ngOnInit() { + interval(1000) + .pipe(takeUntil(this.destroy$)) + .subscribe(() => this.count++); + } + } + + let component: TestComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TestComponent], + }).compileComponents(); + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + }); + + it('should handle async stuff', fakeAsync(() => { + component.ngOnInit(); + + expect(component.count).toBe(0); + tick(1000); + expect(component.count).toBe(1); + tick(1000); + expect(component.count).toBe(2); + + fixture.destroy(); // destroy the component here + + tick(1000); + expect(component.count).toBe(2); + })); + }); +}); diff --git a/libs/ngxtension/inject-destroy/src/inject-destroy.ts b/libs/ngxtension/inject-destroy/src/inject-destroy.ts new file mode 100644 index 00000000..c87cfaff --- /dev/null +++ b/libs/ngxtension/inject-destroy/src/inject-destroy.ts @@ -0,0 +1,44 @@ +import { + DestroyRef, + inject, + Injector, + runInInjectionContext, +} from '@angular/core'; +import { assertInjector } from 'ngxtension/assert-injector'; +import { ReplaySubject } from 'rxjs'; + +/** + * Injects the `DestroyRef` service and returns a `ReplaySubject` that emits + * when the component is destroyed. + * + * @throws {Error} If no `DestroyRef` is found. + * @returns {ReplaySubject} A `ReplaySubject` that emits when the component is destroyed. + * + * @example + * // In your component: + * export class MyComponent { + * private destroy$ = injectDestroy(); + * + * getData() { + * return this.service.getData() + * .pipe(takeUntil(this.destroy$)) + * .subscribe(data => { ... }); + * } + * } + */ +export const injectDestroy = (injector?: Injector) => { + injector = assertInjector(injectDestroy, injector); + + return runInInjectionContext(injector, () => { + const destroyRef = inject(DestroyRef); + + const subject$ = new ReplaySubject(1); + + destroyRef.onDestroy(() => { + subject$.next(); + subject$.complete(); + }); + + return subject$; + }); +}; diff --git a/libs/ngxtension/project.json b/libs/ngxtension/project.json index 86868867..1fa2dc11 100644 --- a/libs/ngxtension/project.json +++ b/libs/ngxtension/project.json @@ -53,7 +53,9 @@ "libs/ngxtension/repeat/**/*.ts", "libs/ngxtension/repeat/**/*.html", "libs/ngxtension/computed-from/**/*.ts", - "libs/ngxtension/computed-from/**/*.html" + "libs/ngxtension/computed-from/**/*.html", + "libs/ngxtension/inject-destroy/**/*.ts", + "libs/ngxtension/inject-destroy/**/*.html" ] } }, diff --git a/tsconfig.base.json b/tsconfig.base.json index 9c17160b..fc9dde8f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -25,6 +25,9 @@ "ngxtension/create-injection-token": [ "libs/ngxtension/create-injection-token/src/index.ts" ], + "ngxtension/inject-destroy": [ + "libs/ngxtension/inject-destroy/src/index.ts" + ], "ngxtension/repeat": ["libs/ngxtension/repeat/src/index.ts"], "ngxtension/resize": ["libs/ngxtension/resize/src/index.ts"] } From 43db19c81d5072b71f9fd6ec78c5b7fc5638327a Mon Sep 17 00:00:00 2001 From: Enea Jahollari Date: Tue, 12 Sep 2023 22:50:01 +0200 Subject: [PATCH 2/2] feat: simplify test scenarios --- libs/ngxtension/computed-from/src/computed-from.spec.ts | 6 ------ libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts | 3 --- 2 files changed, 9 deletions(-) diff --git a/libs/ngxtension/computed-from/src/computed-from.spec.ts b/libs/ngxtension/computed-from/src/computed-from.spec.ts index cb8d960c..2f892721 100644 --- a/libs/ngxtension/computed-from/src/computed-from.spec.ts +++ b/libs/ngxtension/computed-from/src/computed-from.spec.ts @@ -147,9 +147,6 @@ describe(computedFrom.name, () => { let fixture: ComponentFixture; beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [TestComponent], - }).compileComponents(); fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; }); @@ -209,9 +206,6 @@ describe(computedFrom.name, () => { let component: InInitComponent; beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [InInitComponent], - }).compileComponents(); const fixture = TestBed.createComponent(InInitComponent); component = fixture.componentInstance; }); diff --git a/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts b/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts index b5eea845..c95f3ba8 100644 --- a/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts +++ b/libs/ngxtension/inject-destroy/src/inject-destroy.spec.ts @@ -26,9 +26,6 @@ describe(injectDestroy.name, () => { let fixture: ComponentFixture; beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [TestComponent], - }).compileComponents(); fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; });