Initial commit: unionflow-mobile-apps

Application Flutter complète (sans build artifacts).

Signed-off-by: lions dev Team
This commit is contained in:
dahoud
2026-03-15 16:30:08 +00:00
commit d094d6db9c
1790 changed files with 507435 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
/// Tests unitaires pour ApproveTransaction use case
library approve_transaction_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/approve_transaction.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'approve_transaction_test.mocks.dart';
void main() {
late ApproveTransaction useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = ApproveTransaction(mockRepository);
});
group('ApproveTransaction Use Case', () {
const tApprovalId = 'approval-123';
const tComment = 'Approuvé - Montant conforme au budget';
final tApprovedTransaction = TransactionApproval(
id: tApprovalId,
transactionId: 'tx-123',
transactionType: TransactionType.withdrawal,
amount: 500000.0,
currency: 'XOF',
requesterId: 'user-1',
requesterName: 'Amadou Diallo',
requiredLevel: ApprovalLevel.level1,
status: ApprovalStatus.approved,
approvers: [],
createdAt: DateTime(2024, 12, 15),
);
test('should approve transaction successfully', () async {
// Arrange
when(mockRepository.approveTransaction(
approvalId: tApprovalId,
comment: tComment,
)).thenAnswer((_) async => Right(tApprovedTransaction));
// Act
final result = await useCase(approvalId: tApprovalId, comment: tComment);
// Assert
expect(result, Right(tApprovedTransaction));
result.fold(
(failure) => fail('Should not return failure'),
(approval) {
expect(approval.id, equals(tApprovalId));
expect(approval.status, equals(ApprovalStatus.approved));
},
);
verify(mockRepository.approveTransaction(
approvalId: tApprovalId,
comment: tComment,
));
verifyNoMoreInteractions(mockRepository);
});
test('should approve transaction without comment', () async {
// Arrange
when(mockRepository.approveTransaction(
approvalId: tApprovalId,
comment: null,
)).thenAnswer((_) async => Right(tApprovedTransaction));
// Act
final result = await useCase(approvalId: tApprovalId);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(approval) => expect(approval.status, equals(ApprovalStatus.approved)),
);
});
test('should return ValidationFailure when approvalId is empty', () async {
// Act
final result = await useCase(approvalId: '');
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
expect((failure as ValidationFailure).message, contains('ID approbation requis'));
},
(approval) => fail('Should not return approval'),
);
verifyZeroInteractions(mockRepository);
});
test('should return ServerFailure when repository fails', () async {
// Arrange
final tFailure = ServerFailure('Transaction déjà approuvée');
when(mockRepository.approveTransaction(
approvalId: anyNamed('approvalId'),
comment: anyNamed('comment'),
)).thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase(approvalId: tApprovalId);
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(approval) => fail('Should not return approval'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/approve_transaction_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,221 @@
/// Tests unitaires pour CreateBudget use case
library create_budget_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/create_budget.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'create_budget_test.mocks.dart';
void main() {
late CreateBudget useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = CreateBudget(mockRepository);
});
group('CreateBudget Use Case', () {
const tName = 'Budget 2025';
const tOrgId = 'org-123';
final tBudgetLines = [
BudgetLine(
id: 'line-1',
category: BudgetCategory.contributions,
name: 'Cotisations mensuelles',
description: 'Revenus des cotisations',
amountPlanned: 3000000.0,
),
BudgetLine(
id: 'line-2',
category: BudgetCategory.savings,
name: 'Dépôts épargne',
description: 'Collecte épargne',
amountPlanned: 2000000.0,
),
BudgetLine(
id: 'line-3',
category: BudgetCategory.solidarity,
name: 'Aide mutuelle',
description: 'Soutien membres',
amountPlanned: 1000000.0,
),
];
final tCreatedBudget = Budget(
id: 'budget-new',
name: tName,
organizationId: tOrgId,
period: BudgetPeriod.annual,
year: 2025,
status: BudgetStatus.draft,
lines: tBudgetLines,
totalPlanned: 6000000.0,
totalRealized: 0.0,
currency: 'XOF',
createdBy: 'user-1',
createdAt: DateTime.now(),
startDate: DateTime(2025, 1, 1),
endDate: DateTime(2025, 12, 31),
);
test('should create budget successfully', () async {
// Arrange
when(mockRepository.createBudget(
name: tName,
description: anyNamed('description'),
organizationId: tOrgId,
period: BudgetPeriod.annual,
year: 2025,
month: anyNamed('month'),
lines: tBudgetLines,
)).thenAnswer((_) async => Right(tCreatedBudget));
// Act
final result = await useCase(
name: tName,
organizationId: tOrgId,
period: BudgetPeriod.annual,
year: 2025,
lines: tBudgetLines,
);
// Assert
expect(result, Right(tCreatedBudget));
result.fold(
(failure) => fail('Should not return failure'),
(budget) {
expect(budget.id, equals('budget-new'));
expect(budget.name, equals(tName));
expect(budget.status, equals(BudgetStatus.draft));
},
);
verify(mockRepository.createBudget(
name: tName,
description: null,
organizationId: tOrgId,
period: BudgetPeriod.annual,
year: 2025,
month: null,
lines: tBudgetLines,
));
verifyNoMoreInteractions(mockRepository);
});
test('should create monthly budget with description', () async {
// Arrange
const description = 'Budget opérationnel janvier 2025';
final monthlyLines = [
BudgetLine(
id: 'line-monthly',
category: BudgetCategory.contributions,
name: 'Cotisations janvier',
amountPlanned: 500000.0,
),
];
final monthlyBudget = Budget(
id: 'budget-monthly',
name: 'Budget Janvier 2025',
description: description,
organizationId: tOrgId,
period: BudgetPeriod.monthly,
year: 2025,
month: 1,
status: BudgetStatus.draft,
lines: monthlyLines,
totalPlanned: 500000.0,
totalRealized: 0.0,
currency: 'XOF',
createdBy: 'user-1',
createdAt: DateTime.now(),
startDate: DateTime(2025, 1, 1),
endDate: DateTime(2025, 1, 31),
);
when(mockRepository.createBudget(
name: 'Budget Janvier 2025',
description: description,
organizationId: tOrgId,
period: BudgetPeriod.monthly,
year: 2025,
month: 1,
lines: monthlyLines,
)).thenAnswer((_) async => Right(monthlyBudget));
// Act
final result = await useCase(
name: 'Budget Janvier 2025',
description: description,
organizationId: tOrgId,
period: BudgetPeriod.monthly,
year: 2025,
month: 1,
lines: monthlyLines,
);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(budget) {
expect(budget.period, equals(BudgetPeriod.monthly));
expect(budget.month, equals(1));
},
);
});
test('should return ValidationFailure when name is empty', () async {
// Act
final result = await useCase(
name: '',
organizationId: tOrgId,
period: BudgetPeriod.annual,
year: 2025,
lines: [BudgetLine(id: 'test-1', category: BudgetCategory.operational, name: 'Test line', amountPlanned: 100.0)],
);
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
},
(budget) => fail('Should not return budget'),
);
verifyZeroInteractions(mockRepository);
});
test('should return ServerFailure when repository fails', () async {
// Arrange
final tFailure = ServerFailure('Erreur création budget');
when(mockRepository.createBudget(
name: anyNamed('name'),
description: anyNamed('description'),
organizationId: anyNamed('organizationId'),
period: anyNamed('period'),
year: anyNamed('year'),
month: anyNamed('month'),
lines: anyNamed('lines'),
)).thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase(
name: tName,
organizationId: tOrgId,
period: BudgetPeriod.annual,
year: 2025,
lines: [BudgetLine(id: 'test-1', category: BudgetCategory.operational, name: 'Test line', amountPlanned: 100.0)],
);
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(budget) => fail('Should not return budget'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/create_budget_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,112 @@
/// Tests unitaires pour GetApprovalById use case
library get_approval_by_id_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/get_approval_by_id.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'get_approval_by_id_test.mocks.dart';
void main() {
late GetApprovalById useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = GetApprovalById(mockRepository);
});
group('GetApprovalById Use Case', () {
const tApprovalId = 'approval-123';
final tApproval = TransactionApproval(
id: tApprovalId,
transactionId: 'tx-456',
transactionType: TransactionType.solidarity,
amount: 350000.0,
currency: 'XOF',
requesterId: 'user-1',
requesterName: 'Amadou Diallo',
organizationId: 'org-123',
requiredLevel: ApprovalLevel.level2,
status: ApprovalStatus.pending,
approvers: [],
createdAt: DateTime(2024, 12, 15),
);
test('should return approval details by ID', () async {
// Arrange
when(mockRepository.getApprovalById(tApprovalId))
.thenAnswer((_) async => Right(tApproval));
// Act
final result = await useCase(tApprovalId);
// Assert
expect(result, Right(tApproval));
result.fold(
(failure) => fail('Should not return failure'),
(approval) {
expect(approval.id, equals(tApprovalId));
expect(approval.amount, equals(350000.0));
expect(approval.transactionType, equals(TransactionType.solidarity));
},
);
verify(mockRepository.getApprovalById(tApprovalId));
verifyNoMoreInteractions(mockRepository);
});
test('should return approval with level 2 requirement', () async {
// Arrange
when(mockRepository.getApprovalById(tApprovalId))
.thenAnswer((_) async => Right(tApproval));
// Act
final result = await useCase(tApprovalId);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(approval) {
expect(approval.requiredLevel, equals(ApprovalLevel.level2));
},
);
});
test('should return ValidationFailure when approvalId is empty', () async {
// Act
final result = await useCase('');
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
},
(approval) => fail('Should not return approval'),
);
verifyZeroInteractions(mockRepository);
});
test('should return ServerFailure when approval not found', () async {
// Arrange
final tFailure = ServerFailure('Approbation non trouvée');
when(mockRepository.getApprovalById(any))
.thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase('nonexistent');
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(approval) => fail('Should not return approval'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/get_approval_by_id_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,116 @@
/// Tests unitaires pour GetBudgetById use case
library get_budget_by_id_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/get_budget_by_id.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'get_budget_by_id_test.mocks.dart';
void main() {
late GetBudgetById useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = GetBudgetById(mockRepository);
});
group('GetBudgetById Use Case', () {
const tBudgetId = 'budget-123';
final tBudget = Budget(
id: tBudgetId,
name: 'Budget Annuel 2024',
description: 'Budget prévisionnel pour l\'année 2024',
organizationId: 'org-123',
period: BudgetPeriod.annual,
year: 2024,
status: BudgetStatus.active,
lines: [],
totalPlanned: 5000000.0,
totalRealized: 3250000.0,
currency: 'XOF',
createdBy: 'user-1',
createdAt: DateTime(2024, 1, 1),
startDate: DateTime(2024, 1, 1),
endDate: DateTime(2024, 12, 31),
);
test('should return budget details by ID', () async {
// Arrange
when(mockRepository.getBudgetById(tBudgetId))
.thenAnswer((_) async => Right(tBudget));
// Act
final result = await useCase(tBudgetId);
// Assert
expect(result, Right(tBudget));
result.fold(
(failure) => fail('Should not return failure'),
(budget) {
expect(budget.id, equals(tBudgetId));
expect(budget.name, equals('Budget Annuel 2024'));
expect(budget.totalPlanned, equals(5000000.0));
},
);
verify(mockRepository.getBudgetById(tBudgetId));
verifyNoMoreInteractions(mockRepository);
});
test('should return budget with realized amount', () async {
// Arrange
when(mockRepository.getBudgetById(tBudgetId))
.thenAnswer((_) async => Right(tBudget));
// Act
final result = await useCase(tBudgetId);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(budget) {
expect(budget.totalRealized, equals(3250000.0));
expect(budget.totalRealized, lessThan(budget.totalPlanned));
},
);
});
test('should return ValidationFailure when budgetId is empty', () async {
// Act
final result = await useCase('');
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
},
(budget) => fail('Should not return budget'),
);
verifyZeroInteractions(mockRepository);
});
test('should return ServerFailure when budget not found', () async {
// Arrange
final tFailure = ServerFailure('Budget non trouvé');
when(mockRepository.getBudgetById(any))
.thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase('nonexistent');
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(budget) => fail('Should not return budget'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/get_budget_by_id_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,114 @@
/// Tests unitaires pour GetBudgetTracking use case
library get_budget_tracking_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/get_budget_tracking.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'get_budget_tracking_test.mocks.dart';
void main() {
late GetBudgetTracking useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = GetBudgetTracking(mockRepository);
});
group('GetBudgetTracking Use Case', () {
const tBudgetId = 'budget-123';
final tTrackingData = {
'budgetId': tBudgetId,
'totalPlanned': 5000000.0,
'totalRealized': 3250000.0,
'remainingAmount': 1750000.0,
'realizationRate': 0.65,
'categories': {
'contributions': {'planned': 2000000.0, 'realized': 1800000.0, 'rate': 0.9},
'savings': {'planned': 1500000.0, 'realized': 950000.0, 'rate': 0.63},
'solidarity': {'planned': 1000000.0, 'realized': 350000.0, 'rate': 0.35},
'events': {'planned': 500000.0, 'realized': 150000.0, 'rate': 0.3},
},
};
test('should return budget tracking data successfully', () async {
// Arrange
when(mockRepository.getBudgetTracking(budgetId: tBudgetId))
.thenAnswer((_) async => Right(tTrackingData));
// Act
final result = await useCase(budgetId: tBudgetId);
// Assert
expect(result, Right(tTrackingData));
result.fold(
(failure) => fail('Should not return failure'),
(tracking) {
expect(tracking['budgetId'], equals(tBudgetId));
expect(tracking['totalPlanned'], equals(5000000.0));
expect(tracking['realizationRate'], equals(0.65));
},
);
verify(mockRepository.getBudgetTracking(budgetId: tBudgetId));
verifyNoMoreInteractions(mockRepository);
});
test('should return tracking with category breakdown', () async {
// Arrange
when(mockRepository.getBudgetTracking(budgetId: tBudgetId))
.thenAnswer((_) async => Right(tTrackingData));
// Act
final result = await useCase(budgetId: tBudgetId);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(tracking) {
final categories = tracking['categories'] as Map<String, dynamic>;
expect(categories.keys, contains('contributions'));
expect(categories.keys, contains('solidarity'));
final contribs = categories['contributions'] as Map<String, dynamic>;
expect(contribs['rate'], equals(0.9));
},
);
});
test('should return ValidationFailure when budgetId is empty', () async {
// Act
final result = await useCase(budgetId: '');
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
},
(tracking) => fail('Should not return tracking'),
);
verifyZeroInteractions(mockRepository);
});
test('should return ServerFailure when repository fails', () async {
// Arrange
final tFailure = ServerFailure('Erreur suivi budget');
when(mockRepository.getBudgetTracking(budgetId: anyNamed('budgetId')))
.thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase(budgetId: tBudgetId);
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(tracking) => fail('Should not return tracking'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/get_budget_tracking_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,155 @@
/// Tests unitaires pour GetBudgets use case
library get_budgets_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/get_budgets.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'get_budgets_test.mocks.dart';
void main() {
late GetBudgets useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = GetBudgets(mockRepository);
});
group('GetBudgets Use Case', () {
final tBudgets = [
Budget(
id: 'budget-1',
name: 'Budget Annuel 2024',
organizationId: 'org-123',
period: BudgetPeriod.annual,
year: 2024,
status: BudgetStatus.active,
lines: [],
totalPlanned: 5000000.0,
totalRealized: 3250000.0,
currency: 'XOF',
createdBy: 'user-1',
createdAt: DateTime(2024, 1, 1),
startDate: DateTime(2024, 1, 1),
endDate: DateTime(2024, 12, 31),
),
Budget(
id: 'budget-2',
name: 'Budget Q4 2024',
organizationId: 'org-123',
period: BudgetPeriod.quarterly,
year: 2024,
month: 10,
status: BudgetStatus.active,
lines: [],
totalPlanned: 1250000.0,
totalRealized: 850000.0,
currency: 'XOF',
createdBy: 'user-1',
createdAt: DateTime(2024, 10, 1),
startDate: DateTime(2024, 10, 1),
endDate: DateTime(2024, 12, 31),
),
];
test('should return list of budgets successfully', () async {
// Arrange
when(mockRepository.getBudgets(
organizationId: anyNamed('organizationId'),
status: anyNamed('status'),
year: anyNamed('year'),
)).thenAnswer((_) async => Right(tBudgets));
// Act
final result = await useCase(organizationId: 'org-123');
// Assert
expect(result, Right(tBudgets));
result.fold(
(failure) => fail('Should not return failure'),
(budgets) {
expect(budgets.length, equals(2));
expect(budgets[0].name, equals('Budget Annuel 2024'));
expect(budgets[0].totalPlanned, equals(5000000.0));
},
);
verify(mockRepository.getBudgets(
organizationId: 'org-123',
status: null,
year: null,
));
verifyNoMoreInteractions(mockRepository);
});
test('should filter budgets by status and year', () async {
// Arrange
final activeBudgets = [tBudgets[0], tBudgets[1]];
when(mockRepository.getBudgets(
organizationId: 'org-123',
status: BudgetStatus.active,
year: 2024,
)).thenAnswer((_) async => Right(activeBudgets));
// Act
final result = await useCase(
organizationId: 'org-123',
status: BudgetStatus.active,
year: 2024,
);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(budgets) {
expect(budgets.every((b) => b.status == BudgetStatus.active), isTrue);
expect(budgets.every((b) => b.year == 2024), isTrue);
},
);
});
test('should return empty list when no budgets exist', () async {
// Arrange
when(mockRepository.getBudgets(
organizationId: anyNamed('organizationId'),
status: anyNamed('status'),
year: anyNamed('year'),
)).thenAnswer((_) async => Right([]));
// Act
final result = await useCase();
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(budgets) => expect(budgets, isEmpty),
);
});
test('should return ServerFailure when repository fails', () async {
// Arrange
final tFailure = ServerFailure('Erreur serveur');
when(mockRepository.getBudgets(
organizationId: anyNamed('organizationId'),
status: anyNamed('status'),
year: anyNamed('year'),
)).thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase();
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(budgets) => fail('Should not return budgets'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/get_budgets_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,132 @@
/// Tests unitaires pour GetPendingApprovals use case
library get_pending_approvals_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/get_pending_approvals.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'get_pending_approvals_test.mocks.dart';
void main() {
late GetPendingApprovals useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = GetPendingApprovals(mockRepository);
});
group('GetPendingApprovals Use Case', () {
final tApprovals = [
TransactionApproval(
id: 'approval-1',
transactionId: 'tx-123',
transactionType: TransactionType.withdrawal,
amount: 500000.0,
currency: 'XOF',
requesterId: 'user-1',
requesterName: 'Amadou Diallo',
organizationId: 'org-123',
requiredLevel: ApprovalLevel.level2,
status: ApprovalStatus.pending,
approvers: [],
createdAt: DateTime(2024, 12, 15),
),
TransactionApproval(
id: 'approval-2',
transactionId: 'tx-456',
transactionType: TransactionType.solidarity,
amount: 200000.0,
currency: 'XOF',
requesterId: 'user-2',
requesterName: 'Fatou Ndiaye',
requiredLevel: ApprovalLevel.level1,
status: ApprovalStatus.pending,
approvers: [],
createdAt: DateTime(2024, 12, 14),
),
];
test('should return list of pending approvals successfully', () async {
// Arrange
when(mockRepository.getPendingApprovals(
organizationId: anyNamed('organizationId'),
)).thenAnswer((_) async => Right(tApprovals));
// Act
final result = await useCase(organizationId: 'org-123');
// Assert
expect(result, Right(tApprovals));
result.fold(
(failure) => fail('Should not return failure'),
(approvals) {
expect(approvals.length, equals(2));
expect(approvals[0].status, equals(ApprovalStatus.pending));
expect(approvals[0].amount, equals(500000.0));
},
);
verify(mockRepository.getPendingApprovals(organizationId: 'org-123'));
verifyNoMoreInteractions(mockRepository);
});
test('should return approvals with different levels', () async {
// Arrange
when(mockRepository.getPendingApprovals(
organizationId: anyNamed('organizationId'),
)).thenAnswer((_) async => Right(tApprovals));
// Act
final result = await useCase();
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(approvals) {
expect(approvals.any((a) => a.requiredLevel == ApprovalLevel.level2), isTrue);
expect(approvals.any((a) => a.requiredLevel == ApprovalLevel.level1), isTrue);
},
);
});
test('should return empty list when no pending approvals', () async {
// Arrange
when(mockRepository.getPendingApprovals(
organizationId: anyNamed('organizationId'),
)).thenAnswer((_) async => Right([]));
// Act
final result = await useCase();
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(approvals) => expect(approvals, isEmpty),
);
});
test('should return ServerFailure when repository fails', () async {
// Arrange
final tFailure = ServerFailure('Erreur serveur');
when(mockRepository.getPendingApprovals(
organizationId: anyNamed('organizationId'),
)).thenAnswer((_) async => Left(tFailure));
// Act
final result = await useCase();
// Assert
expect(result, Left(tFailure));
result.fold(
(failure) => expect(failure, isA<ServerFailure>()),
(approvals) => fail('Should not return approvals'),
);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/get_pending_approvals_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}

View File

@@ -0,0 +1,116 @@
/// Tests unitaires pour RejectTransaction use case
library reject_transaction_test;
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/reject_transaction.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
@GenerateMocks([FinanceWorkflowRepository])
import 'reject_transaction_test.mocks.dart';
void main() {
late RejectTransaction useCase;
late MockFinanceWorkflowRepository mockRepository;
setUp(() {
mockRepository = MockFinanceWorkflowRepository();
useCase = RejectTransaction(mockRepository);
});
group('RejectTransaction Use Case', () {
const tApprovalId = 'approval-123';
const tReason = 'Montant trop élevé - Budget insuffisant';
final tRejectedTransaction = TransactionApproval(
id: tApprovalId,
transactionId: 'tx-123',
transactionType: TransactionType.withdrawal,
amount: 500000.0,
currency: 'XOF',
requesterId: 'user-1',
requesterName: 'Amadou Diallo',
requiredLevel: ApprovalLevel.level2,
status: ApprovalStatus.rejected,
approvers: [],
createdAt: DateTime(2024, 12, 15),
);
test('should reject transaction successfully', () async {
// Arrange
when(mockRepository.rejectTransaction(
approvalId: tApprovalId,
reason: tReason,
)).thenAnswer((_) async => Right(tRejectedTransaction));
// Act
final result = await useCase(approvalId: tApprovalId, reason: tReason);
// Assert
expect(result, Right(tRejectedTransaction));
result.fold(
(failure) => fail('Should not return failure'),
(approval) {
expect(approval.id, equals(tApprovalId));
expect(approval.status, equals(ApprovalStatus.rejected));
},
);
verify(mockRepository.rejectTransaction(
approvalId: tApprovalId,
reason: tReason,
));
verifyNoMoreInteractions(mockRepository);
});
test('should reject transaction with detailed reason', () async {
// Arrange
const detailedReason = 'Refus: Documentation incomplète + montant non justifié';
when(mockRepository.rejectTransaction(
approvalId: tApprovalId,
reason: detailedReason,
)).thenAnswer((_) async => Right(tRejectedTransaction));
// Act
final result = await useCase(approvalId: tApprovalId, reason: detailedReason);
// Assert
result.fold(
(failure) => fail('Should not return failure'),
(approval) => expect(approval.status, equals(ApprovalStatus.rejected)),
);
});
test('should return ValidationFailure when approvalId is empty', () async {
// Act
final result = await useCase(approvalId: '', reason: tReason);
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
expect((failure as ValidationFailure).message, contains('ID approbation requis'));
},
(approval) => fail('Should not return approval'),
);
verifyZeroInteractions(mockRepository);
});
test('should return ValidationFailure when reason is empty', () async {
// Act
final result = await useCase(approvalId: tApprovalId, reason: ' ');
// Assert
result.fold(
(failure) {
expect(failure, isA<ValidationFailure>());
expect((failure as ValidationFailure).message, contains('Raison du rejet requise'));
},
(approval) => fail('Should not return approval'),
);
verifyZeroInteractions(mockRepository);
});
});
}

View File

@@ -0,0 +1,534 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in unionflow_mobile_apps/test/features/finance_workflow/domain/usecases/reject_transaction_test.dart.
// Do not manually edit this file.
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'package:dartz/dartz.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:unionflow_mobile_apps/core/error/failures.dart' as _i5;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart'
as _i7;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/financial_audit_log.dart'
as _i8;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/transaction_approval.dart'
as _i6;
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart'
as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
class _FakeEither_0<L, R> extends _i1.SmartFake implements _i2.Either<L, R> {
_FakeEither_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}
/// A class which mocks [FinanceWorkflowRepository].
///
/// See the documentation for Mockito's code generation for more information.
class MockFinanceWorkflowRepository extends _i1.Mock
implements _i3.FinanceWorkflowRepository {
MockFinanceWorkflowRepository() {
_i1.throwOnMissingStub(this);
}
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getPendingApprovals({String? organizationId}) => (super.noSuchMethod(
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getPendingApprovals,
[],
{#organizationId: organizationId},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> getApprovalById(
String? approvalId) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalById,
[approvalId],
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#getApprovalById,
[approvalId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> approveTransaction({
required String? approvalId,
String? comment,
}) =>
(super.noSuchMethod(
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#approveTransaction,
[],
{
#approvalId: approvalId,
#comment: comment,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, _i6.TransactionApproval>> rejectTransaction({
required String? approvalId,
required String? reason,
}) =>
(super.noSuchMethod(
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#rejectTransaction,
[],
{
#approvalId: approvalId,
#reason: reason,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>> requestApproval({
required String? transactionId,
required _i6.TransactionType? transactionType,
required double? amount,
}) =>
(super.noSuchMethod(
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>.value(
_FakeEither_0<_i5.Failure, _i6.TransactionApproval>(
this,
Invocation.method(
#requestApproval,
[],
{
#transactionId: transactionId,
#transactionType: transactionType,
#amount: amount,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i6.TransactionApproval>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>
getApprovalsHistory({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i6.ApprovalStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
returnValue: _i4.Future<
_i2
.Either<_i5.Failure, List<_i6.TransactionApproval>>>.value(
_FakeEither_0<_i5.Failure, List<_i6.TransactionApproval>>(
this,
Invocation.method(
#getApprovalsHistory,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#status: status,
},
),
)),
) as _i4
.Future<_i2.Either<_i5.Failure, List<_i6.TransactionApproval>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>> getBudgets({
String? organizationId,
_i7.BudgetStatus? status,
int? year,
}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>.value(
_FakeEither_0<_i5.Failure, List<_i7.Budget>>(
this,
Invocation.method(
#getBudgets,
[],
{
#organizationId: organizationId,
#status: status,
#year: year,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i7.Budget>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> getBudgetById(
String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetById,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#getBudgetById,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> createBudget({
required String? name,
String? description,
required String? organizationId,
required _i7.BudgetPeriod? period,
required int? year,
int? month,
required List<_i7.BudgetLine>? lines,
}) =>
(super.noSuchMethod(
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#createBudget,
[],
{
#name: name,
#description: description,
#organizationId: organizationId,
#period: period,
#year: year,
#month: month,
#lines: lines,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, _i7.Budget>> updateBudget({
required String? budgetId,
String? name,
String? description,
List<_i7.BudgetLine>? lines,
_i7.BudgetStatus? status,
}) =>
(super.noSuchMethod(
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>.value(
_FakeEither_0<_i5.Failure, _i7.Budget>(
this,
Invocation.method(
#updateBudget,
[],
{
#budgetId: budgetId,
#name: name,
#description: description,
#lines: lines,
#status: status,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, _i7.Budget>>);
@override
_i4.Future<_i2.Either<_i5.Failure, void>> deleteBudget(String? budgetId) =>
(super.noSuchMethod(
Invocation.method(
#deleteBudget,
[budgetId],
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, void>>.value(
_FakeEither_0<_i5.Failure, void>(
this,
Invocation.method(
#deleteBudget,
[budgetId],
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, void>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getBudgetTracking(
{required String? budgetId}) =>
(super.noSuchMethod(
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getBudgetTracking,
[],
{#budgetId: budgetId},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAuditLogs({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
_i8.AuditOperation? operation,
_i8.AuditEntityType? entityType,
_i8.AuditSeverity? severity,
int? limit,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#operation: operation,
#entityType: entityType,
#severity: severity,
#limit: limit,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<
_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>> getAnomalies({
String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue: _i4
.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>.value(
_FakeEither_0<_i5.Failure, List<_i8.FinancialAuditLog>>(
this,
Invocation.method(
#getAnomalies,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, List<_i8.FinancialAuditLog>>>);
@override
_i4.Future<_i2.Either<_i5.Failure, String>> exportAuditLogs({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
String? format = r'csv',
}) =>
(super.noSuchMethod(
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
returnValue: _i4.Future<_i2.Either<_i5.Failure, String>>.value(
_FakeEither_0<_i5.Failure, String>(
this,
Invocation.method(
#exportAuditLogs,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
#format: format,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, String>>);
@override
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>> getWorkflowStats({
required String? organizationId,
DateTime? startDate,
DateTime? endDate,
}) =>
(super.noSuchMethod(
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
returnValue:
_i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>.value(
_FakeEither_0<_i5.Failure, Map<String, dynamic>>(
this,
Invocation.method(
#getWorkflowStats,
[],
{
#organizationId: organizationId,
#startDate: startDate,
#endDate: endDate,
},
),
)),
) as _i4.Future<_i2.Either<_i5.Failure, Map<String, dynamic>>>);
}