forked from eatvio/eatvio_app
fix: issue-942, issue-967, fixed images positioning for blog posts
This commit is contained in:
@@ -120,6 +120,29 @@ void main() {
|
||||
expect(find.text('Заблокировать автора'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CustomPopup for non-author admin hides complain but keeps block', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
const CustomPopup(
|
||||
isAuthor: false,
|
||||
isAuthorAdmin: true,
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
path: 'plans/slug',
|
||||
slug: 'slug',
|
||||
userSlug: 'admin-user',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.more_horiz_rounded));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Скопировать ссылку'), findsOneWidget);
|
||||
expect(find.text('Поделиться'), findsOneWidget);
|
||||
expect(find.text('Пожаловаться'), findsNothing);
|
||||
expect(find.text('Заблокировать автора'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('CustomPopup for author recipe does not show edit action', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
|
||||
@@ -24,6 +24,7 @@ void main() {
|
||||
String? slug,
|
||||
int? id,
|
||||
bool? disableActions,
|
||||
bool isAuthorAdmin = false,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
@@ -42,6 +43,7 @@ void main() {
|
||||
slug: slug,
|
||||
id: id,
|
||||
disableActions: disableActions,
|
||||
isAuthorAdmin: isAuthorAdmin,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -71,7 +73,23 @@ void main() {
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(MoreOptions), findsOneWidget);
|
||||
expect(find.text('Пожаловаться'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('hides complain option when author is admin', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: 1,
|
||||
slug: 'test-slug',
|
||||
isAuthorAdmin: true,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Пожаловаться'), findsNothing);
|
||||
expect(find.text('Скопировать ссылку'), findsOneWidget);
|
||||
expect(find.text('Поделиться'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('disables actions when disableActions is true', (tester) async {
|
||||
|
||||
@@ -56,6 +56,33 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('Author', () {
|
||||
test('fromJson читает author_roles и определяет админа', () {
|
||||
final author = Author.fromJson({
|
||||
'author_slug': 'admin-user',
|
||||
'author_name': 'Admin',
|
||||
'author_profile_icon': 'icon.jpg',
|
||||
'author_is_me': false,
|
||||
'author_roles': ['admin', 'consultant'],
|
||||
});
|
||||
|
||||
expect(author.authorRoles, ['admin', 'consultant']);
|
||||
expect(author.isAdmin, isTrue);
|
||||
});
|
||||
|
||||
test('fromJson без author_roles не считает автора админом', () {
|
||||
final author = Author.fromJson({
|
||||
'author_slug': 'regular-user',
|
||||
'author_name': 'User',
|
||||
'author_profile_icon': 'icon.jpg',
|
||||
'author_is_me': false,
|
||||
});
|
||||
|
||||
expect(author.authorRoles, isEmpty);
|
||||
expect(author.isAdmin, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('DietState', () {
|
||||
test('toString возвращает правильные значения', () {
|
||||
expect(DietState.active.toString(), 'active');
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:eatvio_app/features/feed/models/post_feed_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_media_content.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
void main() {
|
||||
const gallery = [
|
||||
FeedGalleryImage(
|
||||
url: 'https://example.com/a.jpg',
|
||||
orientation: 'horizontal',
|
||||
),
|
||||
FeedGalleryImage(url: 'https://example.com/b.jpg', orientation: 'vertical'),
|
||||
];
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
return MaterialApp(
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(size: Size(390, 844)),
|
||||
child: Scaffold(body: child),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
BlogPostMediaContent media({
|
||||
List<FeedGalleryImage> images = gallery,
|
||||
String imageUrl = '',
|
||||
}) {
|
||||
return BlogPostMediaContent(
|
||||
galleryImages: images,
|
||||
imageUrl: imageUrl,
|
||||
videoEmbedUrl: null,
|
||||
videoUrlThumb: null,
|
||||
currentGalleryIndex: 0,
|
||||
onOpenGallery: (_, _) {},
|
||||
onGalleryChanged: (_) {},
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('gallery slides use fitWidth so photos fill the card width', (
|
||||
tester,
|
||||
) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(media()));
|
||||
await tester.pump();
|
||||
|
||||
final images = tester.widgetList<CachedNetworkImage>(
|
||||
find.byType(CachedNetworkImage),
|
||||
);
|
||||
expect(images, isNotEmpty);
|
||||
for (final image in images) {
|
||||
expect(image.fit, BoxFit.fitWidth);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('single gallery image uses fitWidth without a forced height', (
|
||||
tester,
|
||||
) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(media(images: [gallery.first])));
|
||||
await tester.pump();
|
||||
|
||||
final image = tester.widget<CachedNetworkImage>(
|
||||
find.byType(CachedNetworkImage),
|
||||
);
|
||||
expect(image.fit, BoxFit.fitWidth);
|
||||
expect(image.height, isNull);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('cover-only image keeps fitWidth', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
media(images: const [], imageUrl: 'https://example.com/cover.jpg'),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
final image = tester.widget<CachedNetworkImage>(
|
||||
find.byType(CachedNetworkImage),
|
||||
);
|
||||
expect(image.fit, BoxFit.fitWidth);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
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/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/glossary/presentation/pages/glossary_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@@ -46,6 +47,7 @@ void main() {
|
||||
expect(find.byType(GlossaryScreen), findsOneWidget);
|
||||
expect(find.byType(Scaffold), findsOneWidget);
|
||||
expect(find.text('Глоссарий'), findsOneWidget);
|
||||
expect(find.byType(Loader), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('GlossaryScreen создается с правильным passKey', (WidgetTester tester) async {
|
||||
@@ -71,6 +73,66 @@ void main() {
|
||||
|
||||
expect(find.byType(GlossaryScreen), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('показывает стандартный лоадер при загрузке WebView', (WidgetTester tester) async {
|
||||
const passKey = 'test-pass-key';
|
||||
|
||||
final router = GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => const GlossaryScreen(passKey: passKey),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp.router(
|
||||
routerConfig: router,
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(Loader), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
group('shouldHideGlossaryLoader', () {
|
||||
test('не скрывает лоадер на странице login_with_pass_key', () {
|
||||
expect(
|
||||
shouldHideGlossaryLoader(
|
||||
url: 'https://eatvio.ru/login_with_pass_key?id=1',
|
||||
progress: 100,
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('не скрывает лоадер пока URL ещё не известен', () {
|
||||
expect(shouldHideGlossaryLoader(url: '', progress: 80), isFalse);
|
||||
});
|
||||
|
||||
test('не скрывает лоадер пока прогресс глоссария ниже порога', () {
|
||||
expect(
|
||||
shouldHideGlossaryLoader(
|
||||
url: 'https://eatvio.ru/product_nutritional_value',
|
||||
progress: 39,
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('скрывает лоадер когда страница глоссария уже начала отрисовываться', () {
|
||||
expect(
|
||||
shouldHideGlossaryLoader(
|
||||
url: 'https://eatvio.ru/product_nutritional_value',
|
||||
progress: 40,
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,11 @@ class FakePlatformNavigationDelegate extends PlatformNavigationDelegate {
|
||||
// No-op implementation for testing
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setOnProgress(dynamic params) async {
|
||||
// No-op implementation for testing
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setOnWebResourceError(dynamic params) async {
|
||||
// No-op implementation for testing
|
||||
|
||||
Reference in New Issue
Block a user