You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

53 lines
2.1 KiB

import 'package:flutter_test/flutter_test.dart';
/// 守住 `Api.*` 返回值的解包口径。
///
/// 背景:`DioManager.request` 结尾是 `return response.data;` —— 返回的是**data 本身**,
/// 不是 Response。全仓既有调用方都直接下标取字段(`response['devices']`)。
///
/// 早先 MemoryService._data 写成了 `resp.data`。因为 request 的返回类型是 dynamic,
/// **编译和 dart analyze 都不报错**,而且后端没部署时返回 null,正好走空分支看不出来;
/// 一旦后端真的返回成功,每一次调用都会抛 NoSuchMethodError。
///
/// 这个用例把两种形状都过一遍,任何人再改回 `.data` 都会在这里红。
void main() {
group('Api 返回值解包', () {
// 与 MemoryService._data 同一份逻辑(那个是私有方法,这里复刻一份守住口径)
Map<String, dynamic>? unwrap(dynamic resp) {
if (resp == null) return null;
if (resp is Map) return Map<String, dynamic>.from(resp);
return null;
}
test('成功:直接拿到 data Map,能取到字段', () {
final resp = {
'items': [
{'id': 1, 'title': '开会'}
],
'total': 1,
};
final data = unwrap(resp);
expect(data, isNotNull);
expect(data!['total'], 1);
expect((data['items'] as List).length, 1);
});
test('成功但没数据:AuthInterceptor 给的是 {} 而不是 null', () {
final data = unwrap(<String, dynamic>{});
// {} 表示「成功但没数据」,必须是非 null —— 与业务错误的 null 含义相反
expect(data, isNotNull);
expect(data, isEmpty);
});
test('业务错误:AuthInterceptor 把 data 置 null 并 resolve(不抛)', () {
expect(unwrap(null), isNull);
});
test('拿到 Response 这类对象(口径写错时的形状)一律当无数据,不能崩', () {
// 万一有人把 Response 传进来,宁可返回 null 也不要抛
expect(unwrap(Object()), isNull);
expect(unwrap('unexpected string'), isNull);
expect(unwrap(42), isNull);
});
});
}