Files
photo-live/apps/mobile/test/app/app_shell_test.dart
T
浅念 ae17776be6 feat(app): session restore on startup — no forced re-login after app restart
用户反馈:关闭 App 重开每次都要登录。根因:会话已持久化(安全存储,
服务端 TTL 30 天),但启动固定落在登录页——无人消费已存会话。

- _StartupGate(home):watch sessionAccount——在场直进 HomePage,离场
  LoginPage;状态驱动(401/登出清会话后 gate 自动重建,不依赖导航时序)
- onUnauthorized 保留 push 兜底(home 路由被显式导航替换后的 401 场景)
- 测试适配(boot 401 两项重写通过;397/397 全绿)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:48:27 +08:00

57 lines
2.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// App 壳 401 接线测试(P3 计划 Task 3)。
///
/// 覆盖:业务端点 401 → ApiClient 清会话并触发 onUnauthorized →
/// 根导航清栈回 /login(PhotoLiveApp.initState 注册的回调)。
library;
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:photo_live/app/app.dart';
import 'package:photo_live/pages/login_page.dart';
import 'package:photo_live/core/api_client.dart';
import 'package:photo_live/core/error_codes.dart';
import 'package:photo_live/core/session_store.dart';
import '../helpers/fakes.dart';
void main() {
testWidgets('业务 401 → onUnauthorized 清栈回 /login', (tester) async {
final store = FakeSessionStore();
store.session = Session(
token: 'tok-live-1',
expiresAt: DateTime.utc(2099, 1, 1),
account: 'staff01',
);
final adapter = FakeAdapter(
(o) => (401, errorBody(ErrorCodes.authTokenExpired)),
);
final client = ApiClient(
sessionStore: store,
dio: Dio(BaseOptions(baseUrl: 'http://test.local'))
..httpClientAdapter = adapter,
);
// PhotoLiveApp.initState 读取被 override 的客户端并注册 onUnauthorized。
// Task 9 起根组件 watch 引擎作用域(会话→引擎 start),真实
// flutter_secure_storage/path_provider 平台通道在测试环境挂起,须替身。
await tester.pumpWidget(
ProviderScope(
overrides: [...pageTestOverrides(session: store, client: client)],
child: const PhotoLiveApp(),
),
);
await tester.pumpAndSettle();
// UI06 启动门:有会话直接渲染 HomePage(无须手动 push)。
// 触发 401 但不在测试体内 await(fake-async 下时钟由 pump 推进,
// 阻塞等待会死锁);AppException 由 ignore 吞掉,断言在下方。
client.listAlbums().ignore();
await tester.pumpAndSettle();
expect(store.session, isNull, reason: '业务 401 清空本地会话');
expect(find.byType(LoginPage), findsOneWidget, reason: '清栈回登录页');
});
}