117 lines
3.3 KiB
Dart
117 lines
3.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:meeyao_qianwen/core/auth/session_store.dart';
|
|
import 'package:meeyao_qianwen/data/network/api_client.dart';
|
|
import 'package:meeyao_qianwen/data/storage/local_kv_store.dart';
|
|
import 'package:meeyao_qianwen/features/auth/data/apis/auth_api.dart';
|
|
import 'package:meeyao_qianwen/features/auth/data/repositories/auth_repository.dart';
|
|
|
|
class _FakeSessionStore extends SessionStore {
|
|
_FakeSessionStore({this.refreshToken, this.throwOnGetRefreshToken = false})
|
|
: super(LocalKvStore());
|
|
|
|
String? refreshToken;
|
|
bool throwOnGetRefreshToken;
|
|
|
|
bool clearTokenCalled = false;
|
|
bool clearRefreshTokenCalled = false;
|
|
bool clearEmailCalled = false;
|
|
|
|
@override
|
|
Future<String?> getRefreshToken() async {
|
|
if (throwOnGetRefreshToken) {
|
|
throw Exception('read refresh token failed');
|
|
}
|
|
return refreshToken;
|
|
}
|
|
|
|
@override
|
|
Future<void> clearToken() async {
|
|
clearTokenCalled = true;
|
|
}
|
|
|
|
@override
|
|
Future<void> clearRefreshToken() async {
|
|
clearRefreshTokenCalled = true;
|
|
}
|
|
|
|
@override
|
|
Future<void> clearEmail() async {
|
|
clearEmailCalled = true;
|
|
}
|
|
}
|
|
|
|
class _FakeAuthApi extends AuthApi {
|
|
_FakeAuthApi()
|
|
: super(apiClient: ApiClient(baseUrl: 'http://127.0.0.1:5775'));
|
|
|
|
bool deleteSessionCalled = false;
|
|
bool throwOnDeleteSession = false;
|
|
|
|
@override
|
|
Future<void> deleteSession({required String refreshToken}) async {
|
|
deleteSessionCalled = true;
|
|
if (throwOnDeleteSession) {
|
|
throw Exception('delete session failed');
|
|
}
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
test(
|
|
'logout should clear local session when getRefreshToken throws',
|
|
() async {
|
|
final authApi = _FakeAuthApi();
|
|
final sessionStore = _FakeSessionStore(throwOnGetRefreshToken: true);
|
|
final repository = AuthRepositoryImpl(
|
|
authApi: authApi,
|
|
sessionStore: sessionStore,
|
|
);
|
|
|
|
await expectLater(repository.logout(), throwsA(isA<Exception>()));
|
|
|
|
expect(authApi.deleteSessionCalled, isFalse);
|
|
expect(sessionStore.clearTokenCalled, isTrue);
|
|
expect(sessionStore.clearRefreshTokenCalled, isTrue);
|
|
expect(sessionStore.clearEmailCalled, isTrue);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'logout should skip deleteSession when refresh token is empty',
|
|
() async {
|
|
final authApi = _FakeAuthApi();
|
|
final sessionStore = _FakeSessionStore(refreshToken: '');
|
|
final repository = AuthRepositoryImpl(
|
|
authApi: authApi,
|
|
sessionStore: sessionStore,
|
|
);
|
|
|
|
await repository.logout();
|
|
|
|
expect(authApi.deleteSessionCalled, isFalse);
|
|
expect(sessionStore.clearTokenCalled, isTrue);
|
|
expect(sessionStore.clearRefreshTokenCalled, isTrue);
|
|
expect(sessionStore.clearEmailCalled, isTrue);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'logout should still clear local session when deleteSession throws',
|
|
() async {
|
|
final authApi = _FakeAuthApi()..throwOnDeleteSession = true;
|
|
final sessionStore = _FakeSessionStore(refreshToken: 'r1');
|
|
final repository = AuthRepositoryImpl(
|
|
authApi: authApi,
|
|
sessionStore: sessionStore,
|
|
);
|
|
|
|
await expectLater(repository.logout(), throwsA(isA<Exception>()));
|
|
|
|
expect(authApi.deleteSessionCalled, isTrue);
|
|
expect(sessionStore.clearTokenCalled, isTrue);
|
|
expect(sessionStore.clearRefreshTokenCalled, isTrue);
|
|
expect(sessionStore.clearEmailCalled, isTrue);
|
|
},
|
|
);
|
|
}
|