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,265 @@
/// Integration tests for Finance Workflow API (Pure Dart - no Flutter binding)
library finance_workflow_api_test;
import 'dart:convert';
import 'package:test/test.dart';
import 'package:http/http.dart' as http;
import 'helpers/test_config.dart';
import 'helpers/auth_helper.dart';
void main() {
late http.Client client;
late AuthHelper authHelper;
setUpAll(() async {
print('\n╔═══════════════════════════════════════════════╗');
print('║ Finance Workflow Integration Tests (API) ║');
print('╚═══════════════════════════════════════════════╝\n');
client = http.Client();
authHelper = AuthHelper(client);
print('→ Authenticating as ${TestConfig.testOrgAdminUsername}...');
final authenticated = await authHelper.authenticateAsOrgAdmin();
if (!authenticated) {
print('✗ Authentication FAILED');
throw Exception('Authentication failed - check Keycloak and credentials');
}
print('✓ Authentication successful\n');
});
tearDownAll(() {
client.close();
print('\n╔═══════════════════════════════════════════════╗');
print('║ Integration Tests Completed ║');
print('╚═══════════════════════════════════════════════╝\n');
});
group('Finance Workflow - Approvals API', () {
test('GET /api/finance/approvals/pending - List pending approvals', () async {
print('\n[TEST] GET pending approvals...');
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/approvals/pending')
.replace(queryParameters: {'organizationId': TestConfig.testOrganizationId});
final response = await client.get(url, headers: authHelper.getAuthHeaders());
expect(response.statusCode, equals(200), reason: 'HTTP 200 OK expected');
final List<dynamic> approvals = json.decode(response.body);
expect(approvals, isA<List>());
print(' ✓ Status: ${response.statusCode}');
print(' ✓ Approvals found: ${approvals.length}');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
test('GET /api/finance/approvals/{id} - Get approval by ID', () async {
print('\n[TEST] GET approval by ID...');
// First, get list of approvals
final listUrl = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/approvals/pending')
.replace(queryParameters: {'organizationId': TestConfig.testOrganizationId});
final listResponse = await client.get(listUrl, headers: authHelper.getAuthHeaders());
expect(listResponse.statusCode, equals(200));
final List<dynamic> approvals = json.decode(listResponse.body);
if (approvals.isEmpty) {
print(' ⚠ No pending approvals - test skipped');
return;
}
final approvalId = approvals.first['id'];
// Get specific approval
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/approvals/$approvalId');
final response = await client.get(url, headers: authHelper.getAuthHeaders());
expect(response.statusCode, equals(200));
final approval = json.decode(response.body);
expect(approval['id'], equals(approvalId));
print(' ✓ Status: ${response.statusCode}');
print(' ✓ Approval ID: ${approval['id']}');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
});
group('Finance Workflow - Budgets API', () {
String? createdBudgetId;
test('GET /api/finance/budgets - List budgets', () async {
print('\n[TEST] GET budgets list...');
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets')
.replace(queryParameters: {'organizationId': TestConfig.testOrganizationId});
final response = await client.get(url, headers: authHelper.getAuthHeaders());
expect(response.statusCode, equals(200));
final List<dynamic> budgets = json.decode(response.body);
expect(budgets, isA<List>());
print(' ✓ Status: ${response.statusCode}');
print(' ✓ Budgets found: ${budgets.length}');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
test('POST /api/finance/budgets - Create budget', () async {
print('\n[TEST] POST create budget...');
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets');
final timestamp = DateTime.now().millisecondsSinceEpoch;
final requestBody = {
'name': 'Budget Integration Test $timestamp',
'description': 'Budget created by automated integration test',
'organizationId': TestConfig.testOrganizationId,
'period': 'ANNUAL',
'year': DateTime.now().year,
'lines': [
{
'category': 'CONTRIBUTIONS',
'name': 'Member Contributions',
'amountPlanned': 1000000.0,
'description': 'Monthly member contributions',
},
{
'category': 'SAVINGS',
'name': 'Savings Deposits',
'amountPlanned': 500000.0,
'description': 'Member savings deposits',
},
],
};
final response = await client.post(
url,
headers: authHelper.getAuthHeaders(),
body: json.encode(requestBody),
);
expect(response.statusCode, inInclusiveRange(200, 201));
final budget = json.decode(response.body);
expect(budget['id'], isNotNull);
expect(budget['name'], contains('Budget Integration Test'));
createdBudgetId = budget['id'];
print(' ✓ Status: ${response.statusCode}');
print(' ✓ Budget created: ${budget['id']}');
print(' ✓ Budget name: ${budget['name']}');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
test('GET /api/finance/budgets/{id} - Get budget by ID', () async {
print('\n[TEST] GET budget by ID...');
String budgetId;
if (createdBudgetId != null) {
budgetId = createdBudgetId!;
} else {
// Fetch any existing budget
final listUrl = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets')
.replace(queryParameters: {'organizationId': TestConfig.testOrganizationId});
final listResponse = await client.get(listUrl, headers: authHelper.getAuthHeaders());
expect(listResponse.statusCode, equals(200));
final List<dynamic> budgets = json.decode(listResponse.body);
if (budgets.isEmpty) {
print(' ⚠ No budgets found - test skipped');
return;
}
budgetId = budgets.first['id'];
}
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets/$budgetId');
final response = await client.get(url, headers: authHelper.getAuthHeaders());
expect(response.statusCode, equals(200));
final budget = json.decode(response.body);
expect(budget['id'], equals(budgetId));
expect(budget['lines'], isNotNull);
print(' ✓ Status: ${response.statusCode}');
print(' ✓ Budget ID: ${budget['id']}');
print(' ✓ Budget name: ${budget['name']}');
print(' ✓ Budget lines: ${budget['lines'].length}');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
});
group('Finance Workflow - Negative Tests', () {
test('GET nonexistent approval - Should return 404', () async {
print('\n[TEST] GET nonexistent approval (expect 404)...');
final fakeId = '00000000-0000-0000-0000-000000000000';
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/approvals/$fakeId');
final response = await client.get(url, headers: authHelper.getAuthHeaders());
expect(response.statusCode, equals(404));
print(' ✓ Status: ${response.statusCode} (404 as expected)');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
test('GET nonexistent budget - Should return 404', () async {
print('\n[TEST] GET nonexistent budget (expect 404)...');
final fakeId = '00000000-0000-0000-0000-000000000000';
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets/$fakeId');
final response = await client.get(url, headers: authHelper.getAuthHeaders());
expect(response.statusCode, equals(404));
print(' ✓ Status: ${response.statusCode} (404 as expected)');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
test('POST budget without auth - Should return 401', () async {
print('\n[TEST] POST budget without authentication (expect 401)...');
final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets');
final requestBody = {
'name': 'Unauthorized Budget',
'organizationId': TestConfig.testOrganizationId,
'period': 'ANNUAL',
'year': 2026,
'lines': [],
};
final response = await client.post(
url,
headers: {'Content-Type': 'application/json'},
body: json.encode(requestBody),
);
expect(response.statusCode, equals(401));
print(' ✓ Status: ${response.statusCode} (401 as expected)');
await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
});
});
}