// test/unit/register_use_case_test.dart // // Unit test untuk RegisterUseCase. // Jalankan: flutter test test/unit/register_use_case_test.dart import 'package:dartz/dartz.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; // ---------- Stubs ---------- abstract class Failure { final String message; const Failure(this.message); } class ServerFailure extends Failure { const ServerFailure(super.message); } class ValidationFailure extends Failure { const ValidationFailure(super.message); } class NetworkFailure extends Failure { const NetworkFailure(super.message); } class UserEntity { final String token; final String role; final String displayName; final String? uniqueUserId; // hanya ROLE_USER yang punya UserEntity({ required this.token, required this.role, required this.displayName, this.uniqueUserId, }); } abstract class RegisterRepository { Future> register({ required String email, required String password, required String displayName, required String role, // 'ROLE_USER' | 'ROLE_GUARDIAN' }); } class MockRegisterRepository extends Mock implements RegisterRepository {} // ---------- Use case ---------- class RegisterUseCase { final RegisterRepository repository; RegisterUseCase(this.repository); Future> call({ required String email, required String password, required String displayName, required String role, }) async { // Validasi email format sederhana if (email.trim().isEmpty || !email.contains('@')) { return const Left(ValidationFailure('Format email tidak valid')); } // Validasi password if (password.length < 6) { return const Left(ValidationFailure('Password harus minimal 6 karakter')); } // Validasi displayName if (displayName.trim().isEmpty) { return const Left(ValidationFailure('Nama tidak boleh kosong')); } // Validasi role if (role != 'ROLE_USER' && role != 'ROLE_GUARDIAN') { return const Left(ValidationFailure('Role tidak valid')); } return repository.register( email: email.trim(), password: password, displayName: displayName.trim(), role: role, ); } } // ---------- Tests ---------- void main() { late RegisterUseCase registerUseCase; late MockRegisterRepository mockRepo; setUp(() { mockRepo = MockRegisterRepository(); registerUseCase = RegisterUseCase(mockRepo); }); group('RegisterUseCase — validasi email', () { test('harus gagal jika email kosong', () async { final result = await registerUseCase.call( email: '', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isLeft(), true); result.fold( (f) => expect(f, isA()), (_) => fail('Seharusnya gagal'), ); }); test('harus gagal jika email tanpa @', () async { final result = await registerUseCase.call( email: 'bukan-email', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isLeft(), true); }); test('harus berhasil dengan email valid', () async { final fakeUser = UserEntity( token: 'tok', role: 'ROLE_USER', displayName: 'Evan', uniqueUserId: 'ABC123DEF456', ); when(mockRepo.register( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', )).thenAnswer((_) async => Right(fakeUser)); final result = await registerUseCase.call( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isRight(), true); }); }); group('RegisterUseCase — validasi password', () { test('harus gagal jika password kurang dari 6 karakter', () async { final result = await registerUseCase.call( email: 'evan@test.com', password: '12345', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isLeft(), true); result.fold( (f) { expect(f, isA()); expect(f.message, contains('6')); }, (_) => fail('Seharusnya gagal'), ); }); test('harus gagal jika password kosong', () async { final result = await registerUseCase.call( email: 'evan@test.com', password: '', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isLeft(), true); }); test('password tepat 6 karakter harus lolos', () async { final fakeUser = UserEntity(token: 'tok', role: 'ROLE_USER', displayName: 'Evan'); when(mockRepo.register( email: 'evan@test.com', password: 'abc123', displayName: 'Evan', role: 'ROLE_USER', )).thenAnswer((_) async => Right(fakeUser)); final result = await registerUseCase.call( email: 'evan@test.com', password: 'abc123', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isRight(), true); }); }); group('RegisterUseCase — validasi displayName', () { test('harus gagal jika displayName kosong', () async { final result = await registerUseCase.call( email: 'evan@test.com', password: 'password123', displayName: '', role: 'ROLE_USER', ); expect(result.isLeft(), true); }); test('harus gagal jika displayName hanya spasi', () async { final result = await registerUseCase.call( email: 'evan@test.com', password: 'password123', displayName: ' ', role: 'ROLE_USER', ); expect(result.isLeft(), true); }); }); group('RegisterUseCase — validasi role', () { test('harus gagal jika role bukan ROLE_USER atau ROLE_GUARDIAN', () async { final result = await registerUseCase.call( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_ADMIN', ); expect(result.isLeft(), true); result.fold( (f) => expect(f, isA()), (_) => fail('Seharusnya gagal'), ); }); test('ROLE_USER harus valid', () async { final fakeUser = UserEntity( token: 'tok', role: 'ROLE_USER', displayName: 'Evan', uniqueUserId: 'ABC123DEF456', ); when(mockRepo.register( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', )).thenAnswer((_) async => Right(fakeUser)); final result = await registerUseCase.call( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', ); expect(result.isRight(), true); }); test('ROLE_GUARDIAN harus valid', () async { final fakeUser = UserEntity( token: 'tok', role: 'ROLE_GUARDIAN', displayName: 'Bambang', ); when(mockRepo.register( email: 'bambang@test.com', password: 'guardian123', displayName: 'Bambang', role: 'ROLE_GUARDIAN', )).thenAnswer((_) async => Right(fakeUser)); final result = await registerUseCase.call( email: 'bambang@test.com', password: 'guardian123', displayName: 'Bambang', role: 'ROLE_GUARDIAN', ); expect(result.isRight(), true); }); }); group('RegisterUseCase — ROLE_USER mendapat uniqueUserId', () { test('ROLE_USER harus mendapat uniqueUserId dari backend', () async { final fakeUser = UserEntity( token: 'user_jwt', role: 'ROLE_USER', displayName: 'Evan', uniqueUserId: 'ABC123DEF456', ); when(mockRepo.register( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', )).thenAnswer((_) async => Right(fakeUser)); final result = await registerUseCase.call( email: 'evan@test.com', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', ); result.fold( (_) => fail('Seharusnya sukses'), (user) { expect(user.uniqueUserId, isNotNull); expect(user.uniqueUserId!.length, 12); expect(user.role, 'ROLE_USER'); }, ); }); test('ROLE_GUARDIAN tidak perlu uniqueUserId', () async { final fakeUser = UserEntity( token: 'guardian_jwt', role: 'ROLE_GUARDIAN', displayName: 'Bambang', uniqueUserId: null, ); when(mockRepo.register( email: 'bambang@test.com', password: 'guardian123', displayName: 'Bambang', role: 'ROLE_GUARDIAN', )).thenAnswer((_) async => Right(fakeUser)); final result = await registerUseCase.call( email: 'bambang@test.com', password: 'guardian123', displayName: 'Bambang', role: 'ROLE_GUARDIAN', ); result.fold( (_) => fail('Seharusnya sukses'), (user) => expect(user.uniqueUserId, isNull), ); }); }); group('RegisterUseCase — error dari server', () { test('harus propagate ServerFailure dari repository', () async { when(mockRepo.register( email: 'taken@test.com', password: 'password123', displayName: 'Duplicate', role: 'ROLE_USER', )).thenAnswer( (_) async => const Left(ServerFailure('Email sudah terdaftar'))); final result = await registerUseCase.call( email: 'taken@test.com', password: 'password123', displayName: 'Duplicate', role: 'ROLE_USER', ); result.fold( (f) { expect(f, isA()); expect(f.message, 'Email sudah terdaftar'); }, (_) => fail('Seharusnya gagal'), ); }); test('tidak boleh call repo jika validasi gagal', () async { await registerUseCase.call( email: '', password: 'password123', displayName: 'Evan', role: 'ROLE_USER', ); verifyNever(mockRepo.register( email: 'ignored', password: 'ignored', displayName: 'ignored', role: 'ignored', )); }); }); }