A whole lot of stuff

This commit is contained in:
Courtney Arnold 2026-08-18 11:04:58 -05:00
parent faf319322a
commit ad850d2be6
50 changed files with 3013 additions and 213 deletions

View file

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:fuel_tax_tracker/services/app_state.dart';
import 'package:fuel_tax_tracker/widgets/ad_free_upsell_dialog.dart';
/// Covers the "remove ads for a year" upsell shown right after a user
/// watches the app's one ad placement — see `AppState.syncNow`'s
/// `onAdWatched` hook, wired up in main.dart. Tested here as a standalone
/// dialog function, matching backup_reminder_test.dart's convention.
void main() {
Future<void> openDialog(WidgetTester tester, AppState appState) async {
await tester.pumpWidget(
ChangeNotifierProvider.value(
value: appState,
child: MaterialApp(
home: Builder(
builder: (context) => ElevatedButton(
onPressed: () => showAdFreeUpsellDialog(context),
child: const Text('open'),
),
),
),
),
);
await tester.tap(find.text('open'));
await tester.pumpAndSettle();
}
testWidgets('shows the pitch with both actions', (tester) async {
await openDialog(tester, AppState());
expect(find.text('Tired of Ads?'), findsOneWidget);
expect(find.text('Not Now'), findsOneWidget);
expect(find.text('Remove Ads'), findsOneWidget);
});
testWidgets('falls back to generic copy when no price is loaded yet', (tester) async {
await openDialog(tester, AppState());
expect(find.textContaining('a single one-time purchase'), findsOneWidget);
expect(find.textContaining('\$'), findsNothing);
});
testWidgets('Not Now closes the dialog without navigating anywhere', (tester) async {
await openDialog(tester, AppState());
await tester.tap(find.text('Not Now'));
await tester.pumpAndSettle();
expect(find.text('Tired of Ads?'), findsNothing);
});
testWidgets('Remove Ads closes the dialog and starts the purchase flow', (tester) async {
final appState = AppState();
await openDialog(tester, appState);
await tester.tap(find.text('Remove Ads'));
await tester.pumpAndSettle();
expect(find.text('Tired of Ads?'), findsNothing, reason: 'dialog closed');
// buyAdFreeYear() delegates to PurchaseService, which — with no real
// store connection in tests — surfaces its failure through
// AppState.purchaseError rather than throwing, so tapping through is
// enough to confirm the button actually invoked it without crashing.
expect(appState.purchaseError, isNotNull);
});
}