feat: 重构 Reminder Notification 系统并更新应用包名
This commit is contained in:
@@ -73,6 +73,7 @@ class _FakeAgUiService extends AgUiService {
|
||||
loadHistoryHandler;
|
||||
|
||||
int loadHistoryCalls = 0;
|
||||
final List<String?> setUserContextCalls = <String?>[];
|
||||
|
||||
void emitEventForTest(AgUiEvent event) {
|
||||
onEvent(event);
|
||||
@@ -104,7 +105,9 @@ class _FakeAgUiService extends AgUiService {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setUserContext(String? userId) async {}
|
||||
Future<void> setUserContext(String? userId) async {
|
||||
setUserContextCalls.add(userId);
|
||||
}
|
||||
}
|
||||
|
||||
HistorySnapshot _snapshot(
|
||||
@@ -146,9 +149,14 @@ void main() {
|
||||
() async {
|
||||
final service = _FakeAgUiService();
|
||||
final completer = Completer<HistorySnapshot>();
|
||||
var loadCall = 0;
|
||||
service.loadHistoryHandler =
|
||||
({DateTime? beforeDate, bool forceRefresh = false}) {
|
||||
return completer.future;
|
||||
loadCall += 1;
|
||||
if (loadCall == 1) {
|
||||
return completer.future;
|
||||
}
|
||||
return Future<HistorySnapshot>.value(_snapshot(const []));
|
||||
};
|
||||
|
||||
final bloc = ChatBloc(
|
||||
@@ -178,6 +186,82 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test('switchUser loads history after resetting state', () async {
|
||||
final service = _FakeAgUiService();
|
||||
service.loadHistoryHandler =
|
||||
({DateTime? beforeDate, bool forceRefresh = false}) async {
|
||||
final now = DateTime.now();
|
||||
return _snapshot([
|
||||
_historyMessage(
|
||||
id: 'history-1',
|
||||
seq: 1,
|
||||
role: 'assistant',
|
||||
content: 'welcome back',
|
||||
timestamp: now,
|
||||
),
|
||||
]);
|
||||
};
|
||||
|
||||
final bloc = ChatBloc(service: service, chatApi: _NoopChatApi());
|
||||
await bloc.switchUser('user-a');
|
||||
|
||||
expect(service.setUserContextCalls, ['user-a']);
|
||||
expect(service.loadHistoryCalls, 1);
|
||||
expect(bloc.state.items, hasLength(1));
|
||||
expect(
|
||||
bloc.state.items.single,
|
||||
isA<TextMessageItem>().having(
|
||||
(item) => item.content,
|
||||
'content',
|
||||
'welcome back',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('switchUser keeps flow when history load fails', () async {
|
||||
final service = _FakeAgUiService();
|
||||
service.loadHistoryHandler =
|
||||
({DateTime? beforeDate, bool forceRefresh = false}) {
|
||||
throw StateError('history unavailable');
|
||||
};
|
||||
|
||||
final bloc = ChatBloc(service: service, chatApi: _NoopChatApi());
|
||||
await bloc.switchUser('user-a');
|
||||
|
||||
expect(service.setUserContextCalls, ['user-a']);
|
||||
expect(service.loadHistoryCalls, 1);
|
||||
expect(bloc.state.error, contains('history unavailable'));
|
||||
});
|
||||
|
||||
test(
|
||||
'tool calendar_write success triggers calendar refresh callback',
|
||||
() async {
|
||||
final service = _FakeAgUiService();
|
||||
var refreshCalls = 0;
|
||||
final bloc = ChatBloc(
|
||||
service: service,
|
||||
chatApi: _NoopChatApi(),
|
||||
onCalendarMutated: () async {
|
||||
refreshCalls += 1;
|
||||
},
|
||||
);
|
||||
|
||||
service.emitEventForTest(
|
||||
ToolCallResultEvent(
|
||||
messageId: 'msg-1',
|
||||
toolCallId: 'call-1',
|
||||
toolName: 'calendar_write',
|
||||
resultSummary: 'ok',
|
||||
status: 'success',
|
||||
),
|
||||
);
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(refreshCalls, 1);
|
||||
expect(bloc.state.isLoading, isFalse);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'sendMessage recovers from premature SSE close with polled history',
|
||||
() async {
|
||||
|
||||
Reference in New Issue
Block a user