forked from eatvio/eatvio_app
chore(version): update app version to 1.3.5+85 and improve test coverage reporting in CI
This commit is contained in:
@@ -1,73 +1,109 @@
|
||||
import 'package:eatvio_app/core/cubit/base_cubit.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
// Простой тестовый cubit для проверки BaseCubit
|
||||
class TestState {
|
||||
final String? value;
|
||||
TestState({this.value});
|
||||
}
|
||||
// Test implementation of BaseCubit
|
||||
class TestCubit extends BaseCubit<String> {
|
||||
TestCubit() : super('initial');
|
||||
|
||||
class TestCubit extends BaseCubit<TestState> {
|
||||
TestCubit() : super(TestState());
|
||||
|
||||
void testHandleError(Object error, [StackTrace? stackTrace]) {
|
||||
handleError(error, stackTrace);
|
||||
void setState(String state) {
|
||||
emit(state);
|
||||
}
|
||||
|
||||
Future<String?> testSafeExecute() async {
|
||||
return await safeExecute(() async => 'success');
|
||||
Future<String?> executeOperation() async {
|
||||
return await safeExecute(() async {
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
return 'success';
|
||||
});
|
||||
}
|
||||
|
||||
Future<String?> testSafeExecuteWithError() async {
|
||||
return await safeExecute(() async => throw Exception('Test error'));
|
||||
Future<String?> executeOperationWithState() async {
|
||||
return await safeExecuteWithState(
|
||||
() async {
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
return 'result';
|
||||
},
|
||||
loadingState: 'loading',
|
||||
successState: (result) => 'success: $result',
|
||||
errorState: (error) => 'error: $error',
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> testSafeExecuteWithState() async {
|
||||
return await safeExecuteWithState<String>(
|
||||
() async => 'result',
|
||||
loadingState: TestState(value: 'loading'),
|
||||
successState: (result) => TestState(value: result),
|
||||
errorState: (error) => TestState(value: 'error'),
|
||||
Future<String?> executeFailingOperation() async {
|
||||
return await safeExecute(() async {
|
||||
throw Exception('Test error');
|
||||
});
|
||||
}
|
||||
|
||||
Future<String?> executeFailingOperationWithState() async {
|
||||
return await safeExecuteWithState(
|
||||
() async {
|
||||
throw Exception('Test error');
|
||||
},
|
||||
loadingState: 'loading',
|
||||
successState: (result) => 'success: $result',
|
||||
errorState: (error) => 'error: $error',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('BaseCubit', () {
|
||||
late TestCubit testCubit;
|
||||
late TestCubit cubit;
|
||||
|
||||
setUp(() {
|
||||
testCubit = TestCubit();
|
||||
cubit = TestCubit();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (!testCubit.isClosed) {
|
||||
await testCubit.close();
|
||||
}
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('handleError - обрабатывает ошибку без исключений', () {
|
||||
expect(() => testCubit.testHandleError(Exception('Test error')), returnsNormally);
|
||||
test('initial state is set correctly', () {
|
||||
expect(cubit.state, 'initial');
|
||||
});
|
||||
|
||||
test('safeExecute - успешно выполняет операцию', () async {
|
||||
final result = await testCubit.testSafeExecute();
|
||||
test('setState updates state', () {
|
||||
cubit.setState('new state');
|
||||
expect(cubit.state, 'new state');
|
||||
});
|
||||
|
||||
test('safeExecute returns result on success', () async {
|
||||
final result = await cubit.executeOperation();
|
||||
expect(result, 'success');
|
||||
});
|
||||
|
||||
test('safeExecute - возвращает null при ошибке', () async {
|
||||
final result = await testCubit.testSafeExecuteWithError();
|
||||
|
||||
test('safeExecute returns null on error', () async {
|
||||
final result = await cubit.executeFailingOperation();
|
||||
expect(result, isNull);
|
||||
});
|
||||
|
||||
test('safeExecuteWithState - устанавливает состояния правильно', () async {
|
||||
final result = await testCubit.testSafeExecuteWithState();
|
||||
test('safeExecuteWithState emits loading then success state', () async {
|
||||
expectLater(
|
||||
cubit.stream,
|
||||
emitsInOrder([
|
||||
'loading',
|
||||
predicate<String>((state) => state.contains('success')),
|
||||
]),
|
||||
);
|
||||
|
||||
expect(result, 'result');
|
||||
expect(testCubit.state.value, 'result');
|
||||
await cubit.executeOperationWithState();
|
||||
});
|
||||
|
||||
test('safeExecuteWithState emits loading then error state on failure', () async {
|
||||
expectLater(
|
||||
cubit.stream,
|
||||
emitsInOrder([
|
||||
'loading',
|
||||
predicate<String>((state) => state.contains('error')),
|
||||
]),
|
||||
);
|
||||
|
||||
await cubit.executeFailingOperationWithState();
|
||||
});
|
||||
|
||||
test('safeExecuteWithState returns null on error', () async {
|
||||
final result = await cubit.executeFailingOperationWithState();
|
||||
expect(result, isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
22
test/core/cubit/marketing/marketing_cubit_state_test.dart
Normal file
22
test/core/cubit/marketing/marketing_cubit_state_test.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:eatvio_app/core/cubit/marketing/marketing_cubit_state.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('MarketingCubitState', () {
|
||||
test('creates state with const constructor', () {
|
||||
const state = MarketingCubitState();
|
||||
|
||||
expect(state, isA<MarketingCubitState>());
|
||||
});
|
||||
|
||||
test('can create multiple instances', () {
|
||||
const state1 = MarketingCubitState();
|
||||
const state2 = MarketingCubitState();
|
||||
|
||||
expect(state1, isA<MarketingCubitState>());
|
||||
expect(state2, isA<MarketingCubitState>());
|
||||
expect(state1 == state2, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,94 +5,109 @@ import 'package:eatvio_app/core/prefs_keys.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'marketing_cubit_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<Prefs>()])
|
||||
@GenerateMocks([Prefs])
|
||||
void main() {
|
||||
group('MarketingCubit', () {
|
||||
late MarketingCubit marketingCubit;
|
||||
late MockPrefs mockPrefs;
|
||||
late MarketingCubit cubit;
|
||||
|
||||
setUp(() async {
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
setUp(() {
|
||||
mockPrefs = MockPrefs();
|
||||
marketingCubit = MarketingCubit(mockPrefs);
|
||||
cubit = MarketingCubit(mockPrefs);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (!marketingCubit.isClosed) {
|
||||
await marketingCubit.close();
|
||||
}
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('начальное состояние - MarketingCubitState', () {
|
||||
expect(marketingCubit.state, const MarketingCubitState());
|
||||
test('initial state is MarketingCubitState', () {
|
||||
expect(cubit.state, isA<MarketingCubitState>());
|
||||
});
|
||||
|
||||
test('checkRegistrationDate - возвращает false если registrationDate отсутствует', () async {
|
||||
test('returns false when registration date is null', () async {
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate)).thenReturn(null);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.thenReturn(false);
|
||||
|
||||
final result = await marketingCubit.checkRegistrationDate();
|
||||
final result = await cubit.checkRegistrationDate();
|
||||
|
||||
expect(result, isFalse);
|
||||
expect(result, false);
|
||||
verify(mockPrefs.getInt(PrefsKeys.registrationDate)).called(1);
|
||||
});
|
||||
|
||||
test('checkRegistrationDate - возвращает false если маркетинговый bottom sheet уже был показан', () async {
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate)).thenReturn(DateTime.now().millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).thenReturn(true);
|
||||
test('returns false when marketing bottom sheet has been shown', () async {
|
||||
final now = DateTime.now();
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate))
|
||||
.thenReturn(now.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.thenReturn(true);
|
||||
|
||||
final result = await marketingCubit.checkRegistrationDate();
|
||||
final result = await cubit.checkRegistrationDate();
|
||||
|
||||
expect(result, isFalse);
|
||||
expect(result, false);
|
||||
verify(mockPrefs.getInt(PrefsKeys.registrationDate)).called(1);
|
||||
verify(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).called(1);
|
||||
verify(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test('checkRegistrationDate - возвращает false если прошло менее 14 дней', () async {
|
||||
final registrationDate = DateTime.now().subtract(const Duration(days: 10));
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate)).thenReturn(registrationDate.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).thenReturn(false);
|
||||
test('returns false when less than 14 days have passed', () async {
|
||||
final date = DateTime.now().subtract(const Duration(days: 10));
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate))
|
||||
.thenReturn(date.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.thenReturn(false);
|
||||
|
||||
final result = await marketingCubit.checkRegistrationDate();
|
||||
final result = await cubit.checkRegistrationDate();
|
||||
|
||||
expect(result, isFalse);
|
||||
expect(result, false);
|
||||
verify(mockPrefs.getInt(PrefsKeys.registrationDate)).called(1);
|
||||
verify(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).called(1);
|
||||
verifyNever(mockPrefs.setBool(any, any));
|
||||
verify(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test('checkRegistrationDate - возвращает true если прошло 14 дней или больше', () async {
|
||||
final registrationDate = DateTime.now().subtract(const Duration(days: 14));
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate)).thenReturn(registrationDate.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).thenReturn(false);
|
||||
when(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true)).thenAnswer((_) async => Future.value());
|
||||
test('returns true and sets flag when 14 or more days have passed', () async {
|
||||
final date = DateTime.now().subtract(const Duration(days: 14));
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate))
|
||||
.thenReturn(date.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.thenReturn(false);
|
||||
when(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
final result = await marketingCubit.checkRegistrationDate();
|
||||
final result = await cubit.checkRegistrationDate();
|
||||
|
||||
expect(result, isTrue);
|
||||
expect(result, true);
|
||||
verify(mockPrefs.getInt(PrefsKeys.registrationDate)).called(1);
|
||||
verify(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).called(1);
|
||||
verify(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true)).called(1);
|
||||
verify(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.called(1);
|
||||
verify(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test('checkRegistrationDate - устанавливает флаг после показа bottom sheet', () async {
|
||||
final registrationDate = DateTime.now().subtract(const Duration(days: 15));
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate)).thenReturn(registrationDate.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown)).thenReturn(false);
|
||||
when(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true)).thenAnswer((_) async => Future.value());
|
||||
test('returns true when more than 14 days have passed', () async {
|
||||
final date = DateTime.now().subtract(const Duration(days: 20));
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate))
|
||||
.thenReturn(date.millisecondsSinceEpoch);
|
||||
when(mockPrefs.getBool(PrefsKeys.marketingBottomSheetHasBeenShown))
|
||||
.thenReturn(false);
|
||||
when(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
await marketingCubit.checkRegistrationDate();
|
||||
final result = await cubit.checkRegistrationDate();
|
||||
|
||||
verify(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true)).called(1);
|
||||
expect(result, true);
|
||||
verify(mockPrefs.setBool(PrefsKeys.marketingBottomSheetHasBeenShown, true))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test('checkRegistrationDate - пробрасывает исключение', () async {
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate)).thenThrow(Exception('Ошибка чтения'));
|
||||
test('rethrows exception when error occurs', () async {
|
||||
when(mockPrefs.getInt(PrefsKeys.registrationDate))
|
||||
.thenThrow(Exception('Test error'));
|
||||
|
||||
expect(() => marketingCubit.checkRegistrationDate(), throwsException);
|
||||
expect(() => cubit.checkRegistrationDate(), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
64
test/core/cubit/state_utils_test.dart
Normal file
64
test/core/cubit/state_utils_test.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:eatvio_app/core/cubit/state_utils.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('StateUtils', () {
|
||||
test('isLoading returns true for loading state', () {
|
||||
expect(StateUtils.isLoading('loading'), isTrue);
|
||||
expect(StateUtils.isLoading('Loading'), isTrue);
|
||||
expect(StateUtils.isLoading('StateLoading'), isTrue);
|
||||
expect(StateUtils.isLoading('state_loading'), isTrue);
|
||||
});
|
||||
|
||||
test('isLoading returns false for non-loading state', () {
|
||||
expect(StateUtils.isLoading('loaded'), isFalse);
|
||||
expect(StateUtils.isLoading('error'), isFalse);
|
||||
expect(StateUtils.isLoading('success'), isFalse);
|
||||
});
|
||||
|
||||
test('isLoaded returns true for loaded state', () {
|
||||
expect(StateUtils.isLoaded('loaded'), isTrue);
|
||||
expect(StateUtils.isLoaded('Loaded'), isTrue);
|
||||
expect(StateUtils.isLoaded('StateLoaded'), isTrue);
|
||||
expect(StateUtils.isLoaded('state_loaded'), isTrue);
|
||||
});
|
||||
|
||||
test('isLoaded returns false for non-loaded state', () {
|
||||
expect(StateUtils.isLoaded('loading'), isFalse);
|
||||
expect(StateUtils.isLoaded('error'), isFalse);
|
||||
expect(StateUtils.isLoaded('initial'), isFalse);
|
||||
});
|
||||
|
||||
test('isError returns true for error state', () {
|
||||
expect(StateUtils.isError('error'), isTrue);
|
||||
expect(StateUtils.isError('Error'), isTrue);
|
||||
expect(StateUtils.isError('StateError'), isTrue);
|
||||
expect(StateUtils.isError('state_error'), isTrue);
|
||||
});
|
||||
|
||||
test('isError returns false for non-error state', () {
|
||||
expect(StateUtils.isError('loading'), isFalse);
|
||||
expect(StateUtils.isError('loaded'), isFalse);
|
||||
expect(StateUtils.isError('success'), isFalse);
|
||||
});
|
||||
|
||||
test('getErrorMessage returns null for non-error state', () {
|
||||
expect(StateUtils.getErrorMessage('loading'), isNull);
|
||||
expect(StateUtils.getErrorMessage('loaded'), isNull);
|
||||
expect(StateUtils.getErrorMessage('success'), isNull);
|
||||
});
|
||||
|
||||
test('getErrorMessage extracts error message from error state', () {
|
||||
final errorState = 'error: Something went wrong';
|
||||
final message = StateUtils.getErrorMessage(errorState);
|
||||
expect(message, isNotNull);
|
||||
expect(message, contains('Something'));
|
||||
});
|
||||
|
||||
test('getErrorMessage handles various error state formats', () {
|
||||
expect(StateUtils.getErrorMessage('error: test'), isNotNull);
|
||||
expect(StateUtils.getErrorMessage('Error: test message'), isNotNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user