@onekeyfe/hd-core 1.2.2-alpha.119 → 1.2.2-alpha.120
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.
- package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +298 -8
- package/__tests__/core-error-output.test.ts +0 -77
- package/__tests__/device-lifecycle-events.test.ts +8 -8
- package/__tests__/search-devices.test.ts +8 -196
- package/dist/api/SearchDevices.d.ts +15 -2
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +3 -0
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts +0 -2
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/index.js +88 -173
- package/package.json +4 -4
- package/src/api/SearchDevices.ts +27 -121
- package/src/api/allnetwork/AllNetworkGetAddress.ts +47 -20
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +32 -7
- package/src/core/index.ts +19 -58
- package/src/data-manager/TransportManager.ts +3 -14
- package/src/device/Device.ts +0 -7
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { EDeviceType } from '@onekeyfe/hd-shared';
|
|
1
|
+
import { EDeviceType, HardwareErrorCode, HardwareErrorCodeMessage } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import AllNetworkGetAddressBase from '../src/api/allnetwork/AllNetworkGetAddressBase';
|
|
4
4
|
import AllNetworkGetAddress from '../src/api/allnetwork/AllNetworkGetAddress';
|
|
5
5
|
import AllNetworkGetAddressByLoop from '../src/api/allnetwork/AllNetworkGetAddressByLoop';
|
|
6
|
+
import EvmGetAddress from '../src/api/evm/EVMGetAddress';
|
|
7
|
+
import { UI_REQUEST } from '../src/constants/ui-request';
|
|
6
8
|
import { findMethod } from '../src/api/utils';
|
|
7
9
|
import { getActiveRequestsByDeviceInstance } from '../src/utils/tracing';
|
|
8
10
|
|
|
@@ -424,7 +426,257 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
424
426
|
expect(typedCall).not.toHaveBeenCalled();
|
|
425
427
|
});
|
|
426
428
|
|
|
427
|
-
|
|
429
|
+
function createV2NestedHarness(payload: Record<string, unknown>) {
|
|
430
|
+
const calls: string[] = [];
|
|
431
|
+
const checkPassphraseStateSafety = jest
|
|
432
|
+
.fn()
|
|
433
|
+
.mockImplementation((_state, _empty, _skip, deriveCardano) => {
|
|
434
|
+
calls.push(deriveCardano ? 'resume-cardano-session' : 'restore-wallet-session');
|
|
435
|
+
return Promise.resolve(true);
|
|
436
|
+
});
|
|
437
|
+
const method = new TestAllNetworkMethod({
|
|
438
|
+
id: 10,
|
|
439
|
+
payload: {
|
|
440
|
+
method: 'allNetworkGetAddress',
|
|
441
|
+
connectId: 'connect-id',
|
|
442
|
+
deviceId: 'device-id',
|
|
443
|
+
bundle: [],
|
|
444
|
+
...payload,
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
method.protocolV2UnlockContext = { preflightCompleted: true };
|
|
448
|
+
method.device = {
|
|
449
|
+
checkPassphraseStateSafety,
|
|
450
|
+
commands: {
|
|
451
|
+
typedCall: jest.fn(),
|
|
452
|
+
},
|
|
453
|
+
getCurrentFirmwareType: jest.fn(),
|
|
454
|
+
getProtocol: jest.fn().mockReturnValue('V2'),
|
|
455
|
+
getCurrentFirmwareVersionString: jest.fn().mockReturnValue('1.0.0'),
|
|
456
|
+
getCurrentMethodVersionRange: jest
|
|
457
|
+
.fn()
|
|
458
|
+
.mockImplementation((getRange: (type: string) => unknown) => getRange('pro2')),
|
|
459
|
+
instanceId: 'device-instance',
|
|
460
|
+
isProtocolV2: jest.fn().mockReturnValue(true),
|
|
461
|
+
isBootloader: jest.fn().mockReturnValue(false),
|
|
462
|
+
isRomloader: jest.fn().mockReturnValue(false),
|
|
463
|
+
off: jest.fn(),
|
|
464
|
+
on: jest.fn(),
|
|
465
|
+
state: { status: { unlocked: true } },
|
|
466
|
+
updateProtocolV2Status: jest.fn(),
|
|
467
|
+
} as any;
|
|
468
|
+
return { calls, checkPassphraseStateSafety, method };
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function mockInnerChainMethod(name: string, onRun: () => void) {
|
|
472
|
+
return {
|
|
473
|
+
checkSafetyLevelOnTestNet: jest.fn().mockResolvedValue(false),
|
|
474
|
+
connectId: 'connect-id',
|
|
475
|
+
deviceId: 'device-id',
|
|
476
|
+
getVersionRange: jest.fn().mockReturnValue({}),
|
|
477
|
+
assertProtocolSupported: jest.fn(),
|
|
478
|
+
init: jest.fn(),
|
|
479
|
+
name,
|
|
480
|
+
responseID: 50,
|
|
481
|
+
unlockPolicy: 'unlock-before-run',
|
|
482
|
+
run: jest.fn().mockImplementation(() => {
|
|
483
|
+
onRun();
|
|
484
|
+
return Promise.resolve([{ address: `${name}-address` }]);
|
|
485
|
+
}),
|
|
486
|
+
setDevice: jest.fn(),
|
|
487
|
+
strictCheckDeviceSupport: false,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function createGroupedAddressHarness(showOnOneKey?: boolean) {
|
|
492
|
+
const { method: nestedHarness, checkPassphraseStateSafety } = createV2NestedHarness({});
|
|
493
|
+
const bundle = [0, 1, 2].map(index => ({
|
|
494
|
+
network: 'evm',
|
|
495
|
+
path: `m/44'/60'/${index}'/0/0`,
|
|
496
|
+
showOnOneKey,
|
|
497
|
+
}));
|
|
498
|
+
const method = new AllNetworkGetAddress({
|
|
499
|
+
id: 11,
|
|
500
|
+
payload: {
|
|
501
|
+
method: 'allNetworkGetAddress',
|
|
502
|
+
connectId: 'connect-id',
|
|
503
|
+
deviceId: 'device-id',
|
|
504
|
+
useEmptyPassphrase: true,
|
|
505
|
+
bundle,
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
method.protocolV2UnlockContext = nestedHarness.protocolV2UnlockContext;
|
|
509
|
+
method.abortController = new AbortController();
|
|
510
|
+
method.device = nestedHarness.device;
|
|
511
|
+
method.device.getCurrentDeviceType = jest.fn().mockReturnValue(EDeviceType.Pro2);
|
|
512
|
+
method.device.toMessageObject = jest.fn().mockReturnValue({});
|
|
513
|
+
method.postMessage = jest.fn();
|
|
514
|
+
const typedCall = jest
|
|
515
|
+
.fn()
|
|
516
|
+
.mockImplementation((_type: string, _response: string, params: { address_n: number[] }) => {
|
|
517
|
+
const index = params.address_n[2] - 0x80000000;
|
|
518
|
+
if (index === 1) return Promise.reject(new Error('Forbidden key path'));
|
|
519
|
+
return Promise.resolve({ message: { address: `address-${index}` } });
|
|
520
|
+
});
|
|
521
|
+
method.device.commands.typedCall = typedCall;
|
|
522
|
+
(findMethod as jest.Mock).mockImplementation(message => new EvmGetAddress(message));
|
|
523
|
+
method.init();
|
|
524
|
+
return { method, typedCall, checkPassphraseStateSafety, bundle };
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
test.each([false, true, undefined])(
|
|
528
|
+
'isolates a V2 address failure without repeating device confirmations (showOnOneKey=%s)',
|
|
529
|
+
async showOnOneKey => {
|
|
530
|
+
const { method, typedCall, checkPassphraseStateSafety, bundle } =
|
|
531
|
+
createGroupedAddressHarness(showOnOneKey);
|
|
532
|
+
|
|
533
|
+
const result = await method.getAllNetworkAddress(7);
|
|
534
|
+
|
|
535
|
+
expect(result.map(item => item.success)).toEqual([true, false, true]);
|
|
536
|
+
expect(result.map(item => item.path)).toEqual(bundle.map(item => item.path));
|
|
537
|
+
expect(result[0].payload).toMatchObject({ address: 'address-0', rootFingerprint: 7 });
|
|
538
|
+
expect(result[1].payload).toMatchObject({
|
|
539
|
+
code: HardwareErrorCode.CallMethodInvalidParameter,
|
|
540
|
+
});
|
|
541
|
+
expect(result[2].payload).toMatchObject({ address: 'address-2', rootFingerprint: 7 });
|
|
542
|
+
expect(typedCall.mock.calls.map(([, , params]) => params.address_n[2] - 0x80000000)).toEqual(
|
|
543
|
+
showOnOneKey === false ? [0, 1, 0, 1, 2] : [0, 1, 2]
|
|
544
|
+
);
|
|
545
|
+
expect(checkPassphraseStateSafety).toHaveBeenCalledTimes(1);
|
|
546
|
+
expect(method.postMessage).toHaveBeenCalledWith(
|
|
547
|
+
expect.objectContaining({ type: UI_REQUEST.DEVICE_PROGRESS, payload: { progress: 100 } })
|
|
548
|
+
);
|
|
549
|
+
expect(getActiveRequestsByDeviceInstance('device-instance')).toEqual([]);
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
test('does not retry a failed V2 link as individual address requests', async () => {
|
|
554
|
+
const { method, typedCall } = createGroupedAddressHarness(false);
|
|
555
|
+
const error = new Error('link disconnected');
|
|
556
|
+
typedCall.mockRejectedValueOnce(error);
|
|
557
|
+
|
|
558
|
+
await expect(method.getAllNetworkAddress(7)).rejects.toBe(error);
|
|
559
|
+
|
|
560
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
test('does not retry a V2 wallet mismatch as individual address requests', async () => {
|
|
564
|
+
const { method, typedCall, checkPassphraseStateSafety } = createGroupedAddressHarness(false);
|
|
565
|
+
checkPassphraseStateSafety.mockResolvedValueOnce(false);
|
|
566
|
+
|
|
567
|
+
await expect(method.getAllNetworkAddress(7)).rejects.toMatchObject({
|
|
568
|
+
errorCode: HardwareErrorCode.DeviceCheckPassphraseStateError,
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
expect(checkPassphraseStateSafety).toHaveBeenCalledTimes(1);
|
|
572
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
test('does not start individual retries after cancellation', async () => {
|
|
576
|
+
const { method, typedCall } = createGroupedAddressHarness(false);
|
|
577
|
+
typedCall.mockImplementationOnce(() => {
|
|
578
|
+
method.abortController?.abort();
|
|
579
|
+
return Promise.reject(new Error('Forbidden key path'));
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
await expect(method.getAllNetworkAddress(7)).rejects.toThrow(
|
|
583
|
+
HardwareErrorCodeMessage[HardwareErrorCode.RepeatUnlocking]
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
test('preserves Protocol V1 grouped error handling', async () => {
|
|
590
|
+
const { method, typedCall, checkPassphraseStateSafety } = createGroupedAddressHarness(false);
|
|
591
|
+
jest.spyOn(method.device, 'isProtocolV2').mockReturnValue(false);
|
|
592
|
+
jest.spyOn(method.device, 'getProtocol').mockReturnValue('V1');
|
|
593
|
+
|
|
594
|
+
const result = await method.getAllNetworkAddress(7);
|
|
595
|
+
|
|
596
|
+
expect(result.map(item => item.success)).toEqual([false, false, false]);
|
|
597
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
598
|
+
expect(checkPassphraseStateSafety).not.toHaveBeenCalled();
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
test('reuses a Protocol V2 hidden-wallet session across later nested chain methods', async () => {
|
|
602
|
+
const { calls, checkPassphraseStateSafety, method } = createV2NestedHarness({
|
|
603
|
+
passphraseState: 'hidden-state',
|
|
604
|
+
});
|
|
605
|
+
(findMethod as jest.Mock)
|
|
606
|
+
.mockReturnValueOnce(mockInnerChainMethod('evmGetAddress', () => calls.push('run-evm')))
|
|
607
|
+
.mockReturnValueOnce(mockInnerChainMethod('solGetAddress', () => calls.push('run-sol')));
|
|
608
|
+
|
|
609
|
+
await method.callMethod(
|
|
610
|
+
'evmGetAddress',
|
|
611
|
+
{
|
|
612
|
+
bundle: [{ _originRequestParams: { network: 'evm', path: "m/44'/60'/0'/0/0" } }],
|
|
613
|
+
},
|
|
614
|
+
0
|
|
615
|
+
);
|
|
616
|
+
await method.callMethod(
|
|
617
|
+
'solGetAddress',
|
|
618
|
+
{
|
|
619
|
+
bundle: [{ _originRequestParams: { network: 'sol', path: "m/44'/501'/0'" } }],
|
|
620
|
+
},
|
|
621
|
+
0
|
|
622
|
+
);
|
|
623
|
+
|
|
624
|
+
expect(checkPassphraseStateSafety).toHaveBeenCalledTimes(1);
|
|
625
|
+
expect(calls).toEqual(['restore-wallet-session', 'run-evm', 'run-sol']);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test('resumes Cardano after a Protocol V2 standard-domain session, then reuses it', async () => {
|
|
629
|
+
const { calls, checkPassphraseStateSafety, method } = createV2NestedHarness({
|
|
630
|
+
passphraseState: 'hidden-state',
|
|
631
|
+
});
|
|
632
|
+
(findMethod as jest.Mock)
|
|
633
|
+
.mockReturnValueOnce(mockInnerChainMethod('evmGetAddress', () => calls.push('run-evm')))
|
|
634
|
+
.mockReturnValueOnce(
|
|
635
|
+
mockInnerChainMethod('cardanoGetAddress', () => calls.push('run-cardano'))
|
|
636
|
+
)
|
|
637
|
+
.mockReturnValueOnce(mockInnerChainMethod('solGetAddress', () => calls.push('run-sol')));
|
|
638
|
+
|
|
639
|
+
await method.callMethod(
|
|
640
|
+
'evmGetAddress',
|
|
641
|
+
{
|
|
642
|
+
bundle: [{ _originRequestParams: { network: 'evm', path: "m/44'/60'/0'/0/0" } }],
|
|
643
|
+
},
|
|
644
|
+
0
|
|
645
|
+
);
|
|
646
|
+
await method.callMethod(
|
|
647
|
+
'cardanoGetAddress',
|
|
648
|
+
{
|
|
649
|
+
bundle: [{ _originRequestParams: { network: 'ada', path: "m/1852'/1815'/0'/0/0" } }],
|
|
650
|
+
},
|
|
651
|
+
0
|
|
652
|
+
);
|
|
653
|
+
await method.callMethod(
|
|
654
|
+
'solGetAddress',
|
|
655
|
+
{
|
|
656
|
+
bundle: [{ _originRequestParams: { network: 'sol', path: "m/44'/501'/0'" } }],
|
|
657
|
+
},
|
|
658
|
+
0
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
expect(checkPassphraseStateSafety).toHaveBeenCalledTimes(2);
|
|
662
|
+
expect(checkPassphraseStateSafety).toHaveBeenNthCalledWith(
|
|
663
|
+
2,
|
|
664
|
+
'hidden-state',
|
|
665
|
+
false,
|
|
666
|
+
undefined,
|
|
667
|
+
true,
|
|
668
|
+
undefined
|
|
669
|
+
);
|
|
670
|
+
expect(calls).toEqual([
|
|
671
|
+
'restore-wallet-session',
|
|
672
|
+
'run-evm',
|
|
673
|
+
'resume-cardano-session',
|
|
674
|
+
'run-cardano',
|
|
675
|
+
'run-sol',
|
|
676
|
+
]);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
test('batches Protocol V2 same-method addresses onto one nested chain call', async () => {
|
|
428
680
|
const method = new AllNetworkGetAddress({
|
|
429
681
|
id: 3,
|
|
430
682
|
payload: {
|
|
@@ -433,8 +685,43 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
433
685
|
deviceId: 'device-id',
|
|
434
686
|
useEmptyPassphrase: true,
|
|
435
687
|
bundle: [
|
|
436
|
-
{ network: 'evm', path: "m/44'/60'/0'/0/0" },
|
|
437
|
-
{ network: 'evm', path: "m/44'/60'/0'/0/1" },
|
|
688
|
+
{ network: 'evm', path: "m/44'/60'/0'/0/0", showOnOneKey: false },
|
|
689
|
+
{ network: 'evm', path: "m/44'/60'/0'/0/1", showOnOneKey: false },
|
|
690
|
+
],
|
|
691
|
+
},
|
|
692
|
+
});
|
|
693
|
+
method.device = {
|
|
694
|
+
isProtocolV2: jest.fn().mockReturnValue(true),
|
|
695
|
+
} as any;
|
|
696
|
+
method.postMessage = jest.fn();
|
|
697
|
+
const callMethod = jest.fn().mockResolvedValue([
|
|
698
|
+
{ payload: { address: '0x1' }, success: true },
|
|
699
|
+
{ payload: { address: '0x2' }, success: true },
|
|
700
|
+
]);
|
|
701
|
+
method.callMethod = callMethod;
|
|
702
|
+
|
|
703
|
+
await method.getAllNetworkAddress(7);
|
|
704
|
+
|
|
705
|
+
expect(callMethod).toHaveBeenCalledTimes(1);
|
|
706
|
+
expect(callMethod).toHaveBeenCalledWith(
|
|
707
|
+
'evmGetAddress',
|
|
708
|
+
expect.objectContaining({ bundle: [expect.any(Object), expect.any(Object)] }),
|
|
709
|
+
7
|
|
710
|
+
);
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
test('batches Protocol V2 hidden-wallet same-method addresses onto one nested chain call', async () => {
|
|
714
|
+
const method = new AllNetworkGetAddress({
|
|
715
|
+
id: 6,
|
|
716
|
+
payload: {
|
|
717
|
+
method: 'allNetworkGetAddress',
|
|
718
|
+
connectId: 'connect-id',
|
|
719
|
+
deviceId: 'device-id',
|
|
720
|
+
passphraseState: 'hidden-state',
|
|
721
|
+
bundle: [
|
|
722
|
+
{ network: 'evm', path: "m/44'/60'/0'/0/0", showOnOneKey: false },
|
|
723
|
+
{ network: 'evm', path: "m/44'/60'/0'/0/1", showOnOneKey: false },
|
|
724
|
+
{ network: 'sol', path: "m/44'/501'/0'", showOnOneKey: false },
|
|
438
725
|
],
|
|
439
726
|
},
|
|
440
727
|
});
|
|
@@ -444,8 +731,11 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
444
731
|
method.postMessage = jest.fn();
|
|
445
732
|
const callMethod = jest
|
|
446
733
|
.fn()
|
|
447
|
-
.mockResolvedValueOnce([
|
|
448
|
-
|
|
734
|
+
.mockResolvedValueOnce([
|
|
735
|
+
{ payload: { address: '0x1' }, success: true },
|
|
736
|
+
{ payload: { address: '0x2' }, success: true },
|
|
737
|
+
])
|
|
738
|
+
.mockResolvedValueOnce([{ payload: { address: 'sol1' }, success: true }]);
|
|
449
739
|
method.callMethod = callMethod;
|
|
450
740
|
|
|
451
741
|
await method.getAllNetworkAddress(7);
|
|
@@ -454,12 +744,12 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
454
744
|
expect(callMethod).toHaveBeenNthCalledWith(
|
|
455
745
|
1,
|
|
456
746
|
'evmGetAddress',
|
|
457
|
-
expect.objectContaining({ bundle: [expect.any(Object)] }),
|
|
747
|
+
expect.objectContaining({ bundle: [expect.any(Object), expect.any(Object)] }),
|
|
458
748
|
7
|
|
459
749
|
);
|
|
460
750
|
expect(callMethod).toHaveBeenNthCalledWith(
|
|
461
751
|
2,
|
|
462
|
-
'
|
|
752
|
+
'solGetAddress',
|
|
463
753
|
expect.objectContaining({ bundle: [expect.any(Object)] }),
|
|
464
754
|
7
|
|
465
755
|
);
|
|
@@ -4,8 +4,6 @@ import { initConnector, initCore } from '../src/core';
|
|
|
4
4
|
import { DataManager } from '../src/data-manager';
|
|
5
5
|
import TransportManager from '../src/data-manager/TransportManager';
|
|
6
6
|
import { IFRAME } from '../src/events';
|
|
7
|
-
import SearchDevices from '../src/api/SearchDevices';
|
|
8
|
-
import { DeviceList } from '../src/device/DeviceList';
|
|
9
7
|
|
|
10
8
|
jest.mock('../src/data/config', () => ({
|
|
11
9
|
getSDKVersion: jest.fn(() => '1.0.0-test'),
|
|
@@ -26,81 +24,6 @@ describe('Core 错误输出边界', () => {
|
|
|
26
24
|
jest.restoreAllMocks();
|
|
27
25
|
});
|
|
28
26
|
|
|
29
|
-
test.each([
|
|
30
|
-
['webusb', false],
|
|
31
|
-
['desktop-webusb', false],
|
|
32
|
-
['desktop-webusb', true],
|
|
33
|
-
] as const)(
|
|
34
|
-
'%s waits for discovery without masking initialization or cancellation (cancel=%s)',
|
|
35
|
-
async (env, shouldCancel) => {
|
|
36
|
-
jest.spyOn(DataManager, 'getSettings').mockReturnValue(env as never);
|
|
37
|
-
const error = ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed, 'probe failed');
|
|
38
|
-
let finishSearch!: () => void;
|
|
39
|
-
let searchStarted!: () => void;
|
|
40
|
-
const started = new Promise<void>(resolve => {
|
|
41
|
-
searchStarted = resolve;
|
|
42
|
-
});
|
|
43
|
-
const search = jest.spyOn(SearchDevices.prototype, 'run').mockImplementation(async () => {
|
|
44
|
-
searchStarted();
|
|
45
|
-
await new Promise<void>(resolve => {
|
|
46
|
-
finishSearch = resolve;
|
|
47
|
-
});
|
|
48
|
-
return [];
|
|
49
|
-
});
|
|
50
|
-
const initialize = jest
|
|
51
|
-
.spyOn(DeviceList.prototype, 'getDeviceLists')
|
|
52
|
-
.mockRejectedValue(error);
|
|
53
|
-
const core = initCore();
|
|
54
|
-
initConnector();
|
|
55
|
-
try {
|
|
56
|
-
const discovery = core.handleMessage({
|
|
57
|
-
id: 10,
|
|
58
|
-
type: IFRAME.CALL,
|
|
59
|
-
payload: { method: 'searchDevices' },
|
|
60
|
-
} as never);
|
|
61
|
-
await started;
|
|
62
|
-
const request = core.handleMessage({
|
|
63
|
-
id: 11,
|
|
64
|
-
type: IFRAME.CALL,
|
|
65
|
-
payload: {
|
|
66
|
-
method: 'getDeviceState',
|
|
67
|
-
connectId: 'serial-V2',
|
|
68
|
-
retryCount: 1,
|
|
69
|
-
pollIntervalTime: 1,
|
|
70
|
-
timeout: 1000,
|
|
71
|
-
},
|
|
72
|
-
} as never);
|
|
73
|
-
await new Promise(resolve => {
|
|
74
|
-
setTimeout(resolve, 0);
|
|
75
|
-
});
|
|
76
|
-
expect(initialize).not.toHaveBeenCalled();
|
|
77
|
-
if (shouldCancel) {
|
|
78
|
-
await core.handleMessage({
|
|
79
|
-
type: IFRAME.CANCEL,
|
|
80
|
-
payload: { connectId: 'serial-V2' },
|
|
81
|
-
} as never);
|
|
82
|
-
}
|
|
83
|
-
finishSearch();
|
|
84
|
-
await expect(discovery).resolves.toMatchObject({ success: true });
|
|
85
|
-
const expectedError = shouldCancel
|
|
86
|
-
? ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled)
|
|
87
|
-
: error;
|
|
88
|
-
await expect(request).resolves.toMatchObject({
|
|
89
|
-
success: false,
|
|
90
|
-
payload: { code: expectedError.errorCode, error: expectedError.message },
|
|
91
|
-
});
|
|
92
|
-
await new Promise(resolve => {
|
|
93
|
-
setTimeout(resolve, 0);
|
|
94
|
-
});
|
|
95
|
-
expect(search).toHaveBeenCalledTimes(1);
|
|
96
|
-
expect(initialize).toHaveBeenCalledTimes(shouldCancel ? 0 : 2);
|
|
97
|
-
} finally {
|
|
98
|
-
finishSearch?.();
|
|
99
|
-
await core.dispose();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
);
|
|
103
|
-
|
|
104
27
|
test.each([
|
|
105
28
|
HardwareErrorCode.BleDeviceNotBonded,
|
|
106
29
|
HardwareErrorCode.BleDeviceBondedCanceled,
|
|
@@ -362,12 +362,12 @@ describe('public device lifecycle events', () => {
|
|
|
362
362
|
}
|
|
363
363
|
);
|
|
364
364
|
|
|
365
|
-
test('
|
|
365
|
+
test('keeps the cleanup barrier when its deadline expires', async () => {
|
|
366
366
|
const realSetTimeout = setTimeout;
|
|
367
367
|
jest
|
|
368
368
|
.spyOn(global, 'setTimeout')
|
|
369
369
|
.mockImplementation((callback, delay, ...args) =>
|
|
370
|
-
realSetTimeout(callback, delay ===
|
|
370
|
+
realSetTimeout(callback, delay === 15_000 ? 0 : delay, ...args)
|
|
371
371
|
);
|
|
372
372
|
{
|
|
373
373
|
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
@@ -382,13 +382,13 @@ describe('public device lifecycle events', () => {
|
|
|
382
382
|
type: IFRAME.CALL,
|
|
383
383
|
payload: { method: 'getDeviceState', connectId: 'draining-device', connectProtocol: 'V2' },
|
|
384
384
|
} as CoreMessage);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
await new Promise(resolve => {
|
|
389
|
-
setImmediate(resolve);
|
|
385
|
+
await expect(result).resolves.toMatchObject({
|
|
386
|
+
success: false,
|
|
387
|
+
payload: { code: HardwareErrorCode.DeviceBusy },
|
|
390
388
|
});
|
|
391
|
-
expect(
|
|
389
|
+
expect(acquire).not.toHaveBeenCalled();
|
|
390
|
+
expect(context.getPrePendingCallPromise('draining-device')).toBe(gate.promise);
|
|
391
|
+
gate.resolve();
|
|
392
392
|
}
|
|
393
393
|
});
|
|
394
394
|
|