m3_lightmeter/integration_test/utils/widget_tester_actions.dart
Vadim f9246e15d6
ML-245 Add support for subscriptions (#246)
* typos

* added `LogbookPhotosProvider`

* implemented `LogbookScreen`

* implemented `LogbookPhotoEditScreen`

* added photo update

* save geolocation

* added `CameraSettingsSection`

* adjusted logbook grid

* added hero animation

* fixed logbook list updates

* added empty logbook state

* added `saveLogbookPhotos` option

* fixed updating photos

* made `DialogPicker` content scrollable

* added tests for `LogbookPhotosProvider`

* made image preview full-width

* made note field multiline

* wip

* migrated to new iap service

* fixed unit tests

* typo

* fixed arb formatting

* stub logbook photos for tests

* implemented integration test for logbook

* moved date to title

* redundant bottom padding

* added logbook photo screen to screenshots generator

* Update settings.gradle

* aligned iap stub with iap release

* sync

* made logbook iap

* debug screenshots

* Update runner.dart

* fixed dialog picker of optional values

* added bottom padding to logbook edit screen

* fixed tests

* Create camera_stub_image.jpg

* Update films_provider_test.dart

* rename

* aligned with iap

* added missing translations

* theme

* adjusted products color

* check pro status on settings open

* added yearly subscription

* handle purchase errors

* fixed bottom navigation bar behaviour

* handle only lifetime product case

* don't fetch products

* reworked restoring purchases

* fixed mocks

* fixed golden tests

* fixed logbook integration test

* sync pubspec

* sync stub
2025-08-09 17:22:34 +02:00

119 lines
4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lightmeter/application.dart';
import 'package:lightmeter/application_wrapper.dart';
import 'package:lightmeter/environment.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/widget_list_exposure_pairs.dart';
import 'package:lightmeter/screens/metering/screen_metering.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import '../mocks/iap_products_mock.dart';
import '../mocks/paid_features_mock.dart';
import 'finder_actions.dart';
import 'platform_channel_mock.dart';
const mockPhotoEv100 = 8.3;
extension WidgetTesterCommonActions on WidgetTester {
Future<void> pumpApplication({
bool isPro = true,
TogglableMap<EquipmentProfile>? equipmentProfiles,
String selectedEquipmentProfileId = '',
TogglableMap<Film>? predefinedFilms,
TogglableMap<FilmExponential>? customFilms,
String selectedFilmId = '',
}) async {
await pumpWidget(
MockIAPProductsProvider(
initialyPurchased: isPro,
child: ApplicationWrapper(
const Environment.dev(),
child: MockIAPProviders(
equipmentProfiles: equipmentProfiles,
selectedEquipmentProfileId: selectedEquipmentProfileId,
predefinedFilms: predefinedFilms,
customFilms: customFilms,
selectedFilmId: selectedFilmId,
child: const Application(),
),
),
),
);
await pumpAndSettle();
}
Future<void> takePhoto() async {
await tap(find.measureButton());
await pump(const Duration(seconds: 2)); // wait for circular progress indicator
await pump(const Duration(seconds: 1)); // wait for circular progress indicator
await pumpAndSettle();
}
Future<void> toggleIncidentMetering(double ev) async {
await tap(find.measureButton());
await sendMockIncidentEv(ev);
await tap(find.measureButton());
await pumpAndSettle();
}
Future<void> openAnimatedPicker<T>() async {
await tap(find.byType(T));
await pumpAndSettle(Dimens.durationL);
}
Future<void> openSettings() async {
await tap(find.byTooltip(S.current.tooltipOpenSettings));
await pumpAndSettle();
}
Future<void> navigatorPop() async {
(state(find.byType(Navigator)) as NavigatorState).pop();
await pumpAndSettle(Dimens.durationML);
}
}
extension WidgetTesterListTileActions on WidgetTester {
/// Useful for tapping a specific [ListTile] inside a specific screen or dialog
Future<void> tapDescendantTextOf<T>(String text) async {
await tap(find.descendant(of: find.byType(T), matching: find.text(text)));
await pumpAndSettle();
}
}
extension WidgetTesterTextButtonActions on WidgetTester {
Future<void> tapSelectButton() => _tapTextButton(S.current.select);
Future<void> tapCancelButton() => _tapTextButton(S.current.cancel);
Future<void> tapSaveButton() => _tapTextButton(S.current.save);
Future<void> _tapTextButton(String text) async {
final button = find.byWidgetPredicate(
(widget) => widget is TextButton && widget.child is Text && (widget.child as Text?)?.data == text,
);
expect(button, findsOneWidget);
await tap(button);
await pumpAndSettle();
}
}
extension WidgetTesterExposurePairsListActions on WidgetTester {
Future<void> scrollToTheLastExposurePair({
double ev = mockPhotoEv100,
StopType stopType = StopType.third,
EquipmentProfile equipmentProfile = defaultEquipmentProfile,
}) async {
final exposurePairs = MeteringContainerBuidler.buildExposureValues(
ev,
StopType.third,
equipmentProfile,
);
await scrollUntilVisible(
find.byWidgetPredicate((widget) => widget is Row && widget.key == ValueKey(exposurePairs.length - 1)),
56,
scrollable: find.descendant(of: find.byType(ExposurePairsList), matching: find.byType(Scrollable)),
);
}
}