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
@@ -0,0 +1,92 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tm_app/core/constants/pref_keys.dart';
import 'package:tm_app/core/network/network_manager.dart';
import 'package:tm_app/core/utils/logger.dart';
import 'package:tm_app/core/utils/result.dart';
import 'package:tm_app/data/repositories/company_ai_repository.dart';
import 'package:tm_app/data/services/company_ai_service.dart';
import 'package:tm_app/data/services/model/onboarding_response/onboarding_response.dart';
import 'package:tm_app/data/services/model/recommend_response/recommend_response.dart';
void main() {
setUpAll(() {
appLogger.init();
});
group('CompanyAiRepository', () {
test('skips onboarding when company has no indexable data', () async {
SharedPreferences.setMockInitialValues({});
final prefs = await SharedPreferences.getInstance();
final service = _FakeCompanyAiService(prefs);
final repository = CompanyAiRepository(
companyAiService: service,
prefs: prefs,
);
final outcome = await repository.maybeStartOnboarding(
documentFileIds: const [],
website: ' ',
);
expect(outcome, AiOnboardingOutcome.skippedNoData);
expect(service.startOnboardingCalls, 0);
expect(prefs.getString(PrefKeys.onboardingFingerprint), isNull);
});
test('stores fingerprint and skips unchanged profile data', () async {
SharedPreferences.setMockInitialValues({});
final prefs = await SharedPreferences.getInstance();
final service = _FakeCompanyAiService(prefs);
final repository = CompanyAiRepository(
companyAiService: service,
prefs: prefs,
);
final firstOutcome = await repository.maybeStartOnboarding(
documentFileIds: const ['b', 'a'],
website: ' https://example.com ',
);
final secondOutcome = await repository.maybeStartOnboarding(
documentFileIds: const ['a', 'b'],
website: 'https://example.com',
);
expect(firstOutcome, AiOnboardingOutcome.started);
expect(secondOutcome, AiOnboardingOutcome.skippedUnchanged);
expect(service.startOnboardingCalls, 1);
expect(
prefs.getString(PrefKeys.onboardingFingerprint),
'a,b|https://example.com',
);
expect(prefs.getInt(PrefKeys.onboardingStartedAt), isNotNull);
});
});
}
class _FakeCompanyAiService extends CompanyAiService {
_FakeCompanyAiService(SharedPreferences prefs)
: super(networkManager: NetworkManager(prefs));
int startOnboardingCalls = 0;
@override
Future<Result<OnboardingResponse>> startOnboarding() async {
startOnboardingCalls += 1;
return const Result.ok(
OnboardingResponse(
data: null,
error: null,
message: 'started',
success: true,
),
);
}
@override
Future<Result<RecommendResponse>> getRecommendations() async {
return const Result.ok(
RecommendResponse(data: [], error: null, message: 'ok', success: true),
);
}
}