// META: script=/resources/testdriver.js // META: script=/resources/testdriver-vendor.js // META: script=/resources/test-only-api.js // META: script=/webusb/resources/fake-devices.js // META: script=/webusb/resources/usb-helpers.js 'use strict'; usb_test(() => { return navigator.usb.requestDevice({ filters: [] }) .then(device => { assert_unreachable('requestDevice should reject without a user gesture'); }) .catch(error => { assert_equals(error.code, DOMException.SECURITY_ERR); }); }, 'requestDevice rejects when called without a user gesture'); usb_test(() => { return callWithTrustedClick(() => navigator.usb.requestDevice({ filters: [] }) .then(device => { assert_unreachable('requestDevice should reject when no device selected'); }) .catch(error => { assert_equals(error.code, DOMException.NOT_FOUND_ERR); }) ); }, 'requestDevice rejects when no device is chosen'); usb_test(() => { return getFakeDevice().then(({ device, fakeDevice }) => { navigator.usb.test.onrequestdevice = event => { navigator.usb.test.onrequestdevice = undefined; event.respondWith(fakeDevice); }; return callWithTrustedClick(() => { return navigator.usb.requestDevice({ filters: [] }).then(chosenDevice => { assert_equals(chosenDevice, device); }); }); }); }, 'requestDevice returns the device chosen by the user'); usb_test(() => { return getFakeDevice().then(({ device, fakeDevice }) => { navigator.usb.test.onrequestdevice = event => { navigator.usb.test.onrequestdevice = undefined; event.respondWith(fakeDevice); }; return callWithTrustedClick(() => { return navigator.usb.requestDevice({ filters: [] }).then(chosenDevice => { assert_equals(chosenDevice, device); return navigator.usb.getDevices().then(devices => { assert_equals(devices.length, 1); assert_equals(devices[0], chosenDevice); }); }); }); }); }, 'getDevices returns the same object as requestDevice'); usb_test(() => { const expectedFilters = [ { vendorId: 1234, classCode: 0xFF, serialNumber: "123ABC" }, { vendorId: 5678, productId: 0xF00F }, { vendorId: 9012, classCode: 0xFF, subclassCode: 0xEE, protocolCode: 0xDD }, ]; navigator.usb.test.onrequestdevice = event => { navigator.usb.test.onrequestdevice = undefined; assert_equals(event.filters.length, expectedFilters.length); for (var i = 0; i < event.filters.length; ++i) { assert_object_equals(event.filters[i], expectedFilters[i]); } assert_equals(event.exclusionFilters.length, expectedFilters.length); for (var i = 0; i < event.exclusionFilters.length; ++i) { assert_object_equals(event.exclusionFilters[i], expectedFilters[i]); } event.respondWith(null); }; const filters = expectedFilters; const exclusionFilters = expectedFilters; return callWithTrustedClick(() => { return navigator.usb.requestDevice({ filters, exclusionFilters }) .then(device => { assert_unreached( 'requestDevice should reject because no device selected'); }) .catch(error => { assert_equals(error.code, DOMException.NOT_FOUND_ERR); }); }); }, 'filters are sent correctly'); usb_test(async () => { const badFilters = [ { productId: 1234 }, // productId requires vendorId { subclassCode: 5678 }, // subclassCode requires classCode { protocolCode: 9012 }, // protocolCode requires subclassCode ]; const badFilterOptions = ['filters', 'exclusionFilters'].flatMap(key => { return badFilters.map(filter => ({[key]: [filter]})); }); for (const badFilterOption of badFilterOptions) { await callWithTrustedClick(async () => { try { await navigator.usb.requestDevice(badFilterOption); assert_unreached( 'requestDevice should reject because of invalid filters'); } catch (error) { assert_equals(error.name, 'TypeError'); } }); } }, 'requestDevice rejects on invalid filters'); usb_test(() => { return getFakeDevice().then(({ device, fakeDevice }) => { navigator.usb.test.onrequestdevice = event => { event.respondWith(fakeDevice); }; return callWithTrustedClick(() => { let first = navigator.usb.requestDevice({ filters: [] }); let second = navigator.usb.requestDevice({ filters: [] }); return Promise.all([ first.then(chosenDevice => { assert_equals(chosenDevice, device); }), second.then(chosenDevice => { assert_equals(chosenDevice, device); }) ]); }); }); }, 'multiple requestDevice calls are allowed per user activation');