diff --git a/lib/noble.js b/lib/noble.js index dc5d1425..a1e92fbb 100644 --- a/lib/noble.js +++ b/lib/noble.js @@ -188,10 +188,12 @@ class Noble extends EventEmitter { const self = this; const scan = (state) => { if (state !== 'poweredOn') { - self.once('stateChange', scan.bind(self)); + const boundScan = scan.bind(self); + self.once('stateChange', boundScan); const error = new Error(`Could not start scanning, state is ${state} (not poweredOn)`); if (typeof callback === 'function') { + self.removeListener('stateChange', boundScan); callback(error); } else { throw error; diff --git a/test/noble.test.js b/test/noble.test.js index 35736c24..cffff115 100644 --- a/test/noble.test.js +++ b/test/noble.test.js @@ -184,6 +184,24 @@ describe('noble', () => { ); expect(mockBindings.startScanning).not.toHaveBeenCalled(); }); + + test('should not cause MaxListenersExceededWarning warnings after repeated unauthorized errors', async () => { + noble._state = 'unauthorized'; + + const promise = noble.waitForPoweredOnAsync(0); + + for (let i = 0; i < 10; i++) { + try { + await noble.startScanningAsync([]); + } catch (error) { + } + } + + const finalListenerCount = noble.listenerCount('stateChange'); + + await expect(promise).rejects.toThrow('Timeout waiting for Noble to be powered on'); + expect(finalListenerCount).toBeLessThanOrEqual(1); + }); }); describe('stopScanning', () => { @@ -421,7 +439,7 @@ describe('noble', () => { await expect(promise).rejects.toThrow('Timeout waiting for Noble to be powered on'); }); - test('should not cause MaxListenersExceededWarning with multiple timeout calls', async () => { + test('should not cause MaxListenersExceededWarning warnings with multiple timeout calls', async () => { noble._state = 'poweredOff'; const promises = [];