MotorSignal-App/test/pro_upgrade_sheet_landscape...

102 lines
3.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:motorcycle_dash/features/entitlements/widgets/pro_lock_badge.dart';
import 'package:motorcycle_dash/features/rides/ride_state_machine.dart';
import 'package:motorcycle_dash/services/entitlements/feature_access_service.dart';
/// Regression for Issue #52 / BUG-005 follow-up: the "Forensic CSV & PDF Export" Pro
/// upsell sheet showed "BOTTOM OVERFLOWED BY 90 PIXELS" in landscape on a Pixel 8a
/// (~914x411 dp) because showProUpgradeSheet built a non-scrolling Column inside a default
/// modal bottom sheet, which Flutter caps at 9/16 of the screen height.
class _FakeRideStateMachine extends StateNotifier<RideSession>
implements RideStateMachine {
_FakeRideStateMachine(super.initialState);
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
Future<void> _pumpHost(
WidgetTester tester, {
required Size viewport,
double textScale = 1.0,
}) async {
await tester.binding.setSurfaceSize(viewport);
addTearDown(() => tester.binding.setSurfaceSize(null));
await tester.pumpWidget(
ProviderScope(
overrides: [
rideStateMachineProvider.overrideWith(
(ref) => _FakeRideStateMachine(RideSession(state: RideState.idle)),
),
],
child: MediaQuery(
data: MediaQueryData(
size: viewport,
textScaler: TextScaler.linear(textScale),
),
child: MaterialApp(
home: Scaffold(
body: Consumer(
builder: (context, ref, _) => ElevatedButton(
onPressed: () => showProUpgradeSheet(
context,
ref,
feature: MotorSignalFeature.csvExport,
),
child: const Text('Open upsell'),
),
),
),
),
),
),
);
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
for (final viewport in const [
Size(914, 411), // Pixel 8a landscape
Size(800, 360),
Size(780, 360),
]) {
for (final scale in const [1.0, 1.3]) {
testWidgets(
'Pro upgrade sheet has no bottom overflow in landscape '
'${viewport.width.toInt()}x${viewport.height.toInt()} (text scale $scale)',
(tester) async {
await _pumpHost(tester, viewport: viewport, textScale: scale);
await tester.tap(find.text('Open upsell'));
await tester.pumpAndSettle();
expect(find.text('Forensic CSV & PDF Export'), findsOneWidget);
expect(find.text('VIEW MOTORSIGNAL PRO'), findsOneWidget);
expect(find.text('NOT NOW'), findsOneWidget);
// No RenderFlex overflow exception.
expect(tester.takeException(), isNull);
},
);
}
}
testWidgets('NOT NOW is reachable and dismisses the sheet in landscape', (
tester,
) async {
await _pumpHost(tester, viewport: const Size(800, 360), textScale: 1.3);
await tester.tap(find.text('Open upsell'));
await tester.pumpAndSettle();
await tester.ensureVisible(find.text('NOT NOW'));
await tester.tap(find.text('NOT NOW'));
await tester.pumpAndSettle();
expect(find.text('VIEW MOTORSIGNAL PRO'), findsNothing);
expect(tester.takeException(), isNull);
});
}