@stoprocent/noble 1.9.2-16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.editorconfig +11 -0
  2. package/.eslintrc.js +25 -0
  3. package/.github/FUNDING.yml +2 -0
  4. package/.github/workflows/fediverse-action.yml +16 -0
  5. package/.github/workflows/nodepackage.yml +77 -0
  6. package/.github/workflows/npm-publish.yml +26 -0
  7. package/.github/workflows/prebuild.yml +65 -0
  8. package/.nycrc.json +4 -0
  9. package/CHANGELOG.md +119 -0
  10. package/LICENSE +20 -0
  11. package/MAINTAINERS.md +1 -0
  12. package/README.md +833 -0
  13. package/assets/noble-logo.png +0 -0
  14. package/assets/noble-logo.svg +13 -0
  15. package/binding.gyp +19 -0
  16. package/codecov.yml +5 -0
  17. package/examples/advertisement-discovery.js +65 -0
  18. package/examples/cache-gatt-discovery.js +198 -0
  19. package/examples/cache-gatt-reconnect.js +164 -0
  20. package/examples/echo.js +104 -0
  21. package/examples/enter-exit.js +78 -0
  22. package/examples/peripheral-explorer-async.js +133 -0
  23. package/examples/peripheral-explorer.js +225 -0
  24. package/examples/pizza/README.md +15 -0
  25. package/examples/pizza/central.js +194 -0
  26. package/examples/pizza/pizza.js +60 -0
  27. package/index.d.ts +203 -0
  28. package/index.js +6 -0
  29. package/lib/characteristic.js +161 -0
  30. package/lib/characteristics.json +449 -0
  31. package/lib/descriptor.js +72 -0
  32. package/lib/descriptors.json +47 -0
  33. package/lib/distributed/bindings.js +326 -0
  34. package/lib/hci-socket/acl-stream.js +60 -0
  35. package/lib/hci-socket/bindings.js +788 -0
  36. package/lib/hci-socket/crypto.js +74 -0
  37. package/lib/hci-socket/gap.js +432 -0
  38. package/lib/hci-socket/gatt.js +809 -0
  39. package/lib/hci-socket/hci-status.json +71 -0
  40. package/lib/hci-socket/hci.js +1264 -0
  41. package/lib/hci-socket/signaling.js +76 -0
  42. package/lib/hci-socket/smp.js +140 -0
  43. package/lib/hci-uart/bindings.js +569 -0
  44. package/lib/hci-uart/hci-serial-parser.js +70 -0
  45. package/lib/hci-uart/hci.js +1336 -0
  46. package/lib/mac/binding.gyp +26 -0
  47. package/lib/mac/bindings.js +11 -0
  48. package/lib/mac/src/ble_manager.h +41 -0
  49. package/lib/mac/src/ble_manager.mm +435 -0
  50. package/lib/mac/src/callbacks.cc +222 -0
  51. package/lib/mac/src/callbacks.h +84 -0
  52. package/lib/mac/src/napi_objc.h +12 -0
  53. package/lib/mac/src/napi_objc.mm +50 -0
  54. package/lib/mac/src/noble_mac.h +34 -0
  55. package/lib/mac/src/noble_mac.mm +264 -0
  56. package/lib/mac/src/objc_cpp.h +26 -0
  57. package/lib/mac/src/objc_cpp.mm +126 -0
  58. package/lib/mac/src/peripheral.h +23 -0
  59. package/lib/manufacture.js +48 -0
  60. package/lib/noble.js +593 -0
  61. package/lib/peripheral.js +219 -0
  62. package/lib/resolve-bindings-web.js +9 -0
  63. package/lib/resolve-bindings.js +44 -0
  64. package/lib/service.js +72 -0
  65. package/lib/services.json +92 -0
  66. package/lib/webbluetooth/bindings.js +368 -0
  67. package/lib/websocket/bindings.js +321 -0
  68. package/lib/win/binding.gyp +23 -0
  69. package/lib/win/bindings.js +11 -0
  70. package/lib/win/src/ble_manager.cc +802 -0
  71. package/lib/win/src/ble_manager.h +77 -0
  72. package/lib/win/src/callbacks.cc +274 -0
  73. package/lib/win/src/callbacks.h +33 -0
  74. package/lib/win/src/napi_winrt.cc +76 -0
  75. package/lib/win/src/napi_winrt.h +12 -0
  76. package/lib/win/src/noble_winrt.cc +308 -0
  77. package/lib/win/src/noble_winrt.h +34 -0
  78. package/lib/win/src/notify_map.cc +62 -0
  79. package/lib/win/src/notify_map.h +50 -0
  80. package/lib/win/src/peripheral.h +23 -0
  81. package/lib/win/src/peripheral_winrt.cc +296 -0
  82. package/lib/win/src/peripheral_winrt.h +82 -0
  83. package/lib/win/src/radio_watcher.cc +125 -0
  84. package/lib/win/src/radio_watcher.h +61 -0
  85. package/lib/win/src/winrt_cpp.cc +82 -0
  86. package/lib/win/src/winrt_cpp.h +11 -0
  87. package/lib/win/src/winrt_guid.cc +12 -0
  88. package/lib/win/src/winrt_guid.h +13 -0
  89. package/misc/nrf52840dk.hex +6921 -0
  90. package/misc/prj.conf +43 -0
  91. package/package.json +96 -0
  92. package/test/lib/characteristic.test.js +791 -0
  93. package/test/lib/descriptor.test.js +249 -0
  94. package/test/lib/distributed/bindings.test.js +918 -0
  95. package/test/lib/hci-socket/acl-stream.test.js +188 -0
  96. package/test/lib/hci-socket/bindings.test.js +1756 -0
  97. package/test/lib/hci-socket/crypto.test.js +55 -0
  98. package/test/lib/hci-socket/gap.test.js +1089 -0
  99. package/test/lib/hci-socket/gatt.test.js +2392 -0
  100. package/test/lib/hci-socket/hci.test.js +1891 -0
  101. package/test/lib/hci-socket/signaling.test.js +94 -0
  102. package/test/lib/hci-socket/smp.test.js +268 -0
  103. package/test/lib/manufacture.test.js +77 -0
  104. package/test/lib/peripheral.test.js +623 -0
  105. package/test/lib/resolve-bindings.test.js +102 -0
  106. package/test/lib/service.test.js +195 -0
  107. package/test/lib/webbluetooth/bindings.test.js +190 -0
  108. package/test/lib/websocket/bindings.test.js +456 -0
  109. package/test/noble.test.js +1565 -0
  110. package/test.js +131 -0
  111. package/with-bindings.js +5 -0
  112. package/ws-slave.js +404 -0
