Skip to content

Commit

Permalink
feat: add tests for bluetoothRedcer
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-sanderson committed Feb 20, 2025
1 parent c0009aa commit 6d9cf75
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 5 deletions.
6 changes: 6 additions & 0 deletions suite-common/bluetooth/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const baseConfig = require('../../jest.config.base');

module.exports = {
...baseConfig,
roots: ['<rootDir>/src', '<rootDir>/tests', '<rootDir>/../test-utils/__mocks__'],
};
3 changes: 2 additions & 1 deletion suite-common/bluetooth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
"sideEffects": false,
"main": "src/index",
"scripts": {
"test:unit": "yarn g:jest -c ./jest.config.js",
"depcheck": "yarn g:depcheck",
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@reduxjs/toolkit": "1.9.5",
"@suite-common/redux-utils": "workspace:*",
"@suite-common/wallet-core": "workspace:*"
"@trezor/connect": "workspace:*"
}
}
6 changes: 4 additions & 2 deletions suite-common/bluetooth/src/bluetoothReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,13 @@ export const prepareBluetoothReducerCreator = <T extends BluetoothDeviceCommon>(
bluetoothNearbyDevicesUpdateAction,
(state, { payload: { nearbyDevices } }) => {
state.nearbyDevices = nearbyDevices
.sort((a, b) => a.lastUpdatedTimestamp - b.lastUpdatedTimestamp)
.sort((a, b) => b.lastUpdatedTimestamp - a.lastUpdatedTimestamp)
.map(
(device): Draft<BluetoothDeviceState<T>> => ({
device: device as Draft<T>,
status: null,
status:
state.nearbyDevices.find(it => it.device.id === device.id)
?.status ?? null,
}),
);
},
Expand Down
243 changes: 243 additions & 0 deletions suite-common/bluetooth/tests/bluetoothReducer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import { combineReducers } from '@reduxjs/toolkit';

import { TrezorDevice } from '@suite-common/suite-types';
import { configureMockStore, extraDependenciesMock } from '@suite-common/test-utils';
import { deviceActions } from '@suite-common/wallet-core';
import { Device } from '@trezor/connect';

import {
BluetoothDeviceState,
bluetoothAdapterEventAction,
bluetoothConnectDeviceEventAction,
bluetoothKnownDevicesUpdateAction,
bluetoothNearbyDevicesUpdateAction,
bluetoothRemoveKnownDeviceAction,
prepareBluetoothReducerCreator,
} from '../src';
import { BluetoothDeviceCommon, BluetoothState } from '../src/bluetoothReducer';

const bluetoothReducer =
prepareBluetoothReducerCreator<BluetoothDeviceCommon>()(extraDependenciesMock);

const initialState: BluetoothState<BluetoothDeviceCommon> = {
adapterStatus: 'unknown',
scanStatus: 'idle',
nearbyDevices: [] as BluetoothDeviceState<BluetoothDeviceCommon>[],
knownDevices: [] as BluetoothDeviceCommon[],
};

describe('Message system reducer', () => {
it('sets the bluetooth adapter as enabled/disabled when powered/unpowered', () => {
const store = configureMockStore({
extra: {},
reducer: combineReducers({ bluetooth: bluetoothReducer }),
preloadedState: { bluetooth: initialState },
});

expect(store.getState().bluetooth.adapterStatus).toEqual('unknown');
store.dispatch(bluetoothAdapterEventAction({ isPowered: true }));
expect(store.getState().bluetooth.adapterStatus).toEqual('enabled');
store.dispatch(bluetoothAdapterEventAction({ isPowered: false }));
expect(store.getState().bluetooth.adapterStatus).toEqual('disabled');
});

it('sorts the devices based on the `lastUpdatedTimestamp` and keeps the status for already existing device', () => {
const alreadyExistingNearbyDevice: BluetoothDeviceState<BluetoothDeviceCommon> = {
device: {
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
status: { type: 'pairing' },
};

const nearbyDeviceToBeDropped: BluetoothDeviceState<BluetoothDeviceCommon> = {
device: {
id: 'B',
data: [],
name: 'Trezor B',
lastUpdatedTimestamp: 2,
},
status: null,
};

const store = configureMockStore({
extra: {},
reducer: combineReducers({ bluetooth: bluetoothReducer }),
preloadedState: {
bluetooth: {
...initialState,
nearbyDevices: [nearbyDeviceToBeDropped, alreadyExistingNearbyDevice],
},
},
});

const nearbyDevices: BluetoothDeviceCommon[] = [
{
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
{
id: 'C',
data: [],
name: 'Trezor C',
lastUpdatedTimestamp: 3,
},
];

store.dispatch(bluetoothNearbyDevicesUpdateAction({ nearbyDevices }));
expect(store.getState().bluetooth.nearbyDevices).toEqual([
{
device: {
id: 'C',
data: [],
name: 'Trezor C',
lastUpdatedTimestamp: 3,
},
status: null,
},
// No `B` device present, it was dropped
{
device: {
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
status: { type: 'pairing' }, // Keeps the pairing status
},
]);
});

it('changes the status of the given device during pairing process', () => {
const nearbyDevice: BluetoothDeviceState<BluetoothDeviceCommon> = {
device: {
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
status: null,
};

const store = configureMockStore({
extra: {},
reducer: combineReducers({ bluetooth: bluetoothReducer }),
preloadedState: {
bluetooth: { ...initialState, nearbyDevices: [nearbyDevice] },
},
});

store.dispatch(
bluetoothConnectDeviceEventAction({
id: 'A',
connectionStatus: { type: 'pairing', pin: '12345' },
}),
);
expect(store.getState().bluetooth.nearbyDevices).toEqual([
{
device: nearbyDevice.device,
status: { type: 'pairing', pin: '12345' },
},
]);
});

it('updates and removes known devices', () => {
const store = configureMockStore({
extra: {},
reducer: combineReducers({ bluetooth: bluetoothReducer }),
preloadedState: { bluetooth: initialState },
});

const knownDeviceToAdd: BluetoothDeviceCommon[] = [
{
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
{
id: 'B',
data: [],
name: 'Trezor B',
lastUpdatedTimestamp: 2,
},
];

store.dispatch(bluetoothKnownDevicesUpdateAction({ knownDevices: knownDeviceToAdd }));
expect(store.getState().bluetooth.knownDevices).toEqual(knownDeviceToAdd);

store.dispatch(bluetoothRemoveKnownDeviceAction({ id: 'A' }));

expect(store.getState().bluetooth.knownDevices).toEqual([
{
id: 'B',
data: [],
name: 'Trezor B',
lastUpdatedTimestamp: 2,
},
]);
});

it('removes device from knownDevices when the device is disconnected by TrezorConnect', () => {
const alreadyExistingNearbyDevice: BluetoothDeviceState<BluetoothDeviceCommon> = {
device: {
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
status: { type: 'connected' },
};

const store = configureMockStore({
extra: {},
reducer: combineReducers({ bluetooth: bluetoothReducer }),
preloadedState: {
bluetooth: { ...initialState, nearbyDevices: [alreadyExistingNearbyDevice] },
},
});

const trezorDevice: Pick<TrezorDevice, 'bluetoothProps'> = {
bluetoothProps: { id: 'A' },
};

store.dispatch(deviceActions.deviceDisconnect(trezorDevice as TrezorDevice));
expect(store.getState().bluetooth.nearbyDevices).toEqual([]);
});

it('stores a device in `knownDevices` when device is connected by TrezorConnect', () => {
const nearbyDevice: BluetoothDeviceState<BluetoothDeviceCommon> = {
device: {
id: 'A',
data: [],
name: 'Trezor A',
lastUpdatedTimestamp: 1,
},
status: { type: 'connected' },
};

const store = configureMockStore({
extra: {},
reducer: combineReducers({ bluetooth: bluetoothReducer }),
preloadedState: {
bluetooth: { ...initialState, nearbyDevices: [nearbyDevice] },
},
});

const trezorDevice: Pick<Device, 'bluetoothProps'> = {
bluetoothProps: { id: 'A' },
};

store.dispatch(
deviceActions.connectDevice({
device: trezorDevice as Device,
settings: { defaultWalletLoading: 'passphrase' },
}),
);
expect(store.getState().bluetooth.knownDevices).toEqual([nearbyDevice.device]);
});
});
2 changes: 1 addition & 1 deletion suite-common/bluetooth/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"references": [
{ "path": "../redux-utils" },
{ "path": "../suite-types" },
{ "path": "../wallet-core" }
{ "path": "../../packages/connect" }
]
}
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9610,7 +9610,7 @@ __metadata:
dependencies:
"@reduxjs/toolkit": "npm:1.9.5"
"@suite-common/redux-utils": "workspace:*"
"@suite-common/wallet-core": "workspace:*"
"@trezor/connect": "workspace:*"
languageName: unknown
linkType: soft

Expand Down

0 comments on commit 6d9cf75

Please sign in to comment.