forked from eatvio/eatvio_app
feat(tests): test coverage 60%
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chose_plan_date_widget.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/complete_plan_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/plan_complain_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class FakeChatRoomCubit extends Cubit<ChatRoomState> implements ChatRoomCubit {
|
||||
FakeChatRoomCubit(super.initialState);
|
||||
|
||||
bool finishResult = true;
|
||||
bool complainResult = true;
|
||||
|
||||
@override
|
||||
Future<bool> choseStartPlanDate(DateTime date) async => true;
|
||||
|
||||
@override
|
||||
Future<bool> finishChosenPlan() async => finishResult;
|
||||
|
||||
@override
|
||||
Future<bool> complainAboutConsultation({required String description}) async => complainResult;
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _FakeAssetBundle extends CachingAssetBundle {
|
||||
_FakeAssetBundle(this.assets);
|
||||
final Map<String, String> assets;
|
||||
|
||||
@override
|
||||
Future<String> loadString(String key, {bool cache = true}) async {
|
||||
final value = assets[key];
|
||||
if (value == null) throw FlutterError('Asset not found: $key');
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ByteData> load(String key) async {
|
||||
final value = assets[key];
|
||||
if (value == null) throw FlutterError('Asset not found: $key');
|
||||
return ByteData.sublistView(Uint8List.fromList(value.codeUnits));
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Chat bottom sheets smoke', () {
|
||||
const fakeSvg = '''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
|
||||
<rect width="10" height="10" fill="red"/>
|
||||
</svg>
|
||||
''';
|
||||
|
||||
final bundle = _FakeAssetBundle({'assets/icons/error_icon.svg': fakeSvg, 'assets/icons/question_mark.svg': fakeSvg});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
final router = GoRouter(
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (_, _) => Scaffold(body: SingleChildScrollView(child: child)),
|
||||
),
|
||||
],
|
||||
);
|
||||
return DefaultAssetBundle(
|
||||
bundle: bundle,
|
||||
child: Portal(
|
||||
child: MaterialApp.router(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
routerConfig: router,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('ChosePlanDateWidget renders', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading());
|
||||
await tester.pumpWidget(wrap(ChosePlanDateWidget(chatCubit: cubit, hasPersonalDiet: false)));
|
||||
await tester.pump();
|
||||
expect(find.text(S.current.confirm), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('ChosePlanDateWidget toggles tooltip when hasPersonalDiet', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading());
|
||||
await tester.pumpWidget(wrap(ChosePlanDateWidget(chatCubit: cubit, hasPersonalDiet: true)));
|
||||
await tester.pump();
|
||||
|
||||
|
||||
expect(find.text(S.current.chosenPlanStartDateDescr), findsOneWidget);
|
||||
await tester.tap(find.byType(GestureDetector).first);
|
||||
await tester.pump();
|
||||
expect(find.text(S.current.chosenPlanStartDateDescr), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CompletePlanBottomSheet shows failure UI when finish fails', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading())..finishResult = false;
|
||||
await tester.pumpWidget(wrap(CompletePlanBottomSheet(cubit: cubit)));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text(S.current.confirm));
|
||||
await tester.pump();
|
||||
expect(find.text('Произошла ошибка, попробуйте позже'), findsOneWidget);
|
||||
expect(find.text(S.current.ok), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CompletePlanBottomSheet closes on success', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading())..finishResult = true;
|
||||
final router = GoRouter(
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => Scaffold(
|
||||
body: Center(
|
||||
child: TextButton(onPressed: () => context.push('/sheet'), child: const Text('open')),
|
||||
),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/sheet',
|
||||
builder: (_, _) => Scaffold(
|
||||
body: SingleChildScrollView(child: CompletePlanBottomSheet(cubit: cubit)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
DefaultAssetBundle(
|
||||
bundle: bundle,
|
||||
child: Portal(
|
||||
child: MaterialApp.router(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
routerConfig: router,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('open'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CompletePlanBottomSheet), findsOneWidget);
|
||||
await tester.tap(find.text(S.current.confirm));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CompletePlanBottomSheet), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('PlanComplainBottomSheet validates text length', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading());
|
||||
await tester.pumpWidget(wrap(PlanComplainBottomSheet(cubit: cubit)));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text(S.current.confirm));
|
||||
await tester.pump();
|
||||
|
||||
await tester.enterText(find.byType(TextFormField), 'a');
|
||||
await tester.pump();
|
||||
expect(find.text(S.current.atLeast3Symbols), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('PlanComplainBottomSheet shows success UI when submit succeeds', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading())..complainResult = true;
|
||||
await tester.pumpWidget(wrap(PlanComplainBottomSheet(cubit: cubit)));
|
||||
await tester.pump();
|
||||
await tester.enterText(find.byType(TextFormField), 'abc');
|
||||
await tester.pump();
|
||||
await tester.tap(find.text(S.current.confirm));
|
||||
await tester.pump();
|
||||
expect(find.text('Жалоба отправлена на рассмотрение. Обычно это занимает до трёх рабочих дней.'), findsOneWidget);
|
||||
expect(find.text(S.current.ok), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('PlanComplainBottomSheet shows failure UI when submit fails', (tester) async {
|
||||
final cubit = FakeChatRoomCubit(const ChatRoomState.loading())..complainResult = false;
|
||||
await tester.pumpWidget(wrap(PlanComplainBottomSheet(cubit: cubit)));
|
||||
await tester.pump();
|
||||
await tester.enterText(find.byType(TextFormField), 'abc');
|
||||
await tester.pump();
|
||||
await tester.tap(find.text(S.current.confirm));
|
||||
await tester.pump();
|
||||
expect(find.text('Произошла ошибка, попробуйте позже'), findsOneWidget);
|
||||
expect(find.text(S.current.ok), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
class _FakeHttpClient implements HttpClient {
|
||||
bool _autoUncompress = true;
|
||||
|
||||
@override
|
||||
bool get autoUncompress => _autoUncompress;
|
||||
|
||||
@override
|
||||
set autoUncompress(bool value) {
|
||||
_autoUncompress = value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async => _FakeHttpClientRequest();
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _FakeHttpClientRequest implements HttpClientRequest {
|
||||
@override
|
||||
Future<HttpClientResponse> close() async => _FakeHttpClientResponse();
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _FakeHttpClientResponse extends Stream<List<int>> implements HttpClientResponse {
|
||||
|
||||
static final List<int> _png = <int>[
|
||||
0x89,
|
||||
0x50,
|
||||
0x4E,
|
||||
0x47,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x1A,
|
||||
0x0A,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x0D,
|
||||
0x49,
|
||||
0x48,
|
||||
0x44,
|
||||
0x52,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x08,
|
||||
0x06,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x1F,
|
||||
0x15,
|
||||
0xC4,
|
||||
0x89,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x0A,
|
||||
0x49,
|
||||
0x44,
|
||||
0x41,
|
||||
0x54,
|
||||
0x78,
|
||||
0x9C,
|
||||
0x63,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x05,
|
||||
0x00,
|
||||
0x01,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x2D,
|
||||
0xB4,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x49,
|
||||
0x45,
|
||||
0x4E,
|
||||
0x44,
|
||||
0xAE,
|
||||
0x42,
|
||||
0x60,
|
||||
0x82,
|
||||
];
|
||||
|
||||
@override
|
||||
int get statusCode => 200;
|
||||
|
||||
@override
|
||||
int get contentLength => _png.length;
|
||||
|
||||
@override
|
||||
HttpClientResponseCompressionState get compressionState => HttpClientResponseCompressionState.notCompressed;
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(void Function(List<int>)? onData, {Function? onError, void Function()? onDone, bool? cancelOnError}) {
|
||||
return Stream<List<int>>.fromIterable([_png]).listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _FakeAssetBundle extends CachingAssetBundle {
|
||||
_FakeAssetBundle(this.assets);
|
||||
final Map<String, String> assets;
|
||||
|
||||
@override
|
||||
Future<String> loadString(String key, {bool cache = true}) async {
|
||||
final value = assets[key];
|
||||
if (value == null) throw FlutterError('Asset not found: $key');
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ByteData> load(String key) async {
|
||||
final value = assets[key];
|
||||
if (value == null) throw FlutterError('Asset not found: $key');
|
||||
return ByteData.sublistView(Uint8List.fromList(value.codeUnits));
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('ChatBubbleWidget smoke', () {
|
||||
const fakeSvg = '''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
|
||||
<rect width="10" height="10" fill="red"/>
|
||||
</svg>
|
||||
''';
|
||||
|
||||
final bundle = _FakeAssetBundle({'assets/icons/error_icon.svg': fakeSvg});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
return DefaultAssetBundle(
|
||||
bundle: bundle,
|
||||
child: MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(size: Size(1200, 800)),
|
||||
child: Scaffold(body: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('renders with network image attachment', (tester) async {
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
tester.view.physicalSize = const Size(2000, 1200);
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
await HttpOverrides.runZoned(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
ChatBubbleWidget(
|
||||
sendTime: DateTime(2025, 1, 1, 10, 0),
|
||||
text: 'text',
|
||||
isCurrentUser: true,
|
||||
isRead: true,
|
||||
mediaData: const ['https://example.com/a.png'],
|
||||
messageState: MessageState.sent,
|
||||
messageUuid: 'u',
|
||||
userSlug: 'slug',
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(find.byType(ChatBubbleWidget), findsOneWidget);
|
||||
expect(find.text('text'), findsOneWidget);
|
||||
}, createHttpClient: (_) => _FakeHttpClient());
|
||||
});
|
||||
|
||||
testWidgets('renders error state icon for current user', (tester) async {
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
tester.view.physicalSize = const Size(2000, 1200);
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
ChatBubbleWidget(
|
||||
sendTime: DateTime(2025, 1, 1, 10, 0),
|
||||
text: 'tap to retry',
|
||||
isCurrentUser: true,
|
||||
isRead: true,
|
||||
mediaData: const [],
|
||||
messageState: MessageState.error,
|
||||
messageUuid: 'u',
|
||||
userSlug: 'slug',
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(find.byType(ChatBubbleWidget), findsOneWidget);
|
||||
expect(find.text('tap to retry'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import 'package:eatvio_app/core/app_config.dart';
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_entry_widget.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_search_bar_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
void main() {
|
||||
group('Chat list widgets smoke', () {
|
||||
setUpAll(() async {
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
|
||||
});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
final router = GoRouter(
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (_, _) => Scaffold(body: child),
|
||||
),
|
||||
GoRoute(path: '/chat', name: 'chatScreen', builder: (_, _) => const SizedBox.shrink()),
|
||||
],
|
||||
);
|
||||
return MaterialApp.router(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
routerConfig: router,
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('ChatSearchBarWidget clears text and calls onSuffixIconTap', (tester) async {
|
||||
final controller = TextEditingController(text: 'abc');
|
||||
var called = 0;
|
||||
|
||||
await tester.pumpWidget(wrap(ChatSearchBarWidget(controller: controller, hintText: 'Search', onSuffixIconTap: () => called++)));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
await tester.tap(find.byIcon(Icons.clear));
|
||||
await tester.pump();
|
||||
expect(controller.text, '');
|
||||
expect(called, 1);
|
||||
});
|
||||
|
||||
testWidgets('ChatEntryWidget renders unread badge and attachment preview', (tester) async {
|
||||
final chatRoom = ChatRoom(
|
||||
id: '1',
|
||||
lastMessage: ChatMessageModel(
|
||||
id: 1,
|
||||
data: 'ignored',
|
||||
mediaData: const ['chat_files/file.pdf'],
|
||||
authorId: 2,
|
||||
updatedAt: DateTime(2025, 1, 1),
|
||||
isRead: false,
|
||||
isCurrentUserAuthor: false,
|
||||
roomId: '1',
|
||||
),
|
||||
users: const Users(
|
||||
fromChatUser: ChatUser(id: 1, name: 'Me', profilePhotoPath: null, profilePhotoUrl: 'http://localhost/a.png'),
|
||||
toChatUser: ChatUser(id: 2, name: 'Other User', profilePhotoPath: null, profilePhotoUrl: 'http://localhost/b.png'),
|
||||
),
|
||||
unreadMessagesCount: 3,
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(ChatEntryWidget(chatRoom: chatRoom)));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(find.text('Other User'), findsOneWidget);
|
||||
expect(find.text('3'), findsOneWidget);
|
||||
expect(find.text('📎 Вложение'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/about_order_button.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/message_action_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/notification_banner.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
class _FakeAssetBundle extends CachingAssetBundle {
|
||||
_FakeAssetBundle(this.assets);
|
||||
final Map<String, String> assets;
|
||||
|
||||
@override
|
||||
Future<String> loadString(String key, {bool cache = true}) async {
|
||||
final value = assets[key];
|
||||
if (value == null) throw FlutterError('Asset not found: $key');
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ByteData> load(String key) async {
|
||||
final value = assets[key];
|
||||
if (value == null) throw FlutterError('Asset not found: $key');
|
||||
return ByteData.sublistView(Uint8List.fromList(value.codeUnits));
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Chat misc widgets smoke', () {
|
||||
const fakeSvg = '''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
|
||||
<rect width="10" height="10" fill="red"/>
|
||||
</svg>
|
||||
''';
|
||||
|
||||
final bundle = _FakeAssetBundle({
|
||||
'assets/icons/right_arrow.svg': fakeSvg,
|
||||
'assets/icons/resend.svg': fakeSvg,
|
||||
'assets/icons/trash_can.svg': fakeSvg,
|
||||
'assets/icons/reversed_exclamation_mark.svg': fakeSvg,
|
||||
'assets/icons/star.svg': fakeSvg,
|
||||
});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
return DefaultAssetBundle(
|
||||
bundle: bundle,
|
||||
child: MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(size: Size(500, 900)),
|
||||
child: Scaffold(body: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('AboutOrderButton renders and taps', (tester) async {
|
||||
var tapped = false;
|
||||
await tester.pumpWidget(wrap(AboutOrderButton(onTap: () => tapped = true)));
|
||||
await tester.pump();
|
||||
expect(find.byType(AboutOrderButton), findsOneWidget);
|
||||
await tester.tap(find.byType(AboutOrderButton));
|
||||
await tester.pump();
|
||||
expect(tapped, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('MessageActionsBottomSheet renders', (tester) async {
|
||||
await tester.pumpWidget(wrap(MessageActionsBottomSheet(resend: () {}, delete: () {})));
|
||||
await tester.pump();
|
||||
expect(find.byType(MessageActionsBottomSheet), findsOneWidget);
|
||||
expect(find.text(S.current.resend), findsOneWidget);
|
||||
expect(find.text(S.current.delete), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('NotificationBanner renders for multiple banner types', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
const SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
NotificationBanner(bannerType: BannerType.date, hasPersonalDiet: false),
|
||||
NotificationBanner(bannerType: BannerType.card),
|
||||
NotificationBanner(bannerType: BannerType.collectCharge, planName: 'Plan', planPrice: 100, chosenPlanId: 1),
|
||||
NotificationBanner(bannerType: BannerType.finishPlan, planName: 'Plan', planPrice: 100, chosenPlanId: 1),
|
||||
NotificationBanner(bannerType: BannerType.setPersonalDiet, hasPersonalDiet: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(find.byType(NotificationBanner), findsWidgets);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/core/app_config.dart';
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/order_card.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
class _FakeHttpClient implements HttpClient {
|
||||
bool _autoUncompress = true;
|
||||
|
||||
@override
|
||||
bool get autoUncompress => _autoUncompress;
|
||||
|
||||
@override
|
||||
set autoUncompress(bool value) {
|
||||
_autoUncompress = value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async => _FakeHttpClientRequest();
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _FakeHttpClientRequest implements HttpClientRequest {
|
||||
@override
|
||||
Future<HttpClientResponse> close() async => _FakeHttpClientResponse();
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class _FakeHttpClientResponse extends Stream<List<int>> implements HttpClientResponse {
|
||||
static final List<int> _png = <int>[
|
||||
0x89,
|
||||
0x50,
|
||||
0x4E,
|
||||
0x47,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x1A,
|
||||
0x0A,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x0D,
|
||||
0x49,
|
||||
0x48,
|
||||
0x44,
|
||||
0x52,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x08,
|
||||
0x06,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x1F,
|
||||
0x15,
|
||||
0xC4,
|
||||
0x89,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x0A,
|
||||
0x49,
|
||||
0x44,
|
||||
0x41,
|
||||
0x54,
|
||||
0x78,
|
||||
0x9C,
|
||||
0x63,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
0x05,
|
||||
0x00,
|
||||
0x01,
|
||||
0x0D,
|
||||
0x0A,
|
||||
0x2D,
|
||||
0xB4,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x49,
|
||||
0x45,
|
||||
0x4E,
|
||||
0x44,
|
||||
0xAE,
|
||||
0x42,
|
||||
0x60,
|
||||
0x82,
|
||||
];
|
||||
|
||||
@override
|
||||
int get statusCode => 200;
|
||||
|
||||
@override
|
||||
int get contentLength => _png.length;
|
||||
|
||||
@override
|
||||
HttpClientResponseCompressionState get compressionState => HttpClientResponseCompressionState.notCompressed;
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(void Function(List<int>)? onData, {Function? onError, void Function()? onDone, bool? cancelOnError}) {
|
||||
return Stream<List<int>>.fromIterable([_png]).listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('OrderCard smoke', () {
|
||||
setUpAll(() async {
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
|
||||
});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
home: Scaffold(body: SingleChildScrollView(child: child)),
|
||||
);
|
||||
}
|
||||
|
||||
const author = Author(
|
||||
authorSlug: 'a',
|
||||
authorName: 'Author',
|
||||
authorProfileIcon: 'http://localhost/a.png',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: false,
|
||||
authorPlaceInRating: 1,
|
||||
);
|
||||
|
||||
const plan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'slug',
|
||||
name: 'Plan',
|
||||
image: 'img.png',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: false, slim: false, behavior: false, wellness: false),
|
||||
details: '',
|
||||
packetsCount: 1,
|
||||
packet1Options: PacketOptions(items: ['a'], price: 100, short: 'S', description: '', hasPersonalDiet: false),
|
||||
packet2Options: null,
|
||||
packet3Options: null,
|
||||
author: author,
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
isFavorite: false,
|
||||
minPriceOfOptions: 100,
|
||||
maxPriceOfOptions: 100,
|
||||
wasLikedByMe: false,
|
||||
);
|
||||
|
||||
testWidgets('renders and runs cancel action', (tester) async {
|
||||
var cancelled = 0;
|
||||
await HttpOverrides.runZoned(() async {
|
||||
await tester.pumpWidget(wrap(OrderCard(plan: plan, isCustomerView: true, optionType: 'options1', onCancel: () async => cancelled++)));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(find.text('Plan'), findsOneWidget);
|
||||
expect(find.text(S.current.cancel_order), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text(S.current.cancel_order));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
expect(cancelled, 1);
|
||||
}, createHttpClient: (_) => _FakeHttpClient());
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user