196 lines
6.7 KiB
Dart
196 lines
6.7 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:fruitshorts/core/data/models/drama.dart';
|
|
import 'package:fruitshorts/core/data/remote/api_client.dart';
|
|
import 'package:fruitshorts/core/data/remote/auth_api.dart';
|
|
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
|
|
import 'package:fruitshorts/core/data/services/auth_controller.dart';
|
|
import 'package:fruitshorts/core/data/services/auth_session_store.dart';
|
|
import 'package:fruitshorts/core/data/services/favorite_controller.dart';
|
|
import 'package:fruitshorts/core/platform/haptics.dart';
|
|
import 'package:fruitshorts/core/theme/app_colors.dart';
|
|
import 'package:fruitshorts/core/widgets/empty_state.dart';
|
|
import 'package:fruitshorts/l10n/app_localizations.dart';
|
|
import 'package:fruitshorts/pages/favorites/favorites_page.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
|
|
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
|
|
|
|
import '../support/fake_http_adapter.dart';
|
|
import '../support/fake_haptics.dart';
|
|
|
|
Drama _card(String id) => Drama(
|
|
id: id,
|
|
title: 'Drama $id',
|
|
synopsis: 'synopsis',
|
|
posterUrl: '/files/$id.png',
|
|
totalEpisodes: 12,
|
|
);
|
|
|
|
void main() {
|
|
setUp(() {
|
|
SharedPreferencesAsyncPlatform.instance =
|
|
InMemorySharedPreferencesAsync.empty();
|
|
});
|
|
|
|
testWidgets('should_render_favorite_cards_and_visible_remove_action', (
|
|
tester,
|
|
) async {
|
|
final auth = await _auth(signedIn: true);
|
|
final favorites = FavoriteController(
|
|
InMemoryFavoriteRepository(
|
|
saved: {'signal', 'city'},
|
|
cards: [_card('signal'), _card('city')],
|
|
),
|
|
);
|
|
|
|
await _pumpPage(tester, auth: auth, favorites: favorites);
|
|
|
|
expect(find.byKey(const Key('favorites-page')), findsOneWidget);
|
|
expect(find.byKey(const Key('favorites-back')), findsOneWidget);
|
|
expect(
|
|
tester.widget<Text>(find.byKey(const Key('favorites-count'))).data,
|
|
'2 favorites',
|
|
);
|
|
expect(find.text('Long press a card to remove'), findsNothing);
|
|
expect(find.text('Drama signal'), findsOneWidget);
|
|
expect(find.text('Drama city'), findsOneWidget);
|
|
final title = tester.widget<Text>(
|
|
find.byKey(const Key('favorite-title-signal')),
|
|
);
|
|
expect(title.style?.color, AppColors.onSurface);
|
|
expect(title.style?.fontSize, 15);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('favorite-cover-signal'))),
|
|
const Size(80, 106),
|
|
);
|
|
expect(find.byKey(const Key('favorite-remove-signal')), findsOneWidget);
|
|
expect(
|
|
tester.getSize(find.byKey(const Key('favorite-remove-signal'))),
|
|
const Size(28, 28),
|
|
);
|
|
expect(find.byIcon(Icons.star_rounded), findsNWidgets(2));
|
|
expect(find.byIcon(Icons.favorite_rounded), findsNothing);
|
|
final refresh = tester.widget<RefreshIndicator>(
|
|
find.byType(RefreshIndicator),
|
|
);
|
|
expect(refresh.color, AppColors.blue);
|
|
expect(refresh.backgroundColor, AppColors.card);
|
|
expect(refresh.strokeWidth, 2);
|
|
|
|
await tester.tap(find.byKey(const Key('favorite-remove-signal')));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('favorite-card-signal')), findsNothing);
|
|
});
|
|
|
|
testWidgets('should_keep_card_and_show_failure_when_remove_fails', (
|
|
tester,
|
|
) async {
|
|
final auth = await _auth(signedIn: true);
|
|
final repository = InMemoryFavoriteRepository(
|
|
saved: {'signal'},
|
|
cards: [_card('signal')],
|
|
)..failRemove = true;
|
|
final favorites = FavoriteController(repository);
|
|
final haptics = FakeHaptics();
|
|
|
|
await _pumpPage(tester, auth: auth, favorites: favorites, haptics: haptics);
|
|
await tester.tap(find.byKey(const Key('favorite-remove-signal')));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(haptics.lightImpacts, 1);
|
|
expect(find.text('Drama signal'), findsOneWidget);
|
|
expect(
|
|
find.text('Could not update favorites. Please retry.'),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
|
|
testWidgets('should_show_empty_state_when_favorite_list_is_empty', (
|
|
tester,
|
|
) async {
|
|
final auth = await _auth(signedIn: true);
|
|
final favorites = FavoriteController(InMemoryFavoriteRepository());
|
|
|
|
await _pumpPage(tester, auth: auth, favorites: favorites);
|
|
|
|
expect(find.byKey(const Key('favorites-empty')), findsOneWidget);
|
|
expect(find.byType(EmptyState), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('should_show_retry_when_favorite_list_fails', (tester) async {
|
|
final auth = await _auth(signedIn: true);
|
|
final repository = InMemoryFavoriteRepository()..failList = true;
|
|
final favorites = FavoriteController(repository);
|
|
|
|
await _pumpPage(tester, auth: auth, favorites: favorites);
|
|
|
|
expect(find.byKey(const Key('favorites-error')), findsOneWidget);
|
|
expect(find.byKey(const Key('favorites-retry')), findsOneWidget);
|
|
});
|
|
|
|
testWidgets(
|
|
'should_show_auth_gate_without_loading_favorites_when_signed_out',
|
|
(tester) async {
|
|
final auth = await _auth(signedIn: false);
|
|
final repository = InMemoryFavoriteRepository(
|
|
saved: {'signal'},
|
|
cards: [_card('signal')],
|
|
);
|
|
final favorites = FavoriteController(repository);
|
|
|
|
await _pumpPage(tester, auth: auth, favorites: favorites);
|
|
|
|
expect(find.byKey(const Key('auth-gate-panel')), findsOneWidget);
|
|
expect(repository.listCalls, 0);
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<AuthController> _auth({required bool signedIn}) async {
|
|
if (signedIn) {
|
|
SharedPreferencesAsyncPlatform.instance =
|
|
InMemorySharedPreferencesAsync.withData({
|
|
'auth.accessToken': 'test-access',
|
|
'auth.refreshToken': 'test-refresh',
|
|
'auth.user': '{"uid":"1","nickname":"Viewer","avatarUrl":""}',
|
|
});
|
|
}
|
|
final client = ApiClient(
|
|
baseUrl: 'http://127.0.0.1:8081',
|
|
adapter: FakeHttpAdapter(
|
|
(_) async => FakeHttpResponse('{"code":0,"message":"ok","data":null}'),
|
|
),
|
|
);
|
|
final auth = AuthController(AuthApi(client), AuthSessionStore());
|
|
await auth.load();
|
|
return auth;
|
|
}
|
|
|
|
Future<void> _pumpPage(
|
|
WidgetTester tester, {
|
|
required AuthController auth,
|
|
required FavoriteController favorites,
|
|
FakeHaptics? haptics,
|
|
}) async {
|
|
await tester.pumpWidget(
|
|
MultiProvider(
|
|
providers: [
|
|
ChangeNotifierProvider<AuthController>.value(value: auth),
|
|
ChangeNotifierProvider<FavoriteController>.value(value: favorites),
|
|
Provider<Haptics>.value(value: haptics ?? FakeHaptics()),
|
|
],
|
|
child: MaterialApp(
|
|
locale: const Locale('en'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: const FavoritesPage(),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
}
|