@@ -0,0 +1,102 @@
1
+ const should = require('should');
2
+ const proxyquire = require('proxyquire').noCallThru();
3
+ const { EventEmitter } = require('events');
4
+
5
+ let chosenPlatform;
6
+ let chosenRelease;
7
+ const platform = () => chosenPlatform;
8
+ const release = () => chosenRelease;
9
+
10
+ class NobleMac {}
11
+
12
+ class NobleWinrt {}
13
+
14
+ const NobleMacImport = proxyquire('../../lib/mac/bindings', {
15
+ 'node-gyp-build': () => ({ NobleMac })
16
+ });
17
+
18
+ const NobleWinrtImport = proxyquire('../../lib/win/bindings', {
19
+ 'node-gyp-build': () => ({ NobleWinrt })
20
+ });
21
+
22
+ const WebSocket = require('../../lib/websocket/bindings');
23
+ const NobleBindings = proxyquire('../../lib/distributed/bindings', {
24
+ ws: { Server: EventEmitter }
25
+ });
26
+ const HciNobleBindings = proxyquire('../../lib/hci-socket/bindings', {
27
+ './hci': EventEmitter
28
+ });
29
+ const resolver = proxyquire('../../lib/resolve-bindings', {
30
+ './distributed/bindings': NobleBindings,
31
+ './hci-socket/bindings': HciNobleBindings,
32
+ './mac/bindings': NobleMacImport,
33
+ './win/bindings': NobleWinrtImport,
34
+ os: { platform, release }
35
+ });
36
+
37
+ describe('resolve-bindings', () => {
38
+ const OLD_ENV = process.env;
39
+
40
+ beforeEach(() => {
41
+ // Clone initial environment
42
+ process.env = Object.assign({}, OLD_ENV);
43
+ });
44
+
45
+ afterEach(() => {
46
+ // Restore initial environment
47
+ process.env = OLD_ENV;
48
+ });
49
+
50
+ it('web socket', () => {
51
+ process.env.NOBLE_WEBSOCKET = true;
52
+
53
+ const bindings = resolver({});
54
+ should(bindings).instanceof(WebSocket);
55
+ });
56
+
57
+ it('distributed', () => {
58
+ process.env.NOBLE_DISTRIBUTED = true;
59
+
60
+ const bindings = resolver({});
61
+ should(bindings).instanceof(NobleBindings);
62
+ });
63
+
64
+ it('mac', () => {
65
+ chosenPlatform = 'darwin';
66
+
67
+ const bindings = resolver({});
68
+ should(bindings).instanceof(NobleMac);
69
+ });
70
+
71
+ it('linux', () => {
72
+ chosenPlatform = 'linux';
73
+
74
+ const bindings = resolver({});
75
+ should(bindings).instanceof(HciNobleBindings);
76
+ });
77
+
78
+ it('freebsd', () => {
79
+ chosenPlatform = 'freebsd';
80
+
81
+ const bindings = resolver({});
82
+ should(bindings).instanceof(HciNobleBindings);
83
+ });
84
+
85
+ it('win32', () => {
86
+ chosenPlatform = 'win32';
87
+ chosenRelease = '10.0.22000';
88
+
89
+ const bindings = resolver({});
90
+ should(bindings).instanceof(NobleWinrt);
91
+ });
92
+
93
+ it('unknwon', () => {
94
+ chosenPlatform = 'unknwon';
95
+
96
+ try {
97
+ resolver({});
98
+ } catch (e) {
99
+ should(e).have.property('message', 'Unsupported platform');
100
+ }
101
+ });
102
+ });
@@ -0,0 +1,195 @@
1
+ const should = require('should');
2
+ const sinon = require('sinon');
3
+
4
+ const { assert } = sinon;
5
+
6
+ const Service = require('../../lib/service');
7
+
8
+ describe('service', () => {
9
+ let mockNoble = null;
10
+ const mockPeripheralId = 'mock-peripheral-id';
11
+ const mockUuid = 'mock-uuid';
12
+
13
+ let service = null;
14
+
15
+ beforeEach(() => {
16
+ mockNoble = {};
17
+
18
+ service = new Service(mockNoble, mockPeripheralId, mockUuid);
19
+ });
20
+
21
+ it('should have a uuid', () => {
22
+ should(service.uuid).equal(mockUuid);
23
+ });
24
+
25
+ it('should lookup name and type by uuid', () => {
26
+ service = new Service(mockNoble, mockPeripheralId, '1800');
27
+
28
+ should(service.name).equal('Generic Access');
29
+ should(service.type).equal('org.bluetooth.service.generic_access');
30
+ });
31
+
32
+ describe('toString', () => {
33
+ it('should be uuid, name, type, includedServiceUuids', () => {
34
+ should(service.toString()).equal('{"uuid":"mock-uuid","name":null,"type":null,"includedServiceUuids":null}');
35
+ });
36
+ });
37
+
38
+ describe('discoverIncludedServices', () => {
39
+ beforeEach(() => {
40
+ mockNoble.discoverIncludedServices = sinon.spy();
41
+ });
42
+
43
+ afterEach(() => {
44
+ sinon.reset();
45
+ });
46
+
47
+ it('should delegate to noble', () => {
48
+ service.discoverIncludedServices();
49
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, undefined);
50
+ });
51
+
52
+ it('should delegate to noble, with uuids', () => {
53
+ const mockUuids = [];
54
+ service.discoverIncludedServices(mockUuids);
55
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, mockUuids);
56
+ });
57
+
58
+ it('should callback', () => {
59
+ const callback = sinon.spy();
60
+
61
+ service.discoverIncludedServices(null, callback);
62
+ service.emit('includedServicesDiscover');
63
+
64
+ assert.calledOnceWithExactly(callback, null, undefined);
65
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, null);
66
+ });
67
+
68
+ it('should callback with data', () => {
69
+ const mockIncludedServiceUuids = ['service1'];
70
+ const callback = sinon.spy();
71
+
72
+ service.discoverIncludedServices(null, callback);
73
+ service.emit('includedServicesDiscover', mockIncludedServiceUuids);
74
+
75
+ assert.calledOnceWithExactly(callback, null, mockIncludedServiceUuids);
76
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, null);
77
+ });
78
+ });
79
+
80
+ describe('discoverIncludedServicesAsync', () => {
81
+ beforeEach(() => {
82
+ mockNoble.discoverIncludedServices = sinon.spy();
83
+ });
84
+
85
+ afterEach(() => {
86
+ sinon.reset();
87
+ });
88
+
89
+ it('should delegate to noble', async () => {
90
+ const promise = service.discoverIncludedServicesAsync();
91
+ service.emit('includedServicesDiscover');
92
+
93
+ should(promise).resolvedWith(undefined);
94
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, undefined);
95
+ });
96
+
97
+ it('should delegate to noble, with uuids', async () => {
98
+ const mockUuids = [];
99
+ const promise = service.discoverIncludedServicesAsync(mockUuids);
100
+ service.emit('includedServicesDiscover');
101
+
102
+ should(promise).resolvedWith(undefined);
103
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, mockUuids);
104
+ });
105
+
106
+ it('should resolve with data', async () => {
107
+ const mockIncludedServiceUuids = ['service1'];
108
+
109
+ const promise = service.discoverIncludedServicesAsync();
110
+ service.emit('includedServicesDiscover', mockIncludedServiceUuids);
111
+
112
+ should(promise).resolvedWith(mockIncludedServiceUuids);
113
+ assert.calledOnceWithExactly(mockNoble.discoverIncludedServices, mockPeripheralId, mockUuid, undefined);
114
+ });
115
+ });
116
+
117
+ describe('discoverCharacteristics', () => {
118
+ beforeEach(() => {
119
+ mockNoble.discoverCharacteristics = sinon.spy();
120
+ });
121
+
122
+ afterEach(() => {
123
+ sinon.reset();
124
+ });
125
+
126
+ it('should delegate to noble', () => {
127
+ service.discoverCharacteristics();
128
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, undefined);
129
+ });
130
+
131
+ it('should delegate to noble, with uuids', () => {
132
+ const mockUuids = [];
133
+ service.discoverCharacteristics(mockUuids);
134
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, mockUuids);
135
+ });
136
+
137
+ it('should callback', () => {
138
+ const callback = sinon.spy();
139
+
140
+ service.discoverCharacteristics(null, callback);
141
+ service.emit('characteristicsDiscover');
142
+
143
+ assert.calledOnceWithExactly(callback, null, undefined);
144
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, null);
145
+ });
146
+
147
+ it('should callback with data', () => {
148
+ const mockCharacteristics = [];
149
+ const callback = sinon.spy();
150
+
151
+ service.discoverCharacteristics(null, callback);
152
+ service.emit('characteristicsDiscover', mockCharacteristics);
153
+
154
+ assert.calledOnceWithExactly(callback, null, mockCharacteristics);
155
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, null);
156
+ });
157
+ });
158
+
159
+ describe('discoverCharacteristicsAsync', () => {
160
+ beforeEach(() => {
161
+ mockNoble.discoverCharacteristics = sinon.spy();
162
+ });
163
+
164
+ afterEach(() => {
165
+ sinon.reset();
166
+ });
167
+
168
+ it('should delegate to noble', async () => {
169
+ const promise = service.discoverCharacteristicsAsync();
170
+ service.emit('characteristicsDiscover');
171
+
172
+ should(promise).resolvedWith(undefined);
173
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, undefined);
174
+ });
175
+
176
+ it('should delegate to noble, with uuids', async () => {
177
+ const mockUuids = [];
178
+ const promise = service.discoverCharacteristicsAsync(mockUuids);
179
+ service.emit('characteristicsDiscover');
180
+
181
+ should(promise).resolvedWith(undefined);
182
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, mockUuids);
183
+ });
184
+
185
+ it('should resolve with data', async () => {
186
+ const mockCharacteristics = [];
187
+
188
+ const promise = service.discoverCharacteristicsAsync();
189
+ service.emit('characteristicsDiscover', mockCharacteristics);
190
+
191
+ should(promise).resolvedWith(mockCharacteristics);
192
+ assert.calledOnceWithExactly(mockNoble.discoverCharacteristics, mockPeripheralId, mockUuid, undefined);
193
+ });
194
+ });
195
+ });
@@ -0,0 +1,190 @@
1
+ const sinon = require('sinon');
2
+ const should = require('should');
3
+
4
+ const { assert } = sinon;
5
+
6
+ const Bindings = require('../../../lib/webbluetooth/bindings');
7
+
8
+ describe('webbluetooth bindings', () => {
9
+ let bindings;
10
+ let clock;
11
+
12
+ beforeEach(() => {
13
+ clock = sinon.useFakeTimers();
14
+
15
+ bindings = new Bindings();
16
+ });
17
+
18
+ afterEach(() => {
19
+ clock.restore();
20
+ sinon.reset();
21
+ });
22
+
23
+ it('constructor', () => {
24
+ should(bindings._ble).equal(null);
25
+ should(bindings._startScanCommand).equal(null);
26
+ should(bindings._peripherals).deepEqual({});
27
+ });
28
+
29
+ describe('init', () => {
30
+ it('should use ble arg', () => {
31
+ const errorCallback = sinon.spy();
32
+
33
+ bindings.on('error', errorCallback);
34
+ bindings.init({});
35
+
36
+ clock.tick(1);
37
+
38
+ assert.notCalled(errorCallback);
39
+ });
40
+ });
41
+
42
+ it('onClose - should emit stateChange', () => {
43
+ const callback = sinon.spy();
44
+
45
+ bindings.on('stateChange', callback);
46
+ bindings.onClose();
47
+
48
+ assert.calledOnceWithExactly(callback, 'poweredOff');
49
+ });
50
+
51
+ describe('startScanning', () => {
52
+ let scanStopCallback;
53
+ let discoverCallback;
54
+ let errorCallback;
55
+ let scanStartCallback;
56
+
57
+ let device;
58
+
59
+ beforeEach(() => {
60
+ device = {
61
+ id: 'id',
62
+ name: 'name',
63
+ services: ['1234', 'service9']
64
+ };
65
+
66
+ scanStopCallback = sinon.spy();
67
+ discoverCallback = sinon.spy();
68
+ errorCallback = sinon.spy();
69
+ scanStartCallback = sinon.spy();
70
+
71
+ bindings._ble = {
72
+ requestDevice: sinon.fake.resolves(device)
73
+ };
74
+
75
+ bindings.on('scanStop', scanStopCallback);
76
+ bindings.on('discover', discoverCallback);
77
+ bindings.on('error', errorCallback);
78
+ bindings.on('scanStart', scanStartCallback);
79
+ });
80
+
81
+ it('should emit discover with object options', async () => {
82
+ const options = { services: ['1234', '0x5678', 'service'] };
83
+ const allowDuplicates = true;
84
+
85
+ bindings.startScanning(options, allowDuplicates);
86
+
87
+ await clock.tickAsync(210);
88
+
89
+ assert.calledOnceWithExactly(bindings._ble.requestDevice, { filters: [{ services: [4660] }, { services: [22136] }, { services: ['service'] }] });
90
+ assert.calledOnceWithExactly(scanStopCallback, {});
91
+ assert.calledOnceWithExactly(discoverCallback, device.id, device.id, device.addressType, !device.paired, { localName: device.name }, undefined);
92
+ assert.notCalled(errorCallback);
93
+ assert.calledOnceWithExactly(scanStartCallback);
94
+
95
+ should(bindings._peripherals).deepEqual({
96
+ [device.id]: {
97
+ uuid: device.id,
98
+ address: device.id,
99
+ advertisement: { localName: device.name }, // advertisement,
100
+ device: device,
101
+ cachedServices: {},
102
+ localName: device.name,
103
+ serviceUuids: options.services
104
+ }
105
+ });
106
+ });
107
+
108
+ it('should emit discover with array options', async () => {
109
+ const options = ['1234', '0x5678', 'service'];
110
+ const allowDuplicates = false;
111
+
112
+ device.adData = {
113
+ rssi: 33
114
+ };
115
+
116
+ bindings.startScanning(options, allowDuplicates);
117
+
118
+ await clock.tickAsync(210);
119
+
120
+ assert.calledOnceWithExactly(bindings._ble.requestDevice, { filters: [{ services: [4660] }, { services: [22136] }, { services: ['service'] }] });
121
+ assert.calledOnceWithExactly(scanStopCallback, {});
122
+ assert.calledOnceWithExactly(discoverCallback, device.id, device.id, device.addressType, !device.paired, { localName: device.name }, 33);
123
+ assert.notCalled(errorCallback);
124
+ assert.calledOnceWithExactly(scanStartCallback);
125
+
126
+ should(bindings._peripherals).deepEqual({
127
+ [device.id]: {
128
+ uuid: device.id,
129
+ address: device.id,
130
+ advertisement: { localName: device.name }, // advertisement,
131
+ device: device,
132
+ cachedServices: {},
133
+ localName: device.name,
134
+ serviceUuids: [4660, 22136, 'service'],
135
+ rssi: 33
136
+ }
137
+ });
138
+ });
139
+
140
+ it('should not emit discover on null device', async () => {
141
+ const options = ['1234', '0x5678', 'service'];
142
+ const allowDuplicates = false;
143
+
144
+ bindings._ble.requestDevice = sinon.fake.resolves(null);
145
+
146
+ bindings.startScanning(options, allowDuplicates);
147
+
148
+ await clock.tickAsync(210);
149
+
150
+ assert.calledOnceWithExactly(bindings._ble.requestDevice, { filters: [{ services: [4660] }, { services: [22136] }, { services: ['service'] }] });
151
+ assert.calledOnceWithExactly(scanStopCallback, {});
152
+ assert.notCalled(discoverCallback);
153
+ assert.notCalled(errorCallback);
154
+ assert.calledOnceWithExactly(scanStartCallback);
155
+
156
+ should(bindings._peripherals).deepEqual({});
157
+ });
158
+
159
+ it('should emit error', async () => {
160
+ const options = ['1234', '0x5678', 'service'];
161
+ const allowDuplicates = false;
162
+
163
+ bindings._ble.requestDevice = sinon.fake.rejects(new Error('err'));
164
+
165
+ bindings.startScanning(options, allowDuplicates);
166
+
167
+ await clock.tickAsync(210);
168
+
169
+ assert.calledOnceWithExactly(bindings._ble.requestDevice, { filters: [{ services: [4660] }, { services: [22136] }, { services: ['service'] }] });
170
+ assert.calledOnceWithExactly(scanStopCallback, {});
171
+ assert.notCalled(discoverCallback);
172
+ assert.calledOnceWithMatch(errorCallback, sinon.match({ message: 'err' }));
173
+ assert.calledOnceWithExactly(scanStartCallback);
174
+
175
+ should(bindings._peripherals).deepEqual({});
176
+ });
177
+ });
178
+
179
+ it('stopScanning', () => {
180
+ const callback = sinon.spy();
181
+
182
+ bindings._startScanCommand = 'not_null';
183
+ bindings.on('scanStop', callback);
184
+
185
+ bindings.stopScanning();
186
+
187
+ assert.calledOnceWithExactly(callback);
188
+ should(bindings._startScanCommand).equal(null);
189
+ });
190
+ });