Files
reelbox/test/home_banner_widget_test.dart
T

191 lines
6.7 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:reelbox/app.dart';
import 'package:reelbox/data/api_service.dart';
import 'package:reelbox/data/models.dart';
import 'package:reelbox/state/app_state.dart';
import 'package:reelbox/ui/catalog.dart';
import 'package:shared_preferences/shared_preferences.dart';
class HomeBannerFixtureApi extends ApiService {
bool fail = false;
Completer<dynamic>? pending;
dynamic bannerResponse = {'banners': []};
int bannerCalls = 0;
@override
Future<dynamic> get(String path, {Map<String, dynamic>? query}) async {
if (path != 'banners/') return [];
bannerCalls++;
if (fail) throw const ApiException('Offline');
return pending == null ? bannerResponse : pending!.future;
}
@override
Future<void> initialize({bool discover = true}) async {}
@override
Future<Map<String, dynamic>> home() async {
if (fail) throw const ApiException('Offline');
return {'genres': [], 'actors': [], 'countries': []};
}
@override
Future<List<Map<String, dynamic>>> actors({
int page = 1,
String search = '',
}) async => [];
@override
Future<List<Tag>> countries() async => [];
@override
Future<List<Tag>> genres() async => [];
}
Future<AppState> mountBannerHome(
WidgetTester tester,
HomeBannerFixtureApi api, {
String locale = 'en',
}) async {
SharedPreferences.setMockInitialValues({});
final state = AppState(
api: api,
storage: await SharedPreferences.getInstance(),
);
await state.initialize(discover: false);
await state.updateSettings(
state.prefs.copyWith(locale: locale, introCompleted: true),
);
await tester.pumpWidget(MyApp(state: state));
await tester.pumpAndSettle();
return state;
}
void main() {
testWidgets(
'pending config keeps Telegram then labels bilingual ads and honors data saver',
(tester) async {
tester.view.physicalSize = const Size(390, 844);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final api = HomeBannerFixtureApi()..pending = Completer<dynamic>();
final state = await mountBannerHome(tester, api);
expect(find.text('ReelBox updates'), findsOneWidget);
expect(find.text('Advertisement'), findsNothing);
api.pending!.complete({
'banners': [
{
'title_en': 'Fixture sponsor',
'title_fa': 'حامی آزمایشی',
'target_url': 'https://sponsor.example/offer',
'image_url': 'https://sponsor.example/banner.jpg',
},
],
});
await tester.pumpAndSettle();
expect(find.text('Advertisement'), findsOneWidget);
expect(find.text('Fixture sponsor'), findsOneWidget);
expect(find.byType(Image), findsOneWidget);
expect(find.text('ReelBox updates'), findsOneWidget);
final launches = <String>[];
const channel = MethodChannel('plugins.flutter.io/url_launcher');
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
call,
) async {
launches.add(call.arguments['url'] as String);
return true;
});
addTearDown(
() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
null,
),
);
await tester.tap(find.byKey(const Key('home-banner-ad-1')));
await tester.pumpAndSettle();
expect(launches, ['https://sponsor.example/offer']);
await state.updateSettings(
state.prefs.copyWith(locale: 'fa', dataSaver: true),
);
await tester.pumpAndSettle();
expect(find.text('تبلیغات'), findsOneWidget);
expect(find.text('حامی آزمایشی'), findsOneWidget);
expect(find.byType(Image), findsNothing);
expect(tester.takeException(), isNull);
await tester.pumpWidget(const SizedBox());
state.dispose();
},
);
testWidgets(
'failed external launch shows safe error and keeps official banner',
(tester) async {
const channel = MethodChannel('plugins.flutter.io/url_launcher');
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
(_) async => false,
);
addTearDown(
() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
null,
),
);
final state = await mountBannerHome(tester, HomeBannerFixtureApi());
await tester.tap(find.byKey(const Key('home-banner-telegram')));
await tester.pump();
expect(find.text('Could not open this link'), findsOneWidget);
expect(find.text('ReelBox updates'), findsOneWidget);
expect(tester.takeException(), isNull);
await tester.pumpWidget(const SizedBox());
state.dispose();
},
);
testWidgets(
'home Telegram is immediately clickable through API failure in both languages',
(tester) async {
tester.view.physicalSize = const Size(390, 844);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final launches = <MethodCall>[];
const channel = MethodChannel('plugins.flutter.io/url_launcher');
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
call,
) async {
launches.add(call);
return true;
});
addTearDown(
() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
null,
),
);
final api = HomeBannerFixtureApi()..fail = true;
final state = await mountBannerHome(tester, api);
expect(find.byType(DiscoverPage), findsOneWidget);
expect(find.text('ReelBox updates'), findsOneWidget);
expect(find.text('Updates and announcements'), findsOneWidget);
expect(find.text('Offline'), findsWidgets);
await tester.tap(find.byKey(const Key('home-banner-telegram')));
await tester.pumpAndSettle();
expect(launches.single.method, 'launch');
expect(launches.single.arguments['url'], 'https://t.me/ReelBoxApp');
expect(launches.single.arguments['useWebView'], false);
await state.updateSettings(state.prefs.copyWith(locale: 'fa'));
await tester.pumpAndSettle();
expect(find.text('تازه‌های ریل‌باکس'), findsOneWidget);
expect(find.text('به‌روزرسانی‌ها و اطلاعیه‌ها'), findsOneWidget);
expect(
Directionality.of(tester.element(find.text('تازه‌های ریل‌باکس'))),
TextDirection.rtl,
);
expect(tester.takeException(), isNull);
await tester.pumpWidget(const SizedBox());
state.dispose();
},
);
}