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}