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.

311 lines
8.9 KiB

import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
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:app_boilerplate/data/local/models/item.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 FirebaseService firebaseService;
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<FirebaseException>()),
);
});
});
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<FirebaseException>()),
);
});
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<FirebaseException>()),
);
});
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<FirebaseException>()),
);
});
});
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<FirebaseException>()),
);
});
test('syncItemsToFirestore throws when not initialized', () async {
final config = FirebaseConfig.enabled();
final service = FirebaseService(
config: config,
localStorage: mockLocalStorage,
);
expect(
() => service.syncItemsToFirestore('user1'),
throwsA(isA<FirebaseException>()),
);
});
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<FirebaseException>()),
);
});
test('syncItemsFromFirestore throws when not initialized', () async {
final config = FirebaseConfig.enabled();
final service = FirebaseService(
config: config,
localStorage: mockLocalStorage,
);
expect(
() => service.syncItemsFromFirestore('user1'),
throwsA(isA<FirebaseException>()),
);
});
});
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<FirebaseException>()),
);
});
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<FirebaseException>()),
);
});
});
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();
});
});
}

Powered by TurnKey Linux.