409 lines
11 KiB
Dart
409 lines
11 KiB
Dart
// 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<Either<Failure, UserEntity>> register({
|
|
required String email,
|
|
required String password,
|
|
required String displayName,
|
|
required String role, // 'ROLE_USER' | 'ROLE_GUARDIAN'
|
|
});
|
|
}
|
|
|
|
class MockRegisterRepository extends Mock implements RegisterRepository {
|
|
@override
|
|
Future<Either<Failure, UserEntity>> register({
|
|
String? email,
|
|
String? password,
|
|
String? displayName,
|
|
String? role,
|
|
}) =>
|
|
super.noSuchMethod(
|
|
Invocation.method(
|
|
#register,
|
|
const [],
|
|
{
|
|
#email: email,
|
|
#password: password,
|
|
#displayName: displayName,
|
|
#role: role,
|
|
},
|
|
),
|
|
returnValue: Future<Either<Failure, UserEntity>>.value(
|
|
const Left(ServerFailure('Repository belum di-stub')),
|
|
),
|
|
returnValueForMissingStub: Future<Either<Failure, UserEntity>>.value(
|
|
const Left(ServerFailure('Repository belum di-stub')),
|
|
),
|
|
) as Future<Either<Failure, UserEntity>>;
|
|
}
|
|
|
|
// ---------- Use case ----------
|
|
|
|
class RegisterUseCase {
|
|
final RegisterRepository repository;
|
|
RegisterUseCase(this.repository);
|
|
|
|
Future<Either<Failure, UserEntity>> 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<ValidationFailure>()),
|
|
(_) => 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<ValidationFailure>());
|
|
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<ValidationFailure>()),
|
|
(_) => 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<ServerFailure>());
|
|
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',
|
|
));
|
|
});
|
|
});
|
|
}
|