@@ -5,6 +5,12 @@ const proxyquire = require('proxyquire');
55const { getDevices, openDeviceById, openNativeUsbDevice, PollingPolicy } = proxyquire ( '../src/device-base' , {
66 './usb-device-node' : fakeUsb
77} ) ;
8+ // requestDevice() is browser-only, so the node implementation always throws. Stub it out to inspect
9+ // the filters the library passes down to WebUSB.
10+ const requestUsbDeviceStub = sinon . stub ( ) ;
11+ const { requestDevice } = proxyquire ( '../src/device-base' , {
12+ './usb-device-node' : Object . assign ( { } , fakeUsb , { requestUsbDevice : requestUsbDeviceStub } )
13+ } ) ;
814const usbImpl = require ( './usb-device-node' ) ;
915const proto = require ( './usb-protocol' ) ;
1016const error = require ( './error' ) ;
@@ -195,6 +201,65 @@ describe('device-base', () => {
195201 } ) ;
196202 } ) ;
197203
204+ describe ( 'requestDevice()' , ( ) => {
205+ beforeEach ( ( ) => {
206+ requestUsbDeviceStub . reset ( ) ;
207+ } ) ;
208+
209+ it ( 'does not filter by serial number by default' , async ( ) => {
210+ const photon = fakeUsb . addPhoton ( ) ;
211+ requestUsbDeviceStub . resolves ( photon ) ;
212+ const dev = await requestDevice ( ) ;
213+ expect ( dev . usbDevice ) . to . equal ( photon ) ;
214+ const filters = requestUsbDeviceStub . firstCall . args [ 0 ] ;
215+ expect ( filters ) . to . not . be . empty ;
216+ expect ( filters . every ( f => f . serialNumber === undefined ) ) . to . be . true ;
217+ } ) ;
218+
219+ it ( 'filters by serial number when an ID is specified' , async ( ) => {
220+ const photon = fakeUsb . addPhoton ( { id : '111111111111111111111111' } ) ;
221+ requestUsbDeviceStub . resolves ( photon ) ;
222+ const dev = await requestDevice ( { id : '111111111111111111111111' } ) ;
223+ expect ( dev . usbDevice ) . to . equal ( photon ) ;
224+ const filters = requestUsbDeviceStub . firstCall . args [ 0 ] ;
225+ expect ( filters ) . to . not . be . empty ;
226+ expect ( filters . every ( f => f . serialNumber === '111111111111111111111111' ) ) . to . be . true ;
227+ // The ID applies to both the regular and the DFU USB IDs of each platform
228+ expect ( filters ) . to . containSubset ( [ {
229+ serialNumber : '111111111111111111111111' ,
230+ vendorId : photon . vendorId ,
231+ productId : photon . productId
232+ } ] ) ;
233+ } ) ;
234+
235+ it ( 'filters by serial number for the requested device types only' , async ( ) => {
236+ const photon = fakeUsb . addPhoton ( { id : '111111111111111111111111' } ) ;
237+ requestUsbDeviceStub . resolves ( photon ) ;
238+ await requestDevice ( { types : [ 'photon' ] , includeDfu : false , id : '111111111111111111111111' } ) ;
239+ const filters = requestUsbDeviceStub . firstCall . args [ 0 ] ;
240+ expect ( filters ) . to . have . lengthOf ( 1 ) ;
241+ expect ( filters ) . to . containSubset ( [ {
242+ serialNumber : '111111111111111111111111' ,
243+ vendorId : photon . vendorId ,
244+ productId : photon . productId
245+ } ] ) ;
246+ } ) ;
247+
248+ it ( 'does not modify the platform USB IDs' , async ( ) => {
249+ const photon = fakeUsb . addPhoton ( { id : '111111111111111111111111' } ) ;
250+ requestUsbDeviceStub . resolves ( photon ) ;
251+ await requestDevice ( { id : '111111111111111111111111' } ) ;
252+ await requestDevice ( ) ;
253+ const filters = requestUsbDeviceStub . secondCall . args [ 0 ] ;
254+ expect ( filters . every ( f => f . serialNumber === undefined ) ) . to . be . true ;
255+ } ) ;
256+
257+ it ( 'fails if no device type matches the requested types' , async ( ) => {
258+ await expect ( requestDevice ( { types : [ 'nonexistent' ] } ) ) . to . be . rejectedWith ( RangeError ) ;
259+ expect ( requestUsbDeviceStub ) . to . have . not . been . called ;
260+ } ) ;
261+ } ) ;
262+
198263 describe ( 'openNativeUsbDevice()' , ( ) => {
199264 it ( 'opens a native usb device' , async ( ) => {
200265 const fakeNativeDevice = {
0 commit comments