main
1import 'package:bloc_test/bloc_test.dart';
2import 'package:blood_pressure_app/features/bluetooth/backend/mock/mock_device.dart';
3import 'package:blood_pressure_app/features/bluetooth/backend/mock/mock_manager.dart';
4import 'package:blood_pressure_app/features/bluetooth/bluetooth_input.dart';
5import 'package:blood_pressure_app/features/bluetooth/logic/ble_read_cubit.dart';
6import 'package:blood_pressure_app/features/bluetooth/logic/bluetooth_cubit.dart';
7import 'package:blood_pressure_app/features/bluetooth/logic/characteristics/ble_measurement_data.dart';
8import 'package:blood_pressure_app/features/bluetooth/logic/device_scan_cubit.dart';
9import 'package:blood_pressure_app/features/bluetooth/ui/closed_bluetooth_input.dart';
10import 'package:blood_pressure_app/features/bluetooth/ui/measurement_success.dart';
11import 'package:flutter/material.dart';
12import 'package:flutter_test/flutter_test.dart';
13import 'package:health_data_store/health_data_store.dart';
14
15import '../../util.dart';
16
17class _MockBluetoothCubit extends MockCubit<BluetoothState>
18 implements BluetoothCubit {}
19class _MockDeviceScanCubit extends MockCubit<DeviceScanState>
20 implements DeviceScanCubit {}
21class _MockBleReadCubit extends MockCubit<BleReadState>
22 implements BleReadCubit {}
23class _MockBluetoothCubitFailingEnable extends MockCubit<BluetoothState>
24 implements BluetoothCubit {
25 @override
26 Future<bool> enableBluetooth() async {
27 throw 'enableBluetooth called';
28 }
29}
30
31void main() {
32 testWidgets('propagates successful read', (WidgetTester tester) async {
33 final bluetoothCubit = _MockBluetoothCubit();
34 whenListen(bluetoothCubit, Stream<BluetoothState>.fromIterable([BluetoothStateReady()]),
35 initialState: BluetoothStateReady());
36 final deviceScanCubit = _MockDeviceScanCubit();
37 final devScanOk = DeviceSelected(MockBluetoothDevice(MockBluetoothManager(), 'tstDev'));
38 whenListen(deviceScanCubit, Stream<DeviceScanState>.fromIterable([devScanOk]),
39 initialState: devScanOk);
40 final bleReadCubit = _MockBleReadCubit();
41 final bleReadOk = BleReadSuccess(BleMeasurementData(
42 systolic: 123,
43 diastolic: 45,
44 meanArterialPressure: 67,
45 isMMHG: true,
46 ));
47 whenListen(bleReadCubit, Stream<BleReadState>.fromIterable([bleReadOk]),
48 initialState: bleReadOk,
49 );
50
51 final List<BloodPressureRecord> reads = [];
52 await tester.pumpWidget(materialApp(BluetoothInput(
53 manager: MockBluetoothManager(),
54 onMeasurement: reads.add,
55 bluetoothCubit: () => bluetoothCubit,
56 deviceScanCubit: () => deviceScanCubit,
57 bleReadCubit: (device) => bleReadCubit,
58 )));
59
60 await tester.tap(find.byType(ClosedBluetoothInput));
61 await tester.pumpAndSettle();
62 expect(find.byType(ClosedBluetoothInput), findsNothing);
63
64 expect(reads, hasLength(1));
65 expect(reads.first.sys?.mmHg, 123);
66 expect(reads.first.dia?.mmHg, 45);
67 expect(reads.first.pul, null);
68 });
69 testWidgets('allows closing after successful read', (WidgetTester tester) async {
70 final bluetoothCubit = _MockBluetoothCubit();
71 whenListen(bluetoothCubit, Stream<BluetoothState>.fromIterable([BluetoothStateReady()]),
72 initialState: BluetoothStateReady());
73 final deviceScanCubit = _MockDeviceScanCubit();
74 final devScanOk = DeviceSelected(MockBluetoothDevice(MockBluetoothManager(), 'tstDev'));
75 whenListen(deviceScanCubit, Stream<DeviceScanState>.fromIterable([devScanOk]),
76 initialState: devScanOk);
77 final bleReadCubit = _MockBleReadCubit();
78 final bleReadOk = BleReadSuccess(BleMeasurementData(
79 systolic: 123,
80 diastolic: 45,
81 meanArterialPressure: 67,
82 isMMHG: true,
83 ));
84 whenListen(bleReadCubit, Stream<BleReadState>.fromIterable([bleReadOk]),
85 initialState: bleReadOk,
86 );
87
88 final List<BloodPressureRecord> reads = [];
89 await tester.pumpWidget(materialApp(BluetoothInput(
90 manager: MockBluetoothManager(),
91 onMeasurement: reads.add,
92 bluetoothCubit: () => bluetoothCubit,
93 deviceScanCubit: () => deviceScanCubit,
94 bleReadCubit: (device) => bleReadCubit,
95 )));
96
97 await tester.tap(find.byType(ClosedBluetoothInput));
98 await tester.pumpAndSettle();
99 expect(find.byType(ClosedBluetoothInput), findsNothing);
100 expect(find.byType(MeasurementSuccess), findsOneWidget);
101
102 await tester.tap(find.byIcon(Icons.close));
103 await tester.pumpAndSettle();
104 expect(find.byType(ClosedBluetoothInput), findsOneWidget);
105 });
106 testWidgets("doesn't attempt to turn on bluetooth before interaction", (tester) async {
107 final bluetoothCubit = _MockBluetoothCubitFailingEnable();
108 whenListen(bluetoothCubit, Stream<BluetoothState>.fromIterable([BluetoothStateDisabled()]),
109 initialState: BluetoothStateReady());
110 await tester.pumpWidget(materialApp(BluetoothInput(
111 manager: MockBluetoothManager(),
112 onMeasurement: (_) {},
113 bluetoothCubit: () => bluetoothCubit,
114 )));
115 expect(tester.takeException(), isNull);
116 });
117}