refactor(api): 统一响应解析并修复下载错误文案空白
各 *Api 类此前各自实现 data 结构判断,download_api 在结构异常时抛出空 message,界面会显示空白提示。抽出 ResponseDecoders 提供对象、可空对象、 对象数组三种语义,七个文件改为复用;下载侧异常文案与其他接口对齐。
This commit is contained in:
1 parent
70be941755
commit
1be8ebf1f9
9 files changed
+188
-67
No files matched your search
@@ -0,0 +1,87 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/core/data/remote/api_client.dart';
|
||||
import 'package:fruitshorts/core/data/remote/download_api.dart';
|
||||
import 'package:fruitshorts/core/data/remote/response_decoders.dart';
|
||||
|
||||
import '../support/fake_http_adapter.dart';
|
||||
|
||||
void main() {
|
||||
group('ResponseDecoders', () {
|
||||
test('should_return_same_map_when_data_is_object', () {
|
||||
const source = {'id': '1'};
|
||||
expect(ResponseDecoders.asMap(source), same(source));
|
||||
});
|
||||
|
||||
test('should_throw_with_readable_message_when_data_is_not_object', () {
|
||||
expect(
|
||||
() => ResponseDecoders.asMap(const []),
|
||||
throwsA(
|
||||
isA<ApiException>()
|
||||
.having((e) => e.code, 'code', ResponseDecoders.malformedCode)
|
||||
.having(
|
||||
(e) => e.message,
|
||||
'message',
|
||||
ResponseDecoders.malformedMessage,
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(ResponseDecoders.malformedMessage, isNotEmpty);
|
||||
});
|
||||
|
||||
test('should_return_null_when_try_map_receives_non_object', () {
|
||||
expect(ResponseDecoders.tryMap(null), isNull);
|
||||
expect(ResponseDecoders.tryMap('text'), isNull);
|
||||
expect(ResponseDecoders.tryMap({'a': 1})?['a'], 1);
|
||||
});
|
||||
|
||||
test('should_skip_non_object_items_when_decoding_object_list', () {
|
||||
final decoded = ResponseDecoders.asMapList([
|
||||
{'id': '1'},
|
||||
'bad',
|
||||
{'id': '2'},
|
||||
]);
|
||||
expect(decoded.map((item) => item['id']), ['1', '2']);
|
||||
});
|
||||
|
||||
test('should_return_empty_list_when_data_is_not_list', () {
|
||||
expect(ResponseDecoders.asMapList(const {}), isEmpty);
|
||||
expect(ResponseDecoders.asMapList(null), isEmpty);
|
||||
});
|
||||
|
||||
test('should_throw_when_required_list_receives_non_list', () {
|
||||
expect(
|
||||
() => ResponseDecoders.requiredMapList(const {}),
|
||||
throwsA(isA<ApiException>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test(
|
||||
'should_raise_readable_error_when_download_policy_data_is_malformed',
|
||||
() async {
|
||||
final adapter = FakeHttpAdapter(
|
||||
(options) async => FakeHttpResponse(
|
||||
jsonEncode({'code': 0, 'message': 'ok', 'data': null}),
|
||||
),
|
||||
);
|
||||
final client = ApiClient(adapter: adapter);
|
||||
final api = DownloadApi(client);
|
||||
|
||||
await expectLater(
|
||||
api.policy(),
|
||||
throwsA(
|
||||
isA<ApiException>().having(
|
||||
(error) => error.message,
|
||||
'message',
|
||||
ResponseDecoders.malformedMessage,
|
||||
),
|
||||
),
|
||||
);
|
||||
client.close();
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user