Add test coverage for: - ReportTest: 9 tests for reporting API (payload, view types, filters, validation) - ProjectMonthPlanTest: CRUD operations for monthly planning - UntrackedAllocationTest: untracked allocation handling - ReconciliationCalculatorTest: plan vs estimate reconciliation logic - VarianceCalculatorTest: variance and status calculations All tests passing (157 total).
114 lines
3.7 KiB
PHP
114 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Project;
|
|
use App\Models\Role;
|
|
use App\Models\TeamMember;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class UntrackedAllocationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function loginAsManager()
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'manager@test.com',
|
|
'password' => bcrypt('password123'),
|
|
'role' => 'manager',
|
|
'active' => true,
|
|
]);
|
|
|
|
$response = $this->postJson('/api/auth/login', [
|
|
'email' => 'manager@test.com',
|
|
'password' => 'password123',
|
|
]);
|
|
|
|
return $response->json('access_token');
|
|
}
|
|
|
|
public function test_create_allocation_accepts_null_team_member_id(): void
|
|
{
|
|
$token = $this->loginAsManager();
|
|
$project = Project::factory()->create();
|
|
|
|
$response = $this->withHeader('Authorization', "Bearer {$token}")
|
|
->postJson('/api/allocations', [
|
|
'project_id' => $project->id,
|
|
'team_member_id' => null,
|
|
'month' => '2026-02',
|
|
'allocated_hours' => 40,
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$this->assertDatabaseHas('allocations', [
|
|
'project_id' => $project->id,
|
|
'team_member_id' => null,
|
|
'allocated_hours' => 40,
|
|
]);
|
|
}
|
|
|
|
public function test_bulk_create_accepts_mixed_tracked_and_untracked(): void
|
|
{
|
|
$token = $this->loginAsManager();
|
|
$project = Project::factory()->create();
|
|
$role = Role::factory()->create();
|
|
$teamMember = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);
|
|
|
|
$response = $this->withHeader('Authorization', "Bearer {$token}")
|
|
->postJson('/api/allocations/bulk', [
|
|
'allocations' => [
|
|
[
|
|
'project_id' => $project->id,
|
|
'team_member_id' => $teamMember->id,
|
|
'month' => '2026-02',
|
|
'allocated_hours' => 40,
|
|
],
|
|
[
|
|
'project_id' => $project->id,
|
|
'team_member_id' => null,
|
|
'month' => '2026-02',
|
|
'allocated_hours' => 30,
|
|
],
|
|
],
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$this->assertDatabaseCount('allocations', 2);
|
|
}
|
|
|
|
public function test_partial_bulk_persists_valid_rows(): void
|
|
{
|
|
$token = $this->loginAsManager();
|
|
$project = Project::factory()->create();
|
|
$role = Role::factory()->create();
|
|
$teamMember = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);
|
|
|
|
$response = $this->withHeader('Authorization', "Bearer {$token}")
|
|
->postJson('/api/allocations/bulk', [
|
|
'allocations' => [
|
|
[
|
|
'project_id' => $project->id,
|
|
'team_member_id' => $teamMember->id,
|
|
'month' => '2026-02',
|
|
'allocated_hours' => 40,
|
|
],
|
|
[
|
|
'project_id' => 'invalid-uuid',
|
|
'team_member_id' => $teamMember->id,
|
|
'month' => '2026-02',
|
|
'allocated_hours' => 20,
|
|
],
|
|
],
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$response->assertJsonPath('summary.created', 1);
|
|
$response->assertJsonPath('summary.failed', 1);
|
|
$this->assertDatabaseCount('allocations', 1);
|
|
}
|
|
}
|