From a608a0f0965fc35b926117a576718c2106d438a1 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Thu, 4 Mar 2021 10:55:47 +0000 Subject: [PATCH] feat(debug): add optional label config (#2) * feat(debug): allow optional labelling of logs * chore(debug): bump version to 1.2.0 * docs(debug): update API and usage examples to include labels --- README.md | 57 +++++-- package.json | 2 +- packages/operators/debug/README.md | 57 +++++-- packages/operators/debug/package.json | 2 +- .../debug/src/lib/operators-debug.spec.ts | 143 +++++++++++++++++- .../debug/src/lib/operators-debug.ts | 22 +-- 6 files changed, 250 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 55b153e..bd6269b 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,6 @@ We've all had occasions where we've felt the need to simply pipe a `tap(console. This operator aims to reduce the amount of typing you'll have to do! -_P.S. This did originate as a meme idea :P_ - ## Usage ### Installation @@ -42,6 +40,14 @@ Then pipe it to your Observables: const obs$ = source.pipe(debug()); ``` +You can add a label to help identify the Observable: + +```ts +const obs$ = source.pipe(debug('My Observable')); +// OUTPUT +// My Observable {value} +``` + It even allows you to turn it off if you are in a production environment, or for any other reason you wouldn't want to log to the console: ```ts @@ -50,7 +56,7 @@ const obs$ = source.pipe(debug({ shouldIgnore: true })); ### Examples -We can use it on it's own to simply log out values to the console +We can use it on its own to simply log out values to the console ```ts const obs$ = of('my test value'); @@ -60,6 +66,38 @@ obs$.pipe(debug()).subscribe(); // my test value ``` +We can add a label to the logs: + +```ts +const obs$ = of('my test value'); +obs$.pipe(debug('Obserable A')).subscribe(); + +// OUTPUT: +// Obserable A my test value + +// We can label it using the config object syntax: +const obs$ = of('my test value'); +obs$.pipe(debug({ label: 'Obserable A' })).subscribe(); + +// OUTPUT: +// Obserable A my test value + +// However, if we add a label and custom notification handlers, +// we will not get the label in the logs by default: +const obs$ = of('my test value'); +obs$ + .pipe( + debug({ + label: 'Obserable A', + next: (value) => console.log(value), + }) + ) + .subscribe(); + +// OUTPUT: +// my test value +``` + We can also set up our own notification handlers if we prefer: ```ts @@ -98,9 +136,10 @@ obs$ See the list of options available to configure the operator below -| Option | Description | Type | Default | -| -------------- | :----------------------------------------------------------------: | ------------------------- | --------------- | -| `shouldIgnore` | Do not perform the Debug actions | `boolean` | `false` | -| `next` | Action to perform when Observer receives a Next notification | `(value: T) => void` | `console.log` | -| `error` | Action to perform when Observer receives an Error notification | `(value: unkown) => void` | `console.error` | -| `complete` | Action to perform when Observer receives a Completion notification | `() => void` | `() => null` | +| Option | Description | Type | Default | +| -------------- | :----------------------------------------------------------------: | -------------------------- | --------------- | +| `shouldIgnore` | Do not perform the Debug actions | `boolean` | `false` | +| `label` | Add a label to the logs to help identify the Observable | `string` | `null` | +| `next` | Action to perform when Observer receives a Next notification | `(value: T) => void` | `console.log` | +| `error` | Action to perform when Observer receives an Error notification | `(value: unknown) => void` | `console.error` | +| `complete` | Action to perform when Observer receives a Completion notification | `() => void` | `() => null` | diff --git a/package.json b/package.json index 852155a..7414ca6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rxjs-debug-operator", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "scripts": { "nx": "nx", diff --git a/packages/operators/debug/README.md b/packages/operators/debug/README.md index 55b153e..bd6269b 100644 --- a/packages/operators/debug/README.md +++ b/packages/operators/debug/README.md @@ -15,8 +15,6 @@ We've all had occasions where we've felt the need to simply pipe a `tap(console. This operator aims to reduce the amount of typing you'll have to do! -_P.S. This did originate as a meme idea :P_ - ## Usage ### Installation @@ -42,6 +40,14 @@ Then pipe it to your Observables: const obs$ = source.pipe(debug()); ``` +You can add a label to help identify the Observable: + +```ts +const obs$ = source.pipe(debug('My Observable')); +// OUTPUT +// My Observable {value} +``` + It even allows you to turn it off if you are in a production environment, or for any other reason you wouldn't want to log to the console: ```ts @@ -50,7 +56,7 @@ const obs$ = source.pipe(debug({ shouldIgnore: true })); ### Examples -We can use it on it's own to simply log out values to the console +We can use it on its own to simply log out values to the console ```ts const obs$ = of('my test value'); @@ -60,6 +66,38 @@ obs$.pipe(debug()).subscribe(); // my test value ``` +We can add a label to the logs: + +```ts +const obs$ = of('my test value'); +obs$.pipe(debug('Obserable A')).subscribe(); + +// OUTPUT: +// Obserable A my test value + +// We can label it using the config object syntax: +const obs$ = of('my test value'); +obs$.pipe(debug({ label: 'Obserable A' })).subscribe(); + +// OUTPUT: +// Obserable A my test value + +// However, if we add a label and custom notification handlers, +// we will not get the label in the logs by default: +const obs$ = of('my test value'); +obs$ + .pipe( + debug({ + label: 'Obserable A', + next: (value) => console.log(value), + }) + ) + .subscribe(); + +// OUTPUT: +// my test value +``` + We can also set up our own notification handlers if we prefer: ```ts @@ -98,9 +136,10 @@ obs$ See the list of options available to configure the operator below -| Option | Description | Type | Default | -| -------------- | :----------------------------------------------------------------: | ------------------------- | --------------- | -| `shouldIgnore` | Do not perform the Debug actions | `boolean` | `false` | -| `next` | Action to perform when Observer receives a Next notification | `(value: T) => void` | `console.log` | -| `error` | Action to perform when Observer receives an Error notification | `(value: unkown) => void` | `console.error` | -| `complete` | Action to perform when Observer receives a Completion notification | `() => void` | `() => null` | +| Option | Description | Type | Default | +| -------------- | :----------------------------------------------------------------: | -------------------------- | --------------- | +| `shouldIgnore` | Do not perform the Debug actions | `boolean` | `false` | +| `label` | Add a label to the logs to help identify the Observable | `string` | `null` | +| `next` | Action to perform when Observer receives a Next notification | `(value: T) => void` | `console.log` | +| `error` | Action to perform when Observer receives an Error notification | `(value: unknown) => void` | `console.error` | +| `complete` | Action to perform when Observer receives a Completion notification | `() => void` | `() => null` | diff --git a/packages/operators/debug/package.json b/packages/operators/debug/package.json index 1385f59..a01337e 100644 --- a/packages/operators/debug/package.json +++ b/packages/operators/debug/package.json @@ -1,6 +1,6 @@ { "name": "rxjs-debug-operator", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "repository": { "url": "https://github.com/Coly010/rxjs-debug-operator" diff --git a/packages/operators/debug/src/lib/operators-debug.spec.ts b/packages/operators/debug/src/lib/operators-debug.spec.ts index 761d4b5..e85dabc 100644 --- a/packages/operators/debug/src/lib/operators-debug.spec.ts +++ b/packages/operators/debug/src/lib/operators-debug.spec.ts @@ -57,7 +57,7 @@ describe('operators - debug', () => { }); describe('when custom handlers are used', () => { - let config: DebugOperatorConfig; + let config: Partial>; beforeEach( () => @@ -223,7 +223,7 @@ describe('operators - debug', () => { describe('and when shouldIgnore is true', () => { beforeEach(() => (config.shouldIgnore = true)); - it('should log value to the console when next notification receieved', () => { + it('should not log value to the console when next notification receieved', () => { // ARRANGE const obs$ = of('my test value'); @@ -237,7 +237,7 @@ describe('operators - debug', () => { ); }); - it('should error value to the console when error notification receieved', () => { + it('should not error value to the console when error notification receieved', () => { // ARRANGE const obs$ = throwError('my error value'); @@ -248,7 +248,7 @@ describe('operators - debug', () => { expect(console.error).not.toHaveBeenCalledWith('my error value'); }); - it('should log value to the console when complete notification receieved', () => { + it('should not log value to the console when complete notification receieved', () => { // ARRANGE const obs$ = of('my test value'); @@ -264,4 +264,139 @@ describe('operators - debug', () => { }); }); }); + + describe('when a label is used', () => { + describe('using a string param', () => { + it('should log value to the console when next notification receieved with the label', () => { + // ARRANGE + const obs$ = of('my test value'); + + // ACT + obs$.pipe(debug('Test Label')).subscribe(); + + // ASSERT + expect(console.log).toHaveBeenCalledWith('Test Label', 'my test value'); + }); + + it('should error value to the console when error notification receieved with the label', () => { + // ARRANGE + const obs$ = throwError('my error value'); + + // ACT + obs$.pipe(debug('Test Label')).subscribe(); + + // ASSERT + expect(console.error).toHaveBeenCalledWith( + 'Test Label', + 'my error value' + ); + }); + }); + + describe('using the config object', () => { + let config: Partial>; + + beforeEach( + () => + (config = { + shouldIgnore: false, + label: 'Test Label', + }) + ); + + describe('and when shouldIgnore is false', () => { + beforeEach(() => (config.shouldIgnore = false)); + + it('should log value to the console when next notification receieved', () => { + // ARRANGE + const obs$ = of('my test value'); + + // ACT + obs$.pipe(debug(config)).subscribe(); + + // ASSERT + expect(console.log).toHaveBeenCalledWith( + 'Test Label', + 'my test value' + ); + }); + + it('should error value to the console when error notification receieved', () => { + // ARRANGE + const obs$ = throwError('my error value'); + + // ACT + obs$.pipe(debug(config)).subscribe(); + + // ASSERT + expect(console.error).toHaveBeenCalledWith( + 'Test Label', + 'my error value' + ); + }); + + it('should log value to the console when complete notification receieved', () => { + // ARRANGE + const obs$ = of('my test value'); + + // ACT + obs$.pipe(debug(config)).subscribe(); + + // ASSERT + expect(console.log).toHaveBeenCalledTimes(2); + expect(console.log).toHaveBeenNthCalledWith( + 2, + 'Test Label completed' + ); + }); + }); + + describe('and when shouldIgnore is true', () => { + beforeEach(() => (config.shouldIgnore = true)); + + it('should not log value to the console when next notification receieved', () => { + // ARRANGE + const obs$ = of('my test value'); + + // ACT + obs$.pipe(debug(config)).subscribe(); + + // ASSERT + expect(console.log).not.toHaveBeenCalledWith( + 'Test Label', + 'my test value' + ); + }); + + it('should not error value to the console when error notification receieved', () => { + // ARRANGE + const obs$ = throwError('my error value'); + + // ACT + obs$.pipe(debug(config)).subscribe(); + + // ASSERT + expect(console.error).not.toHaveBeenCalledWith( + 'Test Label', + 'my error value' + ); + }); + + it('should not log value to the console when complete notification receieved', () => { + // ARRANGE + const obs$ = of('my test value'); + + // ACT + obs$.pipe(debug(config)).subscribe(); + + // ASSERT + expect(console.log).not.toHaveBeenCalledTimes(2); + expect(console.log).not.toHaveBeenNthCalledWith( + 2, + 'Test Label completed' + ); + }); + }); + }); + }); }); diff --git a/packages/operators/debug/src/lib/operators-debug.ts b/packages/operators/debug/src/lib/operators-debug.ts index 25620d2..ccd44ca 100644 --- a/packages/operators/debug/src/lib/operators-debug.ts +++ b/packages/operators/debug/src/lib/operators-debug.ts @@ -4,17 +4,19 @@ import { MonoTypeOperatorFunction, Observer } from 'rxjs/internal/types'; export interface DebugOperatorConfig extends Omit, 'closed'> { shouldIgnore: boolean; + label: string; next: (value: T) => void; error: (value: unknown) => void; complete: () => void; } -function createDefaultConfig(): DebugOperatorConfig { +function createDefaultConfig(label: string = null): DebugOperatorConfig { return { shouldIgnore: false, - next: console.log, - error: console.error, - complete: () => null, + label, + next: label ? (v) => console.log(label, v) : console.log, + error: label ? (e) => console.error(label, e) : console.error, + complete: label ? () => console.log(`${label} completed`) : () => null, }; } @@ -24,12 +26,14 @@ function createDefaultConfig(): DebugOperatorConfig { * @param config The config to be used to set up the operator */ export function debug( - config: Partial> = {} + config?: Partial> | string ): MonoTypeOperatorFunction { - const { shouldIgnore, next, error, complete } = Object.assign( - createDefaultConfig(), - config - ); + const mergedConfig: DebugOperatorConfig = + typeof config === 'string' + ? createDefaultConfig(config) + : Object.assign(createDefaultConfig(config?.label), config); + + const { shouldIgnore, next, error, complete } = mergedConfig; return (source: Observable) => shouldIgnore ? source : source.pipe(tap(next, error, complete));