From e4700ca231e9d3f837af21317e82e9f7e945d630 Mon Sep 17 00:00:00 2001 From: Eugene Obrezkov Date: Sun, 20 Sep 2020 18:32:00 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20issue=20when=20notifyOnCh?= =?UTF-8?q?angeOnly=20stops=20emitting=20at=20all?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a user provides notifyOnChangeOnly option, we are trying to compare the new metadata with the old one by stringifying them. Turns out, that JSON.stringify() does not work on Map, so it returns an empty object all the time. Leading to broken comparsion that says that metadata never changes. --- .eslintrc.js | 1 + examples/options.ts | 2 +- src/Parser.ts | 17 +++++++++++++---- test/Parser.spec.ts | 11 +++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d07561f..840ed41 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -49,6 +49,7 @@ module.exports = { 'max-len': ['error', 120], 'max-lines-per-function': ['off'], 'max-statements': ['off'], + 'multiline-comment-style': ['error', 'separate-lines'], 'multiline-ternary': ['error', 'always-multiline'], 'no-ternary': ['off'], 'node/no-missing-import': ['error', { tryExtensions: ['.ts'] }], diff --git a/examples/options.ts b/examples/options.ts index 181e9ac..87ab2ad 100644 --- a/examples/options.ts +++ b/examples/options.ts @@ -6,7 +6,7 @@ const radioStation = new Parser({ errorInterval: 10 * 60, keepListen: false, metadataInterval: 5, - notifyOnChangeOnly: false, + notifyOnChangeOnly: true, url: 'https://live.hunter.fm/80s_high', userAgent: 'Custom User Agent', }); diff --git a/src/Parser.ts b/src/Parser.ts index e7c1705..b7433a0 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -28,7 +28,7 @@ export declare interface Parser { } export class Parser extends EventEmitter { - private previousMetadata = ''; + private previousMetadata: Map = new Map(); private readonly options: ParserOptions = { autoUpdate: true, emptyInterval: 5 * 60, @@ -61,10 +61,9 @@ export class Parser extends EventEmitter { this.destroyResponse(response); this.queueNextRequest(this.options.metadataInterval); - const newMetadata = JSON.stringify(metadata); - if (this.options.notifyOnChangeOnly && newMetadata !== this.previousMetadata) { + if (this.options.notifyOnChangeOnly && this.isMetadataChanged(metadata)) { + this.previousMetadata = metadata; this.emit('metadata', metadata); - this.previousMetadata = newMetadata; } else if (!this.options.notifyOnChangeOnly) { this.emit('metadata', metadata); } @@ -114,4 +113,14 @@ export class Parser extends EventEmitter { protected queueRequest (timeout = 0): void { setTimeout(this.makeRequest.bind(this), timeout * 1000); } + + protected isMetadataChanged (metadata: Map): boolean { + for (const [key, value] of metadata.entries()) { + if (this.previousMetadata.get(key) !== value) { + return true; + } + } + + return false; + } } diff --git a/test/Parser.spec.ts b/test/Parser.spec.ts index c3a68b9..edd6ff1 100644 --- a/test/Parser.spec.ts +++ b/test/Parser.spec.ts @@ -53,4 +53,15 @@ describe('parser', () => { resolve(); }); })); + + it('should properly emit metadata event when metadata has been updated', async () => await new Promise((resolve) => { + expect.hasAssertions(); + + const radio = new Parser({ autoUpdate: false, notifyOnChangeOnly: true, url: 'https://live.hunter.fm/80s_high' }); + radio.on('metadata', (metadata) => { + // @ts-expect-error I want to check that metadata was stored in the private property to later comparsion + expect(radio.previousMetadata).toStrictEqual(metadata); + resolve(); + }); + })); });