@onekeyfe/hd-core 1.2.0-alpha.23 → 1.2.0-alpha.24

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 (131) hide show
  1. package/__tests__/DeviceCommands.test.ts +35 -0
  2. package/__tests__/connectSettings.test.ts +5 -47
  3. package/__tests__/device-lifecycle-events.test.ts +59 -0
  4. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +30 -39
  5. package/__tests__/open-wallet-session.test.ts +192 -129
  6. package/__tests__/protocol-v2-ping.test.ts +28 -0
  7. package/__tests__/protocol-v2.test.ts +338 -376
  8. package/__tests__/public-pro2-api-boundary.test.ts +22 -0
  9. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  10. package/dist/api/FirmwareUpdateV2.d.ts +0 -11
  11. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  12. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  13. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  14. package/dist/api/FirmwareUpdateV4.d.ts +5 -21
  15. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  16. package/dist/api/OpenWalletSession.d.ts +1 -8
  17. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  18. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  19. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  20. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
  21. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  22. package/dist/api/firmware/getBinary.d.ts +0 -7
  23. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  24. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  25. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  26. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  27. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  28. package/dist/api/index.d.ts +1 -0
  29. package/dist/api/index.d.ts.map +1 -1
  30. package/dist/api/protocol-v2/Ping.d.ts +2 -0
  31. package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
  32. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  33. package/dist/core/index.d.ts.map +1 -1
  34. package/dist/data-manager/DataManager.d.ts +0 -1
  35. package/dist/data-manager/DataManager.d.ts.map +1 -1
  36. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  37. package/dist/device/Device.d.ts.map +1 -1
  38. package/dist/device/DeviceCommands.d.ts.map +1 -1
  39. package/dist/index.d.ts +89 -273
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +783 -2443
  42. package/dist/inject.d.ts.map +1 -1
  43. package/dist/lowLevelInject.d.ts.map +1 -1
  44. package/dist/protocols/protocol-v2/unlockRetry.d.ts +2 -3
  45. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  46. package/dist/protocols/protocol-v2/walletSession.d.ts +12 -0
  47. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  48. package/dist/topLevelInject.d.ts.map +1 -1
  49. package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -3
  50. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  51. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  52. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  53. package/dist/types/api/export.d.ts +1 -4
  54. package/dist/types/api/export.d.ts.map +1 -1
  55. package/dist/types/api/firmwareUpdate.d.ts +0 -69
  56. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  57. package/dist/types/api/index.d.ts +4 -10
  58. package/dist/types/api/index.d.ts.map +1 -1
  59. package/dist/types/api/openWalletSession.d.ts +0 -12
  60. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  61. package/dist/types/api/protocolV2.d.ts +4 -0
  62. package/dist/types/api/protocolV2.d.ts.map +1 -1
  63. package/dist/types/settings.d.ts +0 -13
  64. package/dist/types/settings.d.ts.map +1 -1
  65. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  66. package/dist/utils/patch.d.ts +1 -1
  67. package/dist/utils/patch.d.ts.map +1 -1
  68. package/package.json +4 -4
  69. package/src/api/CheckAllFirmwareRelease.ts +3 -23
  70. package/src/api/FirmwareUpdateV2.ts +120 -292
  71. package/src/api/FirmwareUpdateV3.ts +55 -256
  72. package/src/api/FirmwareUpdateV4.ts +297 -757
  73. package/src/api/OpenWalletSession.ts +23 -86
  74. package/src/api/device/DeviceUpdateBootloader.ts +6 -122
  75. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
  76. package/src/api/firmware/updateBootloader.ts +4 -19
  77. package/src/api/firmware/uploadFirmware.ts +22 -140
  78. package/src/api/index.ts +1 -0
  79. package/src/api/protocol-v2/Ping.ts +32 -1
  80. package/src/core/index.ts +39 -7
  81. package/src/data/messages/messages-protocol-v2.json +33 -1
  82. package/src/data-manager/DataManager.ts +33 -33
  83. package/src/data-manager/connectSettings.ts +0 -11
  84. package/src/device/Device.ts +7 -9
  85. package/src/device/DeviceCommands.ts +19 -0
  86. package/src/index.ts +0 -5
  87. package/src/inject.ts +4 -22
  88. package/src/lowLevelInject.ts +1 -5
  89. package/src/protocols/protocol-v2/unlockRetry.ts +20 -3
  90. package/src/protocols/protocol-v2/walletSession.ts +26 -8
  91. package/src/topLevelInject.ts +1 -5
  92. package/src/types/api/checkAllFirmwareRelease.ts +0 -3
  93. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  94. package/src/types/api/export.ts +0 -18
  95. package/src/types/api/firmwareUpdate.ts +0 -76
  96. package/src/types/api/index.ts +3 -14
  97. package/src/types/api/openWalletSession.ts +0 -19
  98. package/src/types/api/protocolV2.ts +10 -0
  99. package/src/types/settings.ts +0 -13
  100. package/src/utils/deviceInfoUtils.ts +15 -3
  101. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -86
  102. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  103. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  104. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  105. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -326
  106. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
  107. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  108. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  109. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  110. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  111. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  112. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  113. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  114. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -23
  115. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  116. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -30
  117. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  118. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  119. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  120. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -27
  121. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  122. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  123. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  124. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  125. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  126. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  127. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -621
  128. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -392
  129. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  130. package/src/types/api/firmwareUpdatePlan.ts +0 -36
  131. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -103,6 +103,41 @@ describe('DeviceCommands failure mapping', () => {
103
103
  ).rejects.toMatchObject({ errorCode: code });
104
104
  });
105
105
 
106
+ it.each([
107
+ ['DeviceSessionGet', 5, 'Another flow in progress'],
108
+ ['DeviceSessionAskPin', 0, 'Busy'],
109
+ ])('maps %s firmware busy failures to DeviceBusy', async (callType, subcode, message) => {
110
+ const commands = createCommands();
111
+
112
+ await expect(
113
+ commands._filterCommonTypes(
114
+ {
115
+ type: 'Failure',
116
+ message: { code: 'Failure_ProcessError', subcode, message },
117
+ } as any,
118
+ callType
119
+ )
120
+ ).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceBusy });
121
+ });
122
+
123
+ it('maps the current AskPin passphrase-disabled response without relying on a subcode', async () => {
124
+ const commands = createCommands();
125
+
126
+ await expect(
127
+ commands._filterCommonTypes(
128
+ {
129
+ type: 'Failure',
130
+ message: {
131
+ code: 'Failure_ProcessError',
132
+ subcode: 0,
133
+ message: 'Passphrase disabled',
134
+ },
135
+ } as any,
136
+ 'DeviceSessionAskPin'
137
+ )
138
+ ).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceNotOpenedPassphrase });
139
+ });
140
+
106
141
  it('rejects the Pro2 bootloader DeviceStatusGet unsupported response', async () => {
107
142
  const commands = createCommands();
108
143
 
@@ -1,61 +1,19 @@
1
- import DataManager from '../src/data-manager/DataManager';
2
1
  import { parseConnectSettings } from '../src/data-manager/connectSettings';
3
2
 
4
- import type { RemoteConfigResponse } from '../src/types';
5
-
6
- jest.mock('axios', () => ({
7
- get: jest.fn(),
8
- }));
9
-
10
3
  jest.mock('../src/data/config', () => ({
11
4
  getSDKVersion: jest.fn(() => '1.0.0'),
12
5
  DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
13
6
  }));
14
7
 
15
- const mockAxiosGet: jest.Mock = jest.requireMock('axios').get;
16
-
17
8
  describe('parseConnectSettings', () => {
18
- const preloadedConfig = {
19
- bridge: {},
20
- classic: { firmware: [], ble: [] },
21
- classic1s: { firmware: [], ble: [] },
22
- classicpure: { firmware: [], ble: [] },
23
- mini: { firmware: [], ble: [] },
24
- touch: { firmware: [], ble: [] },
25
- pro: { firmware: [], ble: [] },
26
- pro2: { firmware: [], ble: [] },
27
- } as unknown as RemoteConfigResponse;
28
-
29
- it('keeps a serializable preloaded config in parsed settings', () => {
30
- const settings = parseConnectSettings({
31
- firmwareManifestMode: 'sdk-managed',
32
- preloadedConfig,
33
- });
34
-
35
- expect(settings.firmwareManifestMode).toBe('sdk-managed');
36
- expect(settings.preloadedConfig).toBe(preloadedConfig);
37
- });
38
-
39
- it('uses the preloaded config before the SDK network client', async () => {
40
- const settings = parseConnectSettings({
41
- firmwareManifestMode: 'sdk-managed',
42
- preloadedConfig,
43
- });
44
-
45
- await DataManager.load(settings);
46
-
47
- expect(mockAxiosGet).not.toHaveBeenCalled();
48
- expect(DataManager.deviceMap.classic).toEqual({ firmware: [], ble: [] });
49
- });
9
+ it('keeps custom configFetcher in parsed settings', () => {
10
+ const configFetcher = jest.fn();
50
11
 
51
- it('fails closed without a preloaded config in external-only mode', async () => {
52
12
  const settings = parseConnectSettings({
53
- firmwareManifestMode: 'external-only',
13
+ fetchConfig: true,
14
+ configFetcher,
54
15
  });
55
16
 
56
- await expect(DataManager.load(settings)).rejects.toThrow(
57
- 'External firmware config snapshot is required'
58
- );
59
- expect(mockAxiosGet).not.toHaveBeenCalled();
17
+ expect(settings.configFetcher).toBe(configFetcher);
60
18
  });
61
19
  });
@@ -1,3 +1,5 @@
1
+ import { TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
2
+
1
3
  import { initConnector, initCore } from '../src/core';
2
4
  import { DataManager } from '../src/data-manager';
3
5
  import TransportManager from '../src/data-manager/TransportManager';
@@ -59,6 +61,63 @@ describe('public device lifecycle events', () => {
59
61
  jest.restoreAllMocks();
60
62
  });
61
63
 
64
+ test('registers the shared device lifecycle listeners exactly once', async () => {
65
+ jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
66
+ core = initCore();
67
+ initConnector();
68
+
69
+ for (const id of ['first-call', 'second-call']) {
70
+ await core.handleMessage({
71
+ id,
72
+ event: IFRAME.CALL,
73
+ type: IFRAME.CALL,
74
+ payload: { method: 'clearSessionCache' },
75
+ } as CoreMessage);
76
+ }
77
+
78
+ expect(DevicePool.emitter.listenerCount(DEVICE.CONNECT)).toBe(1);
79
+ expect(DevicePool.emitter.listenerCount(DEVICE.DISCONNECT)).toBe(1);
80
+ });
81
+
82
+ test('converts an internal transport disconnect into a public KnownDevice snapshot', () => {
83
+ jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
84
+ core = initCore();
85
+ initConnector();
86
+ const messages: CoreMessage[] = [];
87
+ core.on(CORE_EVENT, message => messages.push(message));
88
+ const device = createInitializedDevice('V2');
89
+ DevicePool.devicesCache['ble-connect-id'] = device;
90
+
91
+ DevicePool.emitter.emit(TRANSPORT_EVENT.DEVICE_DISCONNECT, {
92
+ id: 'ble-connect-id',
93
+ connectId: 'ble-connect-id',
94
+ name: 'OneKey Test BLE',
95
+ });
96
+
97
+ const disconnectMessage = messages.find(message => message.type === DEVICE.DISCONNECT);
98
+ expect(disconnectMessage?.payload.device).toMatchObject({
99
+ connectId: 'ble-connect-id',
100
+ serialNo: 'SERIAL-001',
101
+ state: { protocol: 'V2' },
102
+ });
103
+ expect(() => JSON.stringify(disconnectMessage?.payload.device)).not.toThrow();
104
+ });
105
+
106
+ test('treats an acquired BLE device as reusable until the transport disconnects', async () => {
107
+ jest.spyOn(DataManager, 'getSettings').mockReturnValue('desktop-web-ble' as never);
108
+ const device = createInitializedDevice('V2');
109
+ const acquire = jest.spyOn(device, 'acquire').mockResolvedValue(undefined);
110
+ (device as unknown as { deviceAcquired: boolean }).deviceAcquired = true;
111
+ (device as any).commands = { disposed: false };
112
+
113
+ expect(device.isUsedHere()).toBe(true);
114
+ await expect(device.connect('V2')).resolves.toBe(true);
115
+ expect(acquire).not.toHaveBeenCalled();
116
+
117
+ device.markTransportDisconnected();
118
+ expect(device.isUsedHere()).toBe(false);
119
+ });
120
+
62
121
  test.each([
63
122
  ['react-native', 'V1'],
64
123
  ['react-native', 'V2'],
@@ -2,7 +2,7 @@ import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shar
2
2
 
3
3
  import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
4
4
  import { getBinary } from '../../src/api/firmware/getBinary';
5
- import { uploadFirmwareFromSource } from '../../src/api/firmware/uploadFirmware';
5
+ import { uploadFirmware } from '../../src/api/firmware/uploadFirmware';
6
6
  import * as utils from '../../src/utils';
7
7
 
8
8
  jest.mock('../../src/data/config', () => ({
@@ -18,8 +18,7 @@ jest.mock('../../src/api/firmware/getBinary', () => ({
18
18
 
19
19
  jest.mock('../../src/api/firmware/uploadFirmware', () => ({
20
20
  updateResources: jest.fn(),
21
- updateResourcesFromSources: jest.fn(),
22
- uploadFirmwareFromSource: jest.fn(),
21
+ uploadFirmware: jest.fn(),
23
22
  }));
24
23
 
25
24
  jest.mock('../../src/device/DevicePool', () => ({
@@ -30,9 +29,7 @@ jest.mock('../../src/device/DevicePool', () => ({
30
29
  }));
31
30
 
32
31
  const mockGetBinary = getBinary as jest.MockedFunction<typeof getBinary>;
33
- const mockUploadFirmwareFromSource = uploadFirmwareFromSource as jest.MockedFunction<
34
- typeof uploadFirmwareFromSource
35
- >;
32
+ const mockUploadFirmware = uploadFirmware as jest.MockedFunction<typeof uploadFirmware>;
36
33
 
37
34
  type DeviceType = 'CLASSIC1S' | 'PURE';
38
35
 
@@ -178,7 +175,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
178
175
  expect(mockGetBinary).toHaveBeenCalledTimes(1);
179
176
  expectNoFirmwareMutationCalls(typedCall);
180
177
  expect(acquire).not.toHaveBeenCalled();
181
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
178
+ expect(mockUploadFirmware).not.toHaveBeenCalled();
182
179
  });
183
180
 
184
181
  it.each([
@@ -219,11 +216,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
219
216
  binary: firmwareBinary,
220
217
  } as Awaited<ReturnType<typeof getBinary>>);
221
218
  });
222
- mockUploadFirmwareFromSource.mockImplementation(() => {
219
+ mockUploadFirmware.mockImplementation(() => {
223
220
  callOrder.push('upload');
224
- return Promise.resolve(
225
- expectedResponse as Awaited<ReturnType<typeof uploadFirmwareFromSource>>
226
- );
221
+ return Promise.resolve(expectedResponse as Awaited<ReturnType<typeof uploadFirmware>>);
227
222
  });
228
223
  const { method, typedCall } = createMethod({
229
224
  updateType,
@@ -253,15 +248,15 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
253
248
  },
254
249
  })
255
250
  );
256
- expect(mockUploadFirmwareFromSource).toHaveBeenCalledWith(
251
+ expect(mockUploadFirmware).toHaveBeenCalledWith(
257
252
  updateType,
258
253
  expect.any(Function),
259
254
  expect.any(Function),
260
255
  method.device,
261
- expect.objectContaining({
262
- size: firmwareBinary.byteLength,
263
- }),
264
- true,
256
+ {
257
+ payload: firmwareBinary,
258
+ rebootOnSuccess: true,
259
+ },
265
260
  isUpdateBootloader
266
261
  );
267
262
  }
@@ -276,11 +271,11 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
276
271
  binary: firmwareBinary,
277
272
  } as Awaited<ReturnType<typeof getBinary>>);
278
273
  });
279
- mockUploadFirmwareFromSource.mockImplementation(() => {
274
+ mockUploadFirmware.mockImplementation(() => {
280
275
  callOrder.push('upload');
281
276
  return Promise.resolve({
282
277
  success: true,
283
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
278
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
284
279
  });
285
280
  const { method, typedCall, acquire } = createMethod({
286
281
  bootloaderMode: true,
@@ -305,9 +300,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
305
300
  resolveDownload = resolve;
306
301
  })
307
302
  );
308
- mockUploadFirmwareFromSource.mockResolvedValue({
303
+ mockUploadFirmware.mockResolvedValue({
309
304
  success: true,
310
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
305
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
311
306
  const { method, typedCall } = createMethod();
312
307
 
313
308
  const runPromise = method.run();
@@ -338,7 +333,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
338
333
 
339
334
  expectNoFirmwareMutationCalls(typedCall);
340
335
  expect(acquire).not.toHaveBeenCalled();
341
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
336
+ expect(mockUploadFirmware).not.toHaveBeenCalled();
342
337
  });
343
338
 
344
339
  it.each([
@@ -347,23 +342,23 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
347
342
  ])(
348
343
  'keeps the non-empty %s binary overload and never downloads it again',
349
344
  async (_kind, binary) => {
350
- mockUploadFirmwareFromSource.mockResolvedValue({
345
+ mockUploadFirmware.mockResolvedValue({
351
346
  success: true,
352
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
347
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
353
348
  const { method } = createMethod({ binary });
354
349
 
355
350
  await method.run();
356
351
 
357
352
  expect(mockGetBinary).not.toHaveBeenCalled();
358
- expect(mockUploadFirmwareFromSource).toHaveBeenCalledWith(
353
+ expect(mockUploadFirmware).toHaveBeenCalledWith(
359
354
  'firmware',
360
355
  expect.any(Function),
361
356
  expect.any(Function),
362
357
  method.device,
363
- expect.objectContaining({
364
- size: binary.byteLength,
365
- }),
366
- true,
358
+ {
359
+ payload: binary,
360
+ rebootOnSuccess: true,
361
+ },
367
362
  undefined
368
363
  );
369
364
  }
@@ -374,21 +369,17 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
374
369
  ['DataView', new DataView(new Uint8Array([9, 3, 4, 9]).buffer, 1, 2), [3, 4]],
375
370
  ['custom Buffer', createCustomBuffer(4), [1, 2, 3, 4]],
376
371
  ])('normalizes a non-empty %s before rebooting', async (_kind, binary, expectedBytes) => {
377
- let uploadedBytes: number[] = [];
378
- mockUploadFirmwareFromSource.mockImplementation(
379
- async (_updateType, _typedCall, _postMessage, _device, source) => {
380
- uploadedBytes = Array.from(new Uint8Array(await source.readAt(0, source.size)));
381
- return {
382
- success: true,
383
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>;
384
- }
385
- );
372
+ mockUploadFirmware.mockResolvedValue({
373
+ success: true,
374
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
386
375
  const { method } = createMethod({ binary });
387
376
 
388
377
  await method.run();
389
378
 
390
379
  expect(mockGetBinary).not.toHaveBeenCalled();
391
- expect(uploadedBytes).toEqual(expectedBytes);
380
+ const normalizedBinary = mockUploadFirmware.mock.calls[0][4].payload;
381
+ expect(normalizedBinary).toBeInstanceOf(ArrayBuffer);
382
+ expect(Array.from(new Uint8Array(normalizedBinary))).toEqual(expectedBytes);
392
383
  });
393
384
 
394
385
  it.each([
@@ -406,6 +397,6 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
406
397
  expect(mockGetBinary).not.toHaveBeenCalled();
407
398
  expectNoFirmwareMutationCalls(typedCall);
408
399
  expect(acquire).not.toHaveBeenCalled();
409
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
400
+ expect(mockUploadFirmware).not.toHaveBeenCalled();
410
401
  });
411
402
  });