test: add AI recommendations fallback tests

Cover repository and view model fallback behavior and fix load state handling for 503 fallback responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
AmirReza Jamali
2026-06-17 13:24:28 +03:30
parent 50e4f43738
commit d4a07fd774
3 changed files with 287 additions and 5 deletions
@@ -72,6 +72,8 @@ class AiRecommendationsViewModel with ChangeNotifier {
final result = await _companyAiRepository.getRecommendations();
var loadedSuccessfully = false;
switch (result) {
case Ok<RecommendResponse>():
_items = result.value.data ?? const [];
@@ -79,28 +81,32 @@ class AiRecommendationsViewModel with ChangeNotifier {
if (_items.isEmpty) {
_stillLearning = _onboardingWasRecent();
}
loadedSuccessfully = true;
case Error<RecommendResponse>():
await _handleError(result.error);
loadedSuccessfully = await _handleError(result.error);
}
_isLoading = false;
_hasLoaded = true;
_hasLoaded = loadedSuccessfully;
notifyListeners();
}
/// Pull-to-refresh: always re-fetches.
Future<void> refresh() => loadRecommendations();
Future<void> _handleError(Exception error) async {
Future<bool> _handleError(Exception error) async {
// 503 means the AI service isn't configured/available — fall back to the
// legacy recommend list rather than showing an error.
// legacy recommend list rather than showing an error. NetworkManager only
// exposes this status when Dio received an HTTP response; connection and
// timeout failures have no reliable status code and should remain retryable.
if (error is AppException && error.statusCode == 503) {
await _loadFallback();
return;
return _errorMessage == null;
}
_items = const [];
_fallbackTenders = const [];
_errorMessage = error.toString();
return false;
}
Future<void> _loadFallback() async {