You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
8.9 KiB
308 lines
8.9 KiB
import 'dart:io';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:mockito/annotations.dart';
|
|
import 'package:app_boilerplate/core/exceptions/firebase_exception.dart' show FirebaseServiceException;
|
|
import 'package:app_boilerplate/data/firebase/firebase_service.dart';
|
|
import 'package:app_boilerplate/data/firebase/models/firebase_config.dart';
|
|
import 'package:app_boilerplate/data/local/local_storage_service.dart';
|
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
|
import 'package:path/path.dart' as path;
|
|
|
|
import 'firebase_service_test.mocks.dart';
|
|
|
|
@GenerateMocks([LocalStorageService])
|
|
void main() {
|
|
// Initialize Flutter bindings and sqflite for testing
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
sqfliteFfiInit();
|
|
databaseFactory = databaseFactoryFfi;
|
|
|
|
late MockLocalStorageService mockLocalStorage;
|
|
late Directory tempDir;
|
|
|
|
setUp(() async {
|
|
tempDir = await Directory.systemTemp.createTemp('firebase_test_');
|
|
mockLocalStorage = MockLocalStorageService();
|
|
});
|
|
|
|
tearDown(() async {
|
|
if (await tempDir.exists()) {
|
|
await tempDir.delete(recursive: true);
|
|
}
|
|
});
|
|
|
|
group('FirebaseService - Configuration', () {
|
|
test('service is disabled when config.enabled is false', () {
|
|
final config = FirebaseConfig.disabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(service.isEnabled, isFalse);
|
|
expect(service.isLoggedIn, isFalse);
|
|
});
|
|
|
|
test('service can be enabled with config', () {
|
|
final config = FirebaseConfig.enabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// Service is not initialized yet, so isEnabled is false
|
|
expect(service.isEnabled, isFalse);
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Initialization', () {
|
|
test('initialize does nothing when Firebase is disabled', () async {
|
|
final config = FirebaseConfig.disabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// Should not throw even though Firebase is not set up
|
|
// (In real app, Firebase.initializeApp() would fail, but we're testing disabled case)
|
|
expect(() => service.initialize(), returnsNormally);
|
|
});
|
|
|
|
test('initialize fails gracefully when Firebase not configured', () async {
|
|
// This test verifies that when Firebase is enabled but not configured,
|
|
// the service handles the error gracefully
|
|
// Note: In real scenarios, Firebase.initializeApp() requires actual config files
|
|
final config = FirebaseConfig.enabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// In a test environment without Firebase config, this will fail
|
|
// but that's expected - Firebase requires actual project setup
|
|
expect(
|
|
() => service.initialize(),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Authentication', () {
|
|
test('loginWithEmailPassword throws when auth disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
authEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.loginWithEmailPassword(
|
|
email: 'test@example.com',
|
|
password: 'password123',
|
|
),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
|
|
test('loginWithEmailPassword throws when not initialized', () async {
|
|
final config = FirebaseConfig.enabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.loginWithEmailPassword(
|
|
email: 'test@example.com',
|
|
password: 'password123',
|
|
),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
|
|
test('logout throws when auth disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
authEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.logout(),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Firestore Sync', () {
|
|
test('syncItemsToFirestore throws when Firestore disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
firestoreEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.syncItemsToFirestore('user1'),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
|
|
test('syncItemsToFirestore throws when not initialized', () async {
|
|
final config = FirebaseConfig.enabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.syncItemsToFirestore('user1'),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
|
|
test('syncItemsFromFirestore throws when Firestore disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
firestoreEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.syncItemsFromFirestore('user1'),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
|
|
test('syncItemsFromFirestore throws when not initialized', () async {
|
|
final config = FirebaseConfig.enabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
expect(
|
|
() => service.syncItemsFromFirestore('user1'),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Storage', () {
|
|
test('uploadFile throws when Storage disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
storageEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
final testFile = File(path.join(tempDir.path, 'test.txt'));
|
|
await testFile.writeAsString('test content');
|
|
|
|
expect(
|
|
() => service.uploadFile(testFile, 'test/path.txt'),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
|
|
test('uploadFile throws when not initialized', () async {
|
|
final config = FirebaseConfig.enabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
final testFile = File(path.join(tempDir.path, 'test.txt'));
|
|
await testFile.writeAsString('test content');
|
|
|
|
expect(
|
|
() => service.uploadFile(testFile, 'test/path.txt'),
|
|
throwsA(isA<FirebaseServiceException>()),
|
|
);
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Messaging', () {
|
|
test('getFcmToken returns null when messaging disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
messagingEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
final token = await service.getFcmToken();
|
|
expect(token, isNull);
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Analytics', () {
|
|
test('logEvent does nothing when Analytics disabled', () async {
|
|
final config = FirebaseConfig(
|
|
enabled: true,
|
|
analyticsEnabled: false,
|
|
);
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// Should not throw even though Analytics is disabled
|
|
await service.logEvent('test_event');
|
|
});
|
|
|
|
test('logEvent does nothing when Firebase disabled', () async {
|
|
final config = FirebaseConfig.disabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// Should not throw even though Firebase is disabled
|
|
await service.logEvent('test_event');
|
|
});
|
|
});
|
|
|
|
group('FirebaseService - Offline Scenarios', () {
|
|
test('service maintains offline-first behavior when disabled', () async {
|
|
final config = FirebaseConfig.disabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// Service should not interfere with local storage operations
|
|
expect(service.isEnabled, isFalse);
|
|
expect(service.isLoggedIn, isFalse);
|
|
});
|
|
|
|
test('service can be disposed safely', () async {
|
|
final config = FirebaseConfig.disabled();
|
|
final service = FirebaseService(
|
|
config: config,
|
|
localStorage: mockLocalStorage,
|
|
);
|
|
|
|
// Should not throw
|
|
await service.dispose();
|
|
});
|
|
});
|
|
}
|