feat(flutter): 接入分类记录收藏与下载授权
This commit is contained in:
1 parent
00280ca0da
commit
cc4d7c5a9d
52 files changed
+4440
-171
No files matched your search
@@ -0,0 +1,179 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/core/data/models/content_category.dart';
|
||||
import 'package:fruitshorts/core/data/models/drama.dart';
|
||||
import 'package:fruitshorts/core/data/models/home_feed.dart';
|
||||
import 'package:fruitshorts/core/data/remote/api_client.dart';
|
||||
import 'package:fruitshorts/core/data/remote/category_api.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/category_repository.dart';
|
||||
import 'package:fruitshorts/core/data/services/category_controller.dart';
|
||||
|
||||
import '../support/fake_http_adapter.dart';
|
||||
|
||||
Drama _drama(String id) => Drama(
|
||||
id: id,
|
||||
title: 'Drama $id',
|
||||
synopsis: 'synopsis',
|
||||
posterUrl: '/files/$id.png',
|
||||
);
|
||||
|
||||
void main() {
|
||||
test(
|
||||
'should_keep_snowflake_category_id_as_string_when_api_returns_list',
|
||||
() async {
|
||||
const id = '2111012753262120962';
|
||||
final adapter = FakeHttpAdapter(
|
||||
(_) async => FakeHttpResponse(
|
||||
jsonEncode({
|
||||
'code': 0,
|
||||
'message': 'ok',
|
||||
'data': [
|
||||
{'id': id, 'name': 'Romance'},
|
||||
],
|
||||
}),
|
||||
),
|
||||
);
|
||||
final client = ApiClient(
|
||||
baseUrl: 'http://127.0.0.1:8081',
|
||||
adapter: adapter,
|
||||
);
|
||||
|
||||
final categories = await CategoryApi(client).list();
|
||||
|
||||
expect(categories.single.id, id);
|
||||
expect(categories.single.name, 'Romance');
|
||||
expect(adapter.requests.single.uri.path, '/app/categories');
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'should_map_category_id_to_discover_section_when_category_is_selected',
|
||||
() async {
|
||||
final repository = ScriptedCategoryRepository(
|
||||
categories: const [
|
||||
ContentCategory(id: '7', name: 'Romance'),
|
||||
ContentCategory(id: '8', name: 'Action'),
|
||||
],
|
||||
feed: HomeFeed(
|
||||
sections: [
|
||||
FeedSection(code: 'hot', title: 'Hot', dramas: [_drama('hot-1')]),
|
||||
FeedSection(code: 'new', title: 'New', dramas: [_drama('new-1')]),
|
||||
FeedSection(
|
||||
code: 'category-7',
|
||||
title: 'Romance',
|
||||
dramas: [_drama('romance-1')],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final controller = CategoryController(repository);
|
||||
|
||||
await controller.load();
|
||||
controller.selectCategory('7');
|
||||
|
||||
expect(controller.selectedCode, 'category-7');
|
||||
expect(controller.visibleDramas.map((drama) => drama.id), ['romance-1']);
|
||||
expect(controller.selectedSectionMissing, isFalse);
|
||||
|
||||
controller.selectCategory('8');
|
||||
expect(controller.selectedCode, 'category-8');
|
||||
expect(controller.visibleDramas, isEmpty);
|
||||
expect(controller.selectedSectionMissing, isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'should_keep_hot_and_new_entries_when_discover_feed_provides_them',
|
||||
() async {
|
||||
final repository = ScriptedCategoryRepository(
|
||||
feed: HomeFeed(
|
||||
sections: [
|
||||
FeedSection(code: 'hot', title: 'Hot', dramas: [_drama('hot-1')]),
|
||||
FeedSection(code: 'new', title: 'New', dramas: [_drama('new-1')]),
|
||||
FeedSection(
|
||||
code: 'category-7',
|
||||
title: 'Romance',
|
||||
dramas: [_drama('romance-1')],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final controller = CategoryController(repository);
|
||||
|
||||
await controller.load();
|
||||
controller.selectCode(CategoryController.hotCode);
|
||||
expect(controller.visibleDramas.map((drama) => drama.id), ['hot-1']);
|
||||
|
||||
controller.selectCode(CategoryController.newCode);
|
||||
expect(controller.visibleDramas.map((drama) => drama.id), ['new-1']);
|
||||
},
|
||||
);
|
||||
|
||||
test('should_dedupe_dramas_when_all_categories_are_selected', () async {
|
||||
final repository = ScriptedCategoryRepository(
|
||||
feed: HomeFeed(
|
||||
sections: [
|
||||
FeedSection(code: 'hot', title: 'Hot', dramas: [_drama('same')]),
|
||||
FeedSection(
|
||||
code: 'category-7',
|
||||
title: 'Romance',
|
||||
dramas: [_drama('same'), _drama('other')],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final controller = CategoryController(repository);
|
||||
|
||||
await controller.load();
|
||||
|
||||
expect(controller.selectedCode, CategoryController.allCode);
|
||||
expect(controller.visibleDramas.map((drama) => drama.id), [
|
||||
'same',
|
||||
'other',
|
||||
]);
|
||||
});
|
||||
|
||||
test('should_clear_error_and_retry_when_initial_load_fails', () async {
|
||||
final repository = ScriptedCategoryRepository(fail: true);
|
||||
final controller = CategoryController(repository);
|
||||
|
||||
await controller.load();
|
||||
expect(controller.error, 'categoriesError');
|
||||
expect(controller.loading, isFalse);
|
||||
|
||||
repository.fail = false;
|
||||
await controller.load();
|
||||
|
||||
expect(controller.error, isNull);
|
||||
expect(repository.loads, 2);
|
||||
});
|
||||
}
|
||||
|
||||
class ScriptedCategoryRepository implements CategoryRepository {
|
||||
ScriptedCategoryRepository({
|
||||
this.categories = const [],
|
||||
this.feed = const HomeFeed(),
|
||||
this.fail = false,
|
||||
});
|
||||
|
||||
List<ContentCategory> categories;
|
||||
HomeFeed feed;
|
||||
bool fail;
|
||||
int loads = 0;
|
||||
|
||||
@override
|
||||
Future<List<ContentCategory>> fetchCategories() async {
|
||||
loads++;
|
||||
if (fail) throw StateError('offline');
|
||||
return categories;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HomeFeed> fetchDiscoverFeed() async {
|
||||
if (fail) throw StateError('offline');
|
||||
return feed;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user