feat: 切换邮箱认证并重构前后端启动与门禁
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:meeyao_qianwen/features/auth/data/models/auth_user.dart';
|
||||
import 'package:meeyao_qianwen/features/auth/data/repositories/auth_repository.dart';
|
||||
import 'package:meeyao_qianwen/features/auth/presentation/bloc/auth_bloc.dart';
|
||||
import 'package:meeyao_qianwen/features/auth/presentation/bloc/auth_state.dart';
|
||||
|
||||
class _FakeAuthRepository implements AuthRepository {
|
||||
_FakeAuthRepository({this.recoveredUser, this.throwOnLogout = false});
|
||||
|
||||
AuthUser? recoveredUser;
|
||||
bool clearCalled = false;
|
||||
bool logoutCalled = false;
|
||||
bool throwOnLogout;
|
||||
|
||||
@override
|
||||
Future<void> clearLocalSession() async {
|
||||
clearCalled = true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AuthUser> loginWithEmailOtp({
|
||||
required String email,
|
||||
required String otp,
|
||||
}) async {
|
||||
return AuthUser(id: 'u1', email: email);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> logout() async {
|
||||
logoutCalled = true;
|
||||
if (throwOnLogout) {
|
||||
throw Exception('logout failed');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AuthUser?> recoverSession() async {
|
||||
return recoveredUser;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> sendOtp(String email) async {}
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('start should become authenticated when recover success', () async {
|
||||
final repo = _FakeAuthRepository(
|
||||
recoveredUser: const AuthUser(id: 'u1', email: 'a@b.com'),
|
||||
);
|
||||
final bloc = AuthBloc(repository: repo);
|
||||
|
||||
await bloc.start();
|
||||
|
||||
expect(bloc.state.status, AuthStatus.authenticated);
|
||||
expect(bloc.state.user?.email, 'a@b.com');
|
||||
});
|
||||
|
||||
test('handleUnauthorized401 should clear local session and unauth', () async {
|
||||
final repo = _FakeAuthRepository(
|
||||
recoveredUser: const AuthUser(id: 'u1', email: 'a@b.com'),
|
||||
);
|
||||
final bloc = AuthBloc(repository: repo);
|
||||
|
||||
await bloc.start();
|
||||
await bloc.handleUnauthorized401();
|
||||
|
||||
expect(repo.clearCalled, isTrue);
|
||||
expect(bloc.state.status, AuthStatus.unauthenticated);
|
||||
});
|
||||
|
||||
test(
|
||||
'logout should set unauthenticated even when repository throws',
|
||||
() async {
|
||||
final repo = _FakeAuthRepository(
|
||||
recoveredUser: const AuthUser(id: 'u1', email: 'a@b.com'),
|
||||
throwOnLogout: true,
|
||||
);
|
||||
final bloc = AuthBloc(repository: repo);
|
||||
|
||||
await bloc.start();
|
||||
|
||||
await expectLater(bloc.logout(), throwsA(isA<Exception>()));
|
||||
expect(repo.logoutCalled, isTrue);
|
||||
expect(bloc.state.status, AuthStatus.unauthenticated);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:meeyao_qianwen/core/auth/session_store.dart';
|
||||
import 'package:meeyao_qianwen/app/app_theme.dart';
|
||||
import 'package:meeyao_qianwen/data/storage/local_kv_store.dart';
|
||||
import 'package:meeyao_qianwen/features/home/presentation/screens/home_screen.dart';
|
||||
import 'package:meeyao_qianwen/l10n/app_localizations.dart';
|
||||
|
||||
class _FakeSessionStore extends SessionStore {
|
||||
_FakeSessionStore({required this.hasReadWelcomeValue})
|
||||
: super(LocalKvStore());
|
||||
|
||||
bool hasReadWelcomeValue;
|
||||
bool setWelcomeReadCalled = false;
|
||||
|
||||
@override
|
||||
Future<bool> hasReadWelcome() async {
|
||||
return hasReadWelcomeValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setWelcomeRead(bool value) async {
|
||||
setWelcomeReadCalled = value;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('history cards should use full available width', (tester) async {
|
||||
final sessionStore = _FakeSessionStore(hasReadWelcomeValue: true);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: AppTheme.light(),
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: HomeScreen(
|
||||
account: 'user@example.com',
|
||||
sessionStore: sessionStore,
|
||||
onLogout: () async {},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final historyCard = find.byType(Card).first;
|
||||
final cardWidth = tester.getSize(historyCard).width;
|
||||
final viewportWidth =
|
||||
tester.view.physicalSize.width / tester.view.devicePixelRatio;
|
||||
|
||||
expect(cardWidth, viewportWidth);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user