@ledgerhq/device-transport-kit-web-hid 1.0.1 → 1.1.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/transport/WebHidTransport.test.ts"],
4
- "sourcesContent": ["import {\n type ApduReceiverServiceFactory,\n type ApduSenderServiceFactory,\n connectedDeviceStubBuilder,\n type DeviceModel,\n DeviceModelId,\n DeviceNotRecognizedError,\n type LoggerPublisherService,\n type LoggerSubscriberService,\n NoAccessibleDeviceError,\n OpeningConnectionError,\n StaticDeviceModelDataSource,\n type TransportDeviceModel,\n type TransportDiscoveredDevice,\n UnknownDeviceError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { Subject } from \"rxjs\";\n\nimport { RECONNECT_DEVICE_TIMEOUT } from \"@api/data/WebHidConfig\";\nimport { WebHidTransportNotSupportedError } from \"@api/model/Errors\";\nimport { hidDeviceStubBuilder } from \"@api/model/HIDDevice.stub\";\n\nimport { WebHidTransport } from \"./WebHidTransport\";\n\nclass LoggerPublisherServiceStub implements LoggerPublisherService {\n constructor(subscribers: LoggerSubscriberService[], tag: string) {\n this.subscribers = subscribers;\n this.tag = tag;\n }\n subscribers: LoggerSubscriberService[] = [];\n tag: string = \"\";\n error = jest.fn();\n warn = jest.fn();\n info = jest.fn();\n debug = jest.fn();\n}\n\n// Our StaticDeviceModelDataSource can directly be used in our unit tests\nconst usbDeviceModelDataSource = new StaticDeviceModelDataSource();\nconst logger = new LoggerPublisherServiceStub([], \"web-usb-hid\");\n\nconst stubDevice: HIDDevice = hidDeviceStubBuilder();\n\n/**\n * Flushes all pending promises\n */\nconst flushPromises = () =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n new Promise(jest.requireActual(\"timers\").setImmediate);\n\ndescribe(\"WebHidTransport\", () => {\n let transport: WebHidTransport;\n let apduReceiverServiceFactoryStub: ApduReceiverServiceFactory;\n let apduSenderServiceFactoryStub: ApduSenderServiceFactory;\n\n function initializeTransport() {\n apduReceiverServiceFactoryStub = jest.fn();\n apduSenderServiceFactoryStub = jest.fn();\n transport = new WebHidTransport(\n usbDeviceModelDataSource,\n () => logger,\n apduSenderServiceFactoryStub,\n apduReceiverServiceFactoryStub,\n );\n }\n\n beforeEach(() => {\n initializeTransport();\n jest.useFakeTimers();\n });\n\n afterEach(() => {\n jest.restoreAllMocks();\n });\n\n const discoverDevice = (\n onSuccess: (discoveredDevice: TransportDiscoveredDevice) => void,\n onError?: (error: unknown) => void,\n ) => {\n transport.startDiscovering().subscribe({\n next: onSuccess,\n error: onError,\n });\n };\n\n describe(\"When WebHID API is not supported\", () => {\n it(\"should not support the transport\", () => {\n expect(transport.isSupported()).toBe(false);\n });\n\n it(\"should emit a startDiscovering error\", (done) => {\n discoverDevice(\n () => {\n done(\"Should not emit any value\");\n },\n (error) => {\n expect(error).toBeInstanceOf(WebHidTransportNotSupportedError);\n done();\n },\n );\n });\n });\n\n describe(\"When WebHID API is supported\", () => {\n const mockedGetDevices = jest.fn();\n const mockedRequestDevice = jest.fn();\n\n const connectionEventsSubject = new Subject<HIDConnectionEvent>();\n const disconnectionEventsSubject = new Subject<HIDConnectionEvent>();\n\n function emitHIDConnectionEvent(device: HIDDevice) {\n connectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n function emitHIDDisconnectionEvent(device: HIDDevice) {\n disconnectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n beforeEach(() => {\n global.navigator = {\n hid: {\n getDevices: mockedGetDevices,\n requestDevice: mockedRequestDevice,\n addEventListener: (\n eventName: string,\n callback: (event: HIDConnectionEvent) => void,\n ) => {\n if (eventName === \"disconnect\") {\n disconnectionEventsSubject.subscribe(callback);\n } else if (eventName === \"connect\") {\n connectionEventsSubject.subscribe(callback);\n }\n },\n },\n } as unknown as Navigator;\n initializeTransport();\n });\n\n afterEach(() => {\n jest.clearAllMocks();\n global.navigator = undefined as unknown as Navigator;\n });\n\n it(\"should support the transport\", () => {\n expect(transport.isSupported()).toBe(true);\n });\n\n describe(\"startDiscovering\", () => {\n const testCases = usbDeviceModelDataSource\n .getAllDeviceModels()\n .flatMap((deviceModel) => {\n return [\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName})`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.usbProductId << 8,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName}, bootloader)`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.bootloaderUsbProductId,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n ];\n });\n\n testCases.forEach((testCase) => {\n it(testCase.testTitle, (done) => {\n mockedRequestDevice.mockResolvedValueOnce([testCase.hidDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n try {\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: testCase.expectedDeviceModel,\n }),\n );\n\n done();\n } catch (expectError) {\n done(expectError);\n }\n },\n (error) => {\n done(error);\n },\n );\n });\n });\n\n // It does not seem possible for a user to select several devices on the browser popup.\n // But if it was possible, we should emit them\n it(\"should emit devices if new grant accesses\", (done) => {\n mockedRequestDevice.mockResolvedValueOnce([\n stubDevice,\n {\n ...stubDevice,\n productId: 0x5011,\n productName: \"Ledger Nano S Plus\",\n },\n ]);\n\n let count = 0;\n discoverDevice(\n (discoveredDevice) => {\n try {\n switch (count) {\n case 0:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n productName: \"Ledger Nano X\",\n usbProductId: 0x40,\n }) as DeviceModel,\n }),\n );\n break;\n case 1:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_SP,\n productName: \"Ledger Nano S Plus\",\n usbProductId: 0x50,\n }) as DeviceModel,\n }),\n );\n\n done();\n break;\n }\n\n count++;\n } catch (expectError) {\n done(expectError);\n }\n },\n (error) => {\n done(error);\n },\n );\n });\n\n it(\"should throw DeviceNotRecognizedError if the device is not recognized\", (done) => {\n mockedRequestDevice.mockResolvedValueOnce([\n {\n ...stubDevice,\n productId: 0x4242,\n },\n ]);\n\n discoverDevice(\n () => {\n done(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(DeviceNotRecognizedError);\n done();\n },\n );\n });\n\n it(\"should emit an error if the request device is in error\", (done) => {\n const message = \"request device error\";\n mockedRequestDevice.mockImplementationOnce(() => {\n throw new Error(message);\n });\n\n discoverDevice(\n () => {\n done(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n expect(error).toStrictEqual(\n new NoAccessibleDeviceError(new Error(message)),\n );\n done();\n },\n );\n });\n\n // [ASK] Is this the behavior we want when the user does not select any device ?\n it(\"should emit an error if the user did not grant us access to a device (clicking on cancel on the browser popup for ex)\", (done) => {\n // When the user does not select any device, the `requestDevice` will return an empty array\n mockedRequestDevice.mockResolvedValueOnce([]);\n\n discoverDevice(\n (discoveredDevice) => {\n done(\n `Should not emit any value, but emitted ${JSON.stringify(\n discoveredDevice,\n )}`,\n );\n },\n (error) => {\n try {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n done();\n } catch (expectError) {\n done(expectError);\n }\n },\n );\n });\n\n it(\"should emit the same discoveredDevice object if its discovered twice in a row\", async () => {\n mockedRequestDevice.mockResolvedValue([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const firstDiscoveredDevice = await new Promise((resolve, reject) => {\n discoverDevice(resolve, (err) => reject(err));\n });\n const secondDiscoveredDevice = await new Promise((resolve, reject) => {\n discoverDevice(resolve, (err) => reject(err));\n });\n expect(secondDiscoveredDevice).toBe(firstDiscoveredDevice);\n });\n });\n\n describe(\"destroy\", () => {\n it(\"should stop monitoring connections if the discovery process is halted\", () => {\n const abortSpy = jest.spyOn(AbortController.prototype, \"abort\");\n\n transport.destroy();\n\n expect(abortSpy).toHaveBeenCalled();\n });\n });\n\n describe(\"connect\", () => {\n it(\"should throw UnknownDeviceError if no internal device\", async () => {\n const connectParams = {\n deviceId: \"fake\",\n onDisconnect: jest.fn(),\n };\n\n const connect = await transport.connect(connectParams);\n\n expect(connect).toStrictEqual(\n Left(new UnknownDeviceError(\"Unknown device fake\")),\n );\n });\n\n it(\"should throw OpeningConnectionError if the device is already opened\", async () => {\n const device = {\n deviceId: \"fake\",\n onDisconnect: jest.fn(),\n };\n\n const connect = await transport.connect(device);\n\n expect(connect).toStrictEqual(\n Left(new UnknownDeviceError(\"Unknown device fake\")),\n );\n });\n\n it(\"should throw OpeningConnectionError if the device cannot be opened\", (done) => {\n const message = \"cannot be opened\";\n const mockedDevice = {\n ...stubDevice,\n open: () => {\n throw new Error(message);\n },\n };\n mockedRequestDevice.mockResolvedValueOnce([mockedDevice]);\n mockedGetDevices.mockResolvedValue([mockedDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: jest.fn(),\n })\n .then((value) => {\n expect(value).toStrictEqual(\n Left(new OpeningConnectionError(new Error(message))),\n );\n done();\n })\n .catch((error) => {\n done(error);\n });\n },\n (error) => {\n done(error);\n },\n );\n });\n\n it(\"should return the opened device\", (done) => {\n const mockedDevice = {\n ...stubDevice,\n opened: false,\n open: () => {\n mockedDevice.opened = true;\n return Promise.resolve();\n },\n };\n\n mockedRequestDevice.mockResolvedValue([mockedDevice]);\n mockedGetDevices.mockResolvedValue([mockedDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: jest.fn(),\n })\n .then((connectedDevice) => {\n connectedDevice\n .ifRight((device) => {\n expect(device).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n done();\n })\n .ifLeft(() => {\n done(connectedDevice);\n });\n })\n .catch((error) => {\n done(error);\n });\n },\n (error) => {\n done(error);\n },\n );\n });\n\n it(\"should return a device if available\", (done) => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: jest.fn(),\n })\n .then((connectedDevice) => {\n connectedDevice\n .ifRight((device) => {\n expect(device).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n done();\n })\n .ifLeft(() => {\n done(connectedDevice);\n });\n })\n .catch((error) => {\n done(error);\n });\n },\n (error) => {\n done(error);\n },\n );\n });\n });\n\n describe(\"disconnect\", () => {\n it(\"should throw an error if the device is not connected\", async () => {\n // given\n const connectedDevice = connectedDeviceStubBuilder();\n\n // when\n const disconnect = await transport.disconnect({\n connectedDevice,\n });\n\n expect(disconnect).toStrictEqual(\n Left(new UnknownDeviceError(`Unknown device ${connectedDevice.id}`)),\n );\n });\n\n it(\"should disconnect if the device is connected\", (done) => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: jest.fn(),\n })\n .then((connectedDevice) => {\n connectedDevice\n .ifRight((device) => {\n transport\n .disconnect({ connectedDevice: device })\n .then((value) => {\n expect(value).toStrictEqual(Right(undefined));\n done();\n })\n .catch((error) => {\n done(error);\n });\n })\n .ifLeft(() => {\n done(connectedDevice);\n });\n })\n .catch((error) => {\n done(error);\n });\n },\n (error) => {\n done(error);\n },\n );\n });\n\n it(\"should call disconnect handler if a connected device is unplugged\", (done) => {\n // given\n const onDisconnect = jest.fn();\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n // when\n transport.startDiscovering().subscribe({\n next: (discoveredDevice) => {\n const mock = {\n sendApdu: jest.fn(),\n device: stubDevice,\n deviceId: discoveredDevice.id,\n disconnect: onDisconnect,\n lostConnection: jest.fn().mockImplementation(() => {\n setTimeout(() => {\n mock.disconnect();\n }, RECONNECT_DEVICE_TIMEOUT);\n }),\n };\n\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n })\n .then(async () => {\n emitHIDDisconnectionEvent(stubDevice);\n\n expect(stubDevice.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the stubDevice.close promise is resolved\n expect(onDisconnect).not.toHaveBeenCalled();\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 2);\n expect(onDisconnect).not.toHaveBeenCalled();\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 2);\n expect(onDisconnect).toHaveBeenCalled();\n done();\n })\n .catch((error) => {\n done(error);\n });\n },\n });\n });\n });\n\n describe(\"reconnect\", () => {\n it.only(\"should stop disconnection if reconnection happen\", (done) => {\n // given\n const onDisconnect = jest.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n\n discoverDevice(async (discoveredDevice) => {\n const mock = {\n sendApdu: jest.fn(),\n device: hidDevice2,\n deviceId: discoveredDevice.id,\n disconnect: onDisconnect,\n lostConnection: jest.fn().mockImplementation(() => {\n setTimeout(() => {\n mock.disconnect();\n }, RECONNECT_DEVICE_TIMEOUT);\n }),\n };\n\n try {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n\n /* Disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n expect(hidDevice2.open).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n done();\n } catch (error) {\n done(error);\n }\n });\n });\n\n it(\"should be able to reconnect twice in a row if the device is unplugged and replugged twice\", (done) => {\n // given\n const onDisconnect = jest.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n const hidDevice3 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([\n hidDevice1,\n hidDevice2,\n hidDevice3,\n ]);\n\n // when\n discoverDevice(async (discoveredDevice) => {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n try {\n /* First disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* First reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n expect(hidDevice2.open).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n /* Second disconnection */\n emitHIDDisconnectionEvent(hidDevice2);\n expect(hidDevice2.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.close promise is resolved\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Second reconnection */\n emitHIDConnectionEvent(hidDevice3);\n\n expect(hidDevice3.open).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice3.open promise is resolved\n jest.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n done();\n } catch (error) {\n done(error);\n }\n });\n });\n });\n\n describe(\"Connection event typeguard\", () => {\n it(\"should validate type of an HIDConnectionEvent\", () => {\n // given\n const event = {\n device: stubDevice,\n } as HIDConnectionEvent;\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(true);\n });\n it(\"should not validate type of another event\", () => {\n // given\n const event = new Event(\"disconnect\", {});\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(false);\n });\n });\n\n describe(\"listenToKnownDevices\", () => {\n it(\"should emit the devices already connected before listening\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = jest.fn();\n const onError = jest.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToKnownDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should emit the new list of devices after connection and disconnection events\", async () => {\n initializeTransport();\n // given\n const hidDevice1 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({\n id: DeviceModelId.NANO_X,\n }).usbProductId << 8,\n });\n const hidDevice2 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({ id: DeviceModelId.STAX })\n .usbProductId << 8,\n });\n mockedGetDevices.mockResolvedValue([hidDevice1]);\n\n const onComplete = jest.fn();\n const onError = jest.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToKnownDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a new device is connected\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n emitHIDConnectionEvent(hidDevice2);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a device is disconnected\n mockedGetDevices.mockResolvedValue([hidDevice2]);\n emitHIDDisconnectionEvent(hidDevice1);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should preserve DeviceId in case the device has been disconnected and reconnected before the timeout\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = jest.fn();\n const onError = jest.fn();\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToKnownDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n const firstObservedDeviceId = observedDevices[0]?.id;\n expect(firstObservedDeviceId).toBeTruthy();\n expect(observedDevices[0]?.deviceModel?.id).toBe(DeviceModelId.NANO_X);\n\n // Start a connection with the device\n await transport.connect({\n deviceId: observedDevices[0]!.id,\n onDisconnect: jest.fn(),\n });\n await flushPromises();\n\n // When the device is disconnected\n mockedGetDevices.mockResolvedValue([]);\n emitHIDDisconnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([]);\n\n // When the device is reconnected\n mockedGetDevices.mockResolvedValue([hidDevice]);\n emitHIDConnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(observedDevices[0]?.id).toBeTruthy();\n expect(observedDevices[0]?.id).toBe(firstObservedDeviceId);\n });\n });\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["connectedDeviceStubBuilder", "DeviceModelId", "DeviceNotRecognizedError", "NoAccessibleDeviceError", "OpeningConnectionError", "StaticDeviceModelDataSource", "UnknownDeviceError", "Left", "Right", "Subject", "RECONNECT_DEVICE_TIMEOUT", "WebHidTransportNotSupportedError", "hidDeviceStubBuilder", "WebHidTransport", "LoggerPublisherServiceStub", "subscribers", "tag", "usbDeviceModelDataSource", "logger", "stubDevice", "flushPromises", "transport", "apduReceiverServiceFactoryStub", "apduSenderServiceFactoryStub", "initializeTransport", "discoverDevice", "onSuccess", "onError", "done", "error", "mockedGetDevices", "mockedRequestDevice", "connectionEventsSubject", "disconnectionEventsSubject", "emitHIDConnectionEvent", "device", "emitHIDDisconnectionEvent", "eventName", "callback", "deviceModel", "testCase", "discoveredDevice", "expectError", "count", "message", "firstDiscoveredDevice", "resolve", "reject", "err", "secondDiscoveredDevice", "abortSpy", "connectParams", "connect", "mockedDevice", "value", "connectedDevice", "disconnect", "onDisconnect", "mock", "hidDevice1", "hidDevice2", "hidDevice3", "event", "result", "hidDevice", "onComplete", "observedDevices", "knownDevices", "firstObservedDeviceId"]
4
+ "sourcesContent": ["/* eslint @typescript-eslint/consistent-type-imports: off */\nimport {\n type ApduReceiverServiceFactory,\n type ApduSenderServiceFactory,\n connectedDeviceStubBuilder,\n type DeviceModel,\n DeviceModelId,\n DeviceNotRecognizedError,\n type LoggerPublisherService,\n type LoggerSubscriberService,\n NoAccessibleDeviceError,\n OpeningConnectionError,\n StaticDeviceModelDataSource,\n type TransportDeviceModel,\n type TransportDiscoveredDevice,\n UnknownDeviceError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { Subject } from \"rxjs\";\n\nimport { RECONNECT_DEVICE_TIMEOUT } from \"@api/data/WebHidConfig\";\nimport { WebHidTransportNotSupportedError } from \"@api/model/Errors\";\nimport { hidDeviceStubBuilder } from \"@api/model/HIDDevice.stub\";\n\nimport { WebHidTransport } from \"./WebHidTransport\";\n\nclass LoggerPublisherServiceStub implements LoggerPublisherService {\n constructor(subscribers: LoggerSubscriberService[], tag: string) {\n this.subscribers = subscribers;\n this.tag = tag;\n }\n subscribers: LoggerSubscriberService[] = [];\n tag: string = \"\";\n error = vi.fn();\n warn = vi.fn();\n info = vi.fn();\n debug = vi.fn();\n}\n\n// Our StaticDeviceModelDataSource can directly be used in our unit tests\nconst usbDeviceModelDataSource = new StaticDeviceModelDataSource();\nconst logger = new LoggerPublisherServiceStub([], \"web-usb-hid\");\n\nconst stubDevice: HIDDevice = hidDeviceStubBuilder();\n\n/**\n * Flushes all pending promises\n */\nconst flushPromises = async () => {\n const timers = await vi.importActual<typeof import(\"timers\")>(\"timers\");\n return new Promise(timers.setImmediate);\n};\n\ndescribe(\"WebHidTransport\", () => {\n let transport: WebHidTransport;\n let apduReceiverServiceFactoryStub: ApduReceiverServiceFactory;\n let apduSenderServiceFactoryStub: ApduSenderServiceFactory;\n\n function initializeTransport() {\n apduReceiverServiceFactoryStub = vi.fn();\n apduSenderServiceFactoryStub = vi.fn();\n transport = new WebHidTransport(\n usbDeviceModelDataSource,\n () => logger,\n apduSenderServiceFactoryStub,\n apduReceiverServiceFactoryStub,\n );\n }\n\n beforeEach(() => {\n initializeTransport();\n vi.useFakeTimers();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n const discoverDevice = (\n onSuccess: (discoveredDevice: TransportDiscoveredDevice) => void,\n onError?: (error: unknown) => void,\n ) => {\n transport.startDiscovering().subscribe({\n next: onSuccess,\n error: onError,\n });\n };\n\n describe(\"When WebHID API is not supported\", () => {\n it(\"should not support the transport\", () => {\n expect(transport.isSupported()).toBe(false);\n });\n\n it(\"should emit a startDiscovering error\", () =>\n new Promise<void>((resolve, reject) => {\n discoverDevice(\n () => {\n reject(\"Should not emit any value\");\n },\n (error) => {\n expect(error).toBeInstanceOf(WebHidTransportNotSupportedError);\n resolve();\n },\n );\n }));\n });\n\n describe(\"When WebHID API is supported\", () => {\n const mockedGetDevices = vi.fn();\n const mockedRequestDevice = vi.fn();\n\n const connectionEventsSubject = new Subject<HIDConnectionEvent>();\n const disconnectionEventsSubject = new Subject<HIDConnectionEvent>();\n\n function emitHIDConnectionEvent(device: HIDDevice) {\n connectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n function emitHIDDisconnectionEvent(device: HIDDevice) {\n disconnectionEventsSubject.next({\n device,\n } as HIDConnectionEvent);\n }\n\n beforeEach(() => {\n global.navigator = {\n hid: {\n getDevices: mockedGetDevices,\n requestDevice: mockedRequestDevice,\n addEventListener: (\n eventName: string,\n callback: (event: HIDConnectionEvent) => void,\n ) => {\n if (eventName === \"disconnect\") {\n disconnectionEventsSubject.subscribe(callback);\n } else if (eventName === \"connect\") {\n connectionEventsSubject.subscribe(callback);\n }\n },\n },\n } as unknown as Navigator;\n initializeTransport();\n });\n\n afterEach(() => {\n vi.clearAllMocks();\n global.navigator = undefined as unknown as Navigator;\n });\n\n it(\"should support the transport\", () => {\n expect(transport.isSupported()).toBe(true);\n });\n\n describe(\"startDiscovering\", () => {\n const testCases = usbDeviceModelDataSource\n .getAllDeviceModels()\n .flatMap((deviceModel) => {\n return [\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName})`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.usbProductId << 8,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n {\n testTitle: `should emit device if user grants access through hid.requestDevice (${deviceModel.productName}, bootloader)`,\n hidDevice: hidDeviceStubBuilder({\n productId: deviceModel.bootloaderUsbProductId,\n productName: deviceModel.productName,\n }),\n expectedDeviceModel: deviceModel,\n },\n ];\n });\n\n testCases.forEach((testCase) => {\n it(\n testCase.testTitle,\n () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([testCase.hidDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n try {\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: testCase.expectedDeviceModel,\n }),\n );\n\n resolve();\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n (error) => {\n reject(error as Error);\n },\n );\n }),\n );\n });\n\n // It does not seem possible for a user to select several devices on the browser popup.\n // But if it was possible, we should emit them\n it(\"should emit devices if new grant accesses\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([\n stubDevice,\n {\n ...stubDevice,\n productId: 0x5011,\n productName: \"Ledger Nano S Plus\",\n },\n ]);\n\n let count = 0;\n discoverDevice(\n (discoveredDevice) => {\n try {\n switch (count) {\n case 0:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n productName: \"Ledger Nano X\",\n usbProductId: 0x40,\n }) as DeviceModel,\n }),\n );\n break;\n case 1:\n expect(discoveredDevice).toEqual(\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_SP,\n productName: \"Ledger Nano S Plus\",\n usbProductId: 0x50,\n }) as DeviceModel,\n }),\n );\n\n resolve();\n break;\n }\n\n count++;\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n\n it(\"should throw DeviceNotRecognizedError if the device is not recognized\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([\n {\n ...stubDevice,\n productId: 0x4242,\n },\n ]);\n\n discoverDevice(\n () => {\n reject(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(DeviceNotRecognizedError);\n resolve();\n },\n );\n }));\n\n it(\"should emit an error if the request device is in error\", () =>\n new Promise<void>((resolve, reject) => {\n const message = \"request device error\";\n mockedRequestDevice.mockImplementationOnce(() => {\n throw new Error(message);\n });\n\n discoverDevice(\n () => {\n reject(\"should not return a device\");\n },\n (error) => {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n expect(error).toStrictEqual(\n new NoAccessibleDeviceError(new Error(message)),\n );\n resolve();\n },\n );\n }));\n\n // [ASK] Is this the behavior we want when the user does not select any device ?\n it(\"should emit an error if the user did not grant us access to a device (clicking on cancel on the browser popup for ex)\", () =>\n new Promise<void>((resolve, reject) => {\n // When the user does not select any device, the `requestDevice` will return an empty array\n mockedRequestDevice.mockResolvedValueOnce([]);\n\n discoverDevice(\n (discoveredDevice) => {\n reject(\n `Should not emit any value, but emitted ${JSON.stringify(\n discoveredDevice,\n )}`,\n );\n },\n (error) => {\n try {\n expect(error).toBeInstanceOf(NoAccessibleDeviceError);\n resolve();\n } catch (expectError) {\n reject(expectError as Error);\n }\n },\n );\n }));\n\n it(\"should emit the same discoveredDevice object if its discovered twice in a row\", async () => {\n mockedRequestDevice.mockResolvedValue([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n const firstDiscoveredDevice = await new Promise<void>(\n (resolve, reject) => {\n discoverDevice(\n () => resolve(),\n (err) => reject(err),\n );\n },\n );\n const secondDiscoveredDevice = await new Promise<void>(\n (resolve, reject) => {\n discoverDevice(\n () => resolve(),\n (err) => reject(err),\n );\n },\n );\n expect(secondDiscoveredDevice).toBe(firstDiscoveredDevice);\n });\n });\n\n describe(\"destroy\", () => {\n it(\"should stop monitoring connections if the discovery process is halted\", () => {\n const abortSpy = vi.spyOn(AbortController.prototype, \"abort\");\n\n transport.destroy();\n\n expect(abortSpy).toHaveBeenCalled();\n });\n });\n\n describe(\"connect\", () => {\n it(\"should throw UnknownDeviceError if no internal device\", async () => {\n const connectParams = {\n deviceId: \"fake\",\n onDisconnect: vi.fn(),\n };\n\n const connect = await transport.connect(connectParams);\n\n expect(connect).toStrictEqual(\n Left(new UnknownDeviceError(\"Unknown device fake\")),\n );\n });\n\n it(\"should throw OpeningConnectionError if the device is already opened\", async () => {\n const device = {\n deviceId: \"fake\",\n onDisconnect: vi.fn(),\n };\n\n const connect = await transport.connect(device);\n\n expect(connect).toStrictEqual(\n Left(new UnknownDeviceError(\"Unknown device fake\")),\n );\n });\n\n it(\"should throw OpeningConnectionError if the device cannot be opened\", () =>\n new Promise<void>((resolve, reject) => {\n const message = \"cannot be opened\";\n const mockedDevice = {\n ...stubDevice,\n open: () => {\n throw new Error(message);\n },\n };\n mockedRequestDevice.mockResolvedValueOnce([mockedDevice]);\n mockedGetDevices.mockResolvedValue([mockedDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n })\n .then((value) => {\n expect(value).toStrictEqual(\n Left(new OpeningConnectionError(new Error(message))),\n );\n resolve();\n })\n .catch((error) => {\n reject(error);\n });\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n\n it(\"should return the opened device\", () =>\n new Promise<void>((resolve, reject) => {\n const mockedDevice = {\n ...stubDevice,\n opened: false,\n open: () => {\n mockedDevice.opened = true;\n return Promise.resolve();\n },\n };\n\n mockedRequestDevice.mockResolvedValue([mockedDevice]);\n mockedGetDevices.mockResolvedValue([mockedDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n })\n .then((connectedDevice) => {\n connectedDevice\n .ifRight((device) => {\n expect(device).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n resolve();\n })\n .ifLeft(() => {\n reject(connectedDevice);\n });\n })\n .catch((error) => {\n reject(error);\n });\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n\n it(\"should return a device if available\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n })\n .then((connectedDevice) => {\n connectedDevice\n .ifRight((device) => {\n expect(device).toEqual(\n expect.objectContaining({ id: discoveredDevice.id }),\n );\n resolve();\n })\n .ifLeft(() => {\n reject(connectedDevice);\n });\n })\n .catch((error) => {\n reject(error);\n });\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n });\n\n describe(\"disconnect\", () => {\n it(\"should throw an error if the device is not connected\", async () => {\n // given\n const connectedDevice = connectedDeviceStubBuilder();\n\n // when\n const disconnect = await transport.disconnect({\n connectedDevice,\n });\n\n expect(disconnect).toStrictEqual(\n Left(new UnknownDeviceError(`Unknown device ${connectedDevice.id}`)),\n );\n });\n\n it(\"should disconnect if the device is connected\", () =>\n new Promise<void>((resolve, reject) => {\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n discoverDevice(\n (discoveredDevice) => {\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect: vi.fn(),\n })\n .then((connectedDevice) => {\n connectedDevice\n .ifRight((device) => {\n transport\n .disconnect({ connectedDevice: device })\n .then((value) => {\n expect(value).toStrictEqual(Right(undefined));\n resolve();\n })\n .catch((error) => {\n reject(error);\n });\n })\n .ifLeft(() => {\n reject(connectedDevice);\n });\n })\n .catch((error) => {\n reject(error);\n });\n },\n (error) => {\n reject(error as Error);\n },\n );\n }));\n\n it(\"should call disconnect handler if a connected device is unplugged\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n mockedRequestDevice.mockResolvedValueOnce([stubDevice]);\n mockedGetDevices.mockResolvedValue([stubDevice]);\n\n // when\n transport.startDiscovering().subscribe({\n next: (discoveredDevice) => {\n const mock = {\n sendApdu: vi.fn(),\n device: stubDevice,\n deviceId: discoveredDevice.id,\n disconnect: onDisconnect,\n lostConnection: vi.fn().mockImplementation(() => {\n setTimeout(() => {\n mock.disconnect();\n }, RECONNECT_DEVICE_TIMEOUT);\n }),\n };\n\n transport\n .connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n })\n .then(async () => {\n emitHIDDisconnectionEvent(stubDevice);\n\n expect(stubDevice.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the stubDevice.close promise is resolved\n expect(onDisconnect).not.toHaveBeenCalled();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 2);\n expect(onDisconnect).not.toHaveBeenCalled();\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 2);\n expect(onDisconnect).toHaveBeenCalled();\n resolve();\n })\n .catch((error) => {\n reject(error);\n });\n },\n });\n }));\n });\n\n describe(\"reconnect\", () => {\n it(\"should stop disconnection if reconnection happen\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n\n discoverDevice(async (discoveredDevice) => {\n const mock = {\n sendApdu: vi.fn(),\n device: hidDevice2,\n deviceId: discoveredDevice.id,\n disconnect: onDisconnect,\n lostConnection: vi.fn().mockImplementation(() => {\n setTimeout(() => {\n mock.disconnect();\n }, RECONNECT_DEVICE_TIMEOUT);\n }),\n };\n\n try {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n\n /* Disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n expect(hidDevice2.open).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n resolve();\n } catch (error) {\n reject(error as Error);\n }\n });\n }));\n\n it(\"should be able to reconnect twice in a row if the device is unplugged and replugged twice\", () =>\n new Promise<void>((resolve, reject) => {\n // given\n const onDisconnect = vi.fn();\n\n const hidDevice1 = hidDeviceStubBuilder();\n const hidDevice2 = hidDeviceStubBuilder();\n const hidDevice3 = hidDeviceStubBuilder();\n\n mockedRequestDevice.mockResolvedValueOnce([hidDevice1]);\n mockedGetDevices.mockResolvedValue([\n hidDevice1,\n hidDevice2,\n hidDevice3,\n ]);\n\n // when\n discoverDevice(async (discoveredDevice) => {\n await transport.connect({\n deviceId: discoveredDevice.id,\n onDisconnect,\n });\n try {\n /* First disconnection */\n emitHIDDisconnectionEvent(hidDevice1);\n expect(hidDevice1.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice1.close promise is resolved\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* First reconnection */\n emitHIDConnectionEvent(hidDevice2);\n\n expect(hidDevice2.open).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.open promise is resolved\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n /* Second disconnection */\n emitHIDDisconnectionEvent(hidDevice2);\n expect(hidDevice2.close).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice2.close promise is resolved\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT / 3);\n\n /* Second reconnection */\n emitHIDConnectionEvent(hidDevice3);\n\n expect(hidDevice3.open).toHaveBeenCalled();\n await Promise.resolve(); // wait for the next tick so the hidDevice3.open promise is resolved\n vi.advanceTimersByTime(RECONNECT_DEVICE_TIMEOUT);\n expect(onDisconnect).not.toHaveBeenCalled();\n\n resolve();\n } catch (error) {\n reject(error as Error);\n }\n });\n }));\n });\n\n describe(\"Connection event typeguard\", () => {\n it(\"should validate type of an HIDConnectionEvent\", () => {\n // given\n const event = {\n device: stubDevice,\n } as HIDConnectionEvent;\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(true);\n });\n\n it(\"should not validate type of another event\", () => {\n // given\n const event = new Event(\"disconnect\", {});\n // when\n // @ts-expect-error trying to access private member\n const result = transport.isHIDConnectionEvent(event);\n // then\n expect(result).toBe(false);\n });\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"should emit the devices already connected before listening\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should emit the new list of devices after connection and disconnection events\", async () => {\n initializeTransport();\n // given\n const hidDevice1 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({\n id: DeviceModelId.NANO_X,\n }).usbProductId << 8,\n });\n const hidDevice2 = hidDeviceStubBuilder({\n productId:\n usbDeviceModelDataSource.getDeviceModel({ id: DeviceModelId.STAX })\n .usbProductId << 8,\n });\n mockedGetDevices.mockResolvedValue([hidDevice1]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a new device is connected\n mockedGetDevices.mockResolvedValue([hidDevice1, hidDevice2]);\n emitHIDConnectionEvent(hidDevice2);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n // When a device is disconnected\n mockedGetDevices.mockResolvedValue([hidDevice2]);\n emitHIDDisconnectionEvent(hidDevice1);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.STAX,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(onComplete).not.toHaveBeenCalled();\n expect(onError).not.toHaveBeenCalled();\n });\n\n it(\"should preserve DeviceId in case the device has been disconnected and reconnected before the timeout\", async () => {\n // given\n const hidDevice = hidDeviceStubBuilder();\n\n mockedGetDevices.mockResolvedValue([hidDevice]);\n\n const onComplete = vi.fn();\n const onError = vi.fn();\n let observedDevices: TransportDiscoveredDevice[] = [];\n // when\n transport.listenToAvailableDevices().subscribe({\n next: (knownDevices) => {\n observedDevices = knownDevices;\n },\n complete: onComplete,\n error: onError,\n });\n\n await flushPromises();\n\n const firstObservedDeviceId = observedDevices[0]?.id;\n expect(firstObservedDeviceId).toBeTruthy();\n expect(observedDevices[0]?.deviceModel?.id).toBe(DeviceModelId.NANO_X);\n\n // Start a connection with the device\n await transport.connect({\n deviceId: observedDevices[0]!.id,\n onDisconnect: vi.fn(),\n });\n await flushPromises();\n\n // When the device is disconnected\n mockedGetDevices.mockResolvedValue([]);\n emitHIDDisconnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([]);\n\n // When the device is reconnected\n mockedGetDevices.mockResolvedValue([hidDevice]);\n emitHIDConnectionEvent(hidDevice);\n await flushPromises();\n\n expect(observedDevices).toEqual([\n expect.objectContaining({\n deviceModel: expect.objectContaining({\n id: DeviceModelId.NANO_X,\n }) as TransportDeviceModel,\n }),\n ]);\n\n expect(observedDevices[0]?.id).toBeTruthy();\n expect(observedDevices[0]?.id).toBe(firstObservedDeviceId);\n });\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["connectedDeviceStubBuilder", "DeviceModelId", "DeviceNotRecognizedError", "NoAccessibleDeviceError", "OpeningConnectionError", "StaticDeviceModelDataSource", "UnknownDeviceError", "Left", "Right", "Subject", "RECONNECT_DEVICE_TIMEOUT", "WebHidTransportNotSupportedError", "hidDeviceStubBuilder", "WebHidTransport", "LoggerPublisherServiceStub", "subscribers", "tag", "usbDeviceModelDataSource", "logger", "stubDevice", "flushPromises", "timers", "transport", "apduReceiverServiceFactoryStub", "apduSenderServiceFactoryStub", "initializeTransport", "discoverDevice", "onSuccess", "onError", "resolve", "reject", "error", "mockedGetDevices", "mockedRequestDevice", "connectionEventsSubject", "disconnectionEventsSubject", "emitHIDConnectionEvent", "device", "emitHIDDisconnectionEvent", "eventName", "callback", "deviceModel", "testCase", "discoveredDevice", "expectError", "count", "message", "firstDiscoveredDevice", "err", "secondDiscoveredDevice", "abortSpy", "connectParams", "connect", "mockedDevice", "value", "connectedDevice", "disconnect", "onDisconnect", "mock", "hidDevice1", "hidDevice2", "hidDevice3", "event", "result", "hidDevice", "onComplete", "observedDevices", "knownDevices", "firstObservedDeviceId"]
7
7
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/device-transport-kit-web-hid",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "private": false,
6
6
  "exports": {
@@ -25,9 +25,9 @@
25
25
  "prettier": "prettier . --check",
26
26
  "prettier:fix": "prettier . --write",
27
27
  "typecheck": "tsc --noEmit",
28
- "test": "jest",
29
- "test:watch": "pnpm test -- --watch",
30
- "test:coverage": "pnpm test -- --coverage"
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "test:coverage": "vitest run --coverage"
31
31
  },
32
32
  "dependencies": {
33
33
  "@sentry/minimal": "^6.19.7",
@@ -38,16 +38,16 @@
38
38
  "@ledgerhq/device-management-kit": "workspace:*",
39
39
  "@ledgerhq/esbuild-tools": "workspace:*",
40
40
  "@ledgerhq/eslint-config-dsdk": "workspace:*",
41
- "@ledgerhq/jest-config-dsdk": "workspace:*",
42
41
  "@ledgerhq/prettier-config-dsdk": "workspace:*",
43
42
  "@ledgerhq/tsconfig-dsdk": "workspace:*",
43
+ "@ledgerhq/vitest-config-dmk": "workspace:*",
44
44
  "@types/uuid": "^10.0.0",
45
45
  "@types/w3c-web-hid": "^1.0.6",
46
- "rxjs": "^7.8.1",
46
+ "rxjs": "^7.8.2",
47
47
  "ts-node": "^10.9.2"
48
48
  },
49
49
  "peerDependencies": {
50
- "@ledgerhq/device-management-kit": ">= 0.6 < 2",
51
- "rxjs": "^7.8.1"
50
+ "@ledgerhq/device-management-kit": ">=0.6.2",
51
+ "rxjs": "^7.8.2"
52
52
  }
53
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WebHidDeviceConnection.stub.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebHidDeviceConnection.stub.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,iCAAiC,CAAC;AAEzC,qBAAa,0BAA2B,YAAW,gBAAgB;IACjE,QAAQ,EAAE,cAAc,CAAa;CACtC"}
1
+ {"version":3,"file":"WebHidDeviceConnection.stub.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebHidDeviceConnection.stub.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,iCAAiC,CAAC;AAEzC,qBAAa,0BAA2B,YAAW,gBAAgB;IACjE,QAAQ,EAAE,cAAc,CAAW;CACpC"}
@@ -42,7 +42,7 @@ export declare class WebHidTransport implements Transport {
42
42
  /**
43
43
  * Listen to known devices (devices to which the user has granted access)
44
44
  */
45
- listenToKnownDevices(): Observable<TransportDiscoveredDevice[]>;
45
+ listenToAvailableDevices(): Observable<TransportDiscoveredDevice[]>;
46
46
  private updateTransportDiscoveredDevices;
47
47
  /**
48
48
  * Wrapper around navigator.hid.requestDevice()
@@ -1 +1 @@
1
- {"version":3,"file":"WebHidTransport.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebHidTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAEjB,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAE1B,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EAGb,KAAK,sBAAsB,EAG3B,KAAK,SAAS,EACd,wBAAwB,EAExB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAEzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,KAAK,MAAM,EAAmC,MAAM,WAAW,CAAC;AACzE,OAAO,EAA8B,KAAK,UAAU,EAAa,MAAM,MAAM,CAAC;AAe9E,eAAO,MAAM,gBAAgB,EAAE,mBAA+B,CAAC;AAE/D,qBAAa,eAAgB,YAAW,SAAS;IA2B7C,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAGtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IA/BvC,oDAAoD;IACpD,OAAO,CAAC,2BAA2B,CAEiC;IAEpE,mEAAmE;IACnE,OAAO,CAAC,6BAA6B,CAGvB;IAEd;;;OAGG;IACH,OAAO,CAAC,qCAAqC,CACjC;IAEZ,iEAAiE;IACjE,OAAO,CAAC,mCAAmC,CACnB;IACxB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyC;gBAGjD,sBAAsB,EAAE,qBAAqB,EAC7C,qBAAqB,EAAE,CACtC,GAAG,EAAE,MAAM,KACR,sBAAsB,EACV,kBAAkB,EAAE,wBAAwB,EAC5C,oBAAoB,EAAE,0BAA0B;IAOnE;;;OAGG;IACH,OAAO,KAAK,MAAM,GAMjB;IAED,WAAW;IAWX,aAAa,IAAI,mBAAmB;IAIpC;;;;OAIG;YACW,UAAU;IAmBxB;;OAEG;IACH,OAAO,CAAC,uCAAuC;IA4C/C;;OAEG;IACI,oBAAoB,IAAI,UAAU,CAAC,yBAAyB,EAAE,CAAC;YAOxD,gCAAgC;IAoB9C;;;OAGG;YACW,kBAAkB;IA+ChC,gBAAgB,IAAI,UAAU,CAAC,yBAAyB,CAAC;IA2BzD,eAAe,IAAI,IAAI;IAOvB,OAAO,CAAC,gCAAgC;IAkBxC,OAAO,CAAC,+BAA+B;IAKvC;;OAEG;IACG,OAAO,CAAC,EACZ,QAAQ,EACR,YAAY,GACb,EAAE;QACD,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,EAAE,iBAAiB,CAAC;KACjC,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;IA4E3D,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE;QACvB,eAAe,EAAE,wBAAwB,CAAC;KAC3C,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAyBnC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;OAGG;YACW,8BAA8B;IA+B5C,OAAO,CAAC,wBAAwB;IAiBhC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA8B5B,OAAO;CAOf;AAED,eAAO,MAAM,sBAAsB,EAAE,gBAWlC,CAAC"}
1
+ {"version":3,"file":"WebHidTransport.d.ts","sourceRoot":"","sources":["../../../../src/api/transport/WebHidTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAEjB,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAE1B,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EAGb,KAAK,sBAAsB,EAG3B,KAAK,SAAS,EACd,wBAAwB,EAExB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAEzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,KAAK,MAAM,EAAmC,MAAM,WAAW,CAAC;AACzE,OAAO,EAA8B,KAAK,UAAU,EAAa,MAAM,MAAM,CAAC;AAe9E,eAAO,MAAM,gBAAgB,EAAE,mBAA+B,CAAC;AAE/D,qBAAa,eAAgB,YAAW,SAAS;IA2B7C,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAGtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IA/BvC,oDAAoD;IACpD,OAAO,CAAC,2BAA2B,CAEiC;IAEpE,mEAAmE;IACnE,OAAO,CAAC,6BAA6B,CAGvB;IAEd;;;OAGG;IACH,OAAO,CAAC,qCAAqC,CACjC;IAEZ,iEAAiE;IACjE,OAAO,CAAC,mCAAmC,CACnB;IACxB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyC;gBAGjD,sBAAsB,EAAE,qBAAqB,EAC7C,qBAAqB,EAAE,CACtC,GAAG,EAAE,MAAM,KACR,sBAAsB,EACV,kBAAkB,EAAE,wBAAwB,EAC5C,oBAAoB,EAAE,0BAA0B;IAOnE;;;OAGG;IACH,OAAO,KAAK,MAAM,GAMjB;IAED,WAAW;IAWX,aAAa,IAAI,mBAAmB;IAIpC;;;;OAIG;YACW,UAAU;IAmBxB;;OAEG;IACH,OAAO,CAAC,uCAAuC;IA4C/C;;OAEG;IACI,wBAAwB,IAAI,UAAU,CAAC,yBAAyB,EAAE,CAAC;YAO5D,gCAAgC;IAoB9C;;;OAGG;YACW,kBAAkB;IA+ChC,gBAAgB,IAAI,UAAU,CAAC,yBAAyB,CAAC;IA2BzD,eAAe,IAAI,IAAI;IAOvB,OAAO,CAAC,gCAAgC;IAkBxC,OAAO,CAAC,+BAA+B;IAKvC;;OAEG;IACG,OAAO,CAAC,EACZ,QAAQ,EACR,YAAY,GACb,EAAE;QACD,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,EAAE,iBAAiB,CAAC;KACjC,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;IA4E3D,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE;QACvB,eAAe,EAAE,wBAAwB,CAAC;KAC3C,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAyBnC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;OAGG;YACW,8BAA8B;IA+B5C,OAAO,CAAC,wBAAwB;IAiBhC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA8B5B,OAAO;CAOf;AAED,eAAO,MAAM,sBAAsB,EAAE,gBAWlC,CAAC"}