修复工作人员端令牌失效后的登录恢复

This commit is contained in:
czl231
2026-09-05 19:51:36 +08:00
parent 7ea39334eb
commit 1670d5880f
20 changed files with 849 additions and 46 deletions

View File

@@ -0,0 +1,115 @@
// 功能描述:验证工作人员端统一请求的鉴权失效通知和上传处理。
// 版本1.0.0
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:image_picker/image_picker.dart';
import 'package:service_app/data/services/api_client.dart';
/// 覆盖 HTTP 状态、业务码、匿名请求、请求令牌快照和上传场景。
void main() {
test('受保护接口返回 HTTP 401 时通知会话并抛出专用异常', () async {
final rejectedTokens = <String>[];
final client = ApiClient(
() => 'JWT expired-token',
baseUrl: 'https://api.example.com',
onUnauthorized: rejectedTokens.add,
client: MockClient((request) async => http.Response('', 401)),
);
await expectLater(
client.get('/protected'),
throwsA(isA<SessionExpiredException>()),
);
expect(rejectedTokens, ['JWT expired-token']);
});
test('受保护接口返回鉴权业务码时通知会话', () async {
final rejectedTokens = <String>[];
final client = ApiClient(
() => 'JWT expired-token',
baseUrl: 'https://api.example.com',
onUnauthorized: rejectedTokens.add,
client: MockClient(
(request) async => http.Response(
'{"code":1308,"message":"Token Expired","details":null}',
200,
),
),
);
await expectLater(
client.get('/protected'),
throwsA(isA<SessionExpiredException>()),
);
expect(rejectedTokens, ['JWT expired-token']);
});
test('未鉴权接口返回 401 时不得清理已有会话', () async {
final rejectedTokens = <String>[];
final client = ApiClient(
() => 'JWT current-token',
baseUrl: 'https://api.example.com',
onUnauthorized: rejectedTokens.add,
client: MockClient((request) async => http.Response('', 401)),
);
await expectLater(
client.post('/login', authenticated: false),
throwsA(
isA<ApiException>()
.having((error) => error.code, 'code', 401)
.having((error) => error is SessionExpiredException, 'session expired', isFalse),
),
);
expect(rejectedTokens, isEmpty);
});
test('请求发送后令牌变化时仍上报实际被拒绝的旧令牌', () async {
var currentToken = 'JWT old-token';
final rejectedTokens = <String>[];
final client = ApiClient(
() => currentToken,
baseUrl: 'https://api.example.com',
onUnauthorized: rejectedTokens.add,
client: MockClient((request) async {
currentToken = 'JWT new-token';
return http.Response('', 401);
}),
);
await expectLater(
client.get('/protected'),
throwsA(isA<SessionExpiredException>()),
);
expect(rejectedTokens, ['JWT old-token']);
});
test('文件上传返回鉴权业务码时同样触发统一会话失效', () async {
final rejectedTokens = <String>[];
final client = ApiClient(
() => 'JWT expired-token',
baseUrl: 'https://api.example.com',
onUnauthorized: rejectedTokens.add,
client: MockClient(
(request) async => http.Response(
'{"code":1715,"message":"Unauthorized","details":null}',
200,
),
),
);
final file = XFile.fromData(
Uint8List.fromList(const [1, 2, 3]),
name: 'proof.jpg',
mimeType: 'image/jpeg',
);
await expectLater(
client.upload(file),
throwsA(isA<SessionExpiredException>()),
);
expect(rejectedTokens, ['JWT expired-token']);
});
}