create(); Sanctum::actingAs($user); return $user; } protected function tearDown(): void { Mockery::close(); parent::tearDown(); } public function test_form_data_returns_success_response(): void { $this->authenticate(); $mock = Mockery::mock(BadgeFormDataService::class); $mock->shouldReceive('build') ->once() ->with('2025-2026', [10, 20], 'teacher') ->andReturn([ 'users' => [], 'schoolYears' => ['2025-2026'], 'selectedYear' => '2025-2026', 'selectedUserIds' => [10, 20], 'rolesTabs' => ['teacher' => 'Teachers'], 'active_role' => 'teacher', ]); $this->app->instance(BadgeFormDataService::class, $mock); $response = $this->getJson('/api/badges/form-data?school_year=2025-2026&user_ids=10,20&active_role=teacher'); $response->assertOk() ->assertJson([ 'ok' => true, 'data' => [ 'selectedYear' => '2025-2026', 'selectedUserIds' => [10, 20], 'active_role' => 'teacher', ], ]); } public function test_print_status_returns_success_response(): void { $this->authenticate(); $mock = Mockery::mock(BadgePrintLogService::class); $mock->shouldReceive('getStatus') ->once() ->with([5, 7], '2025-2026') ->andReturn([ 5 => [ 'count' => 2, 'last_printed_at' => '2026-03-06 12:00:00', 'last_printed_by' => 1, ], ]); $this->app->instance(BadgePrintLogService::class, $mock); $response = $this->getJson('/api/badges/print-status?user_ids=5,7&school_year=2025-2026'); $response->assertOk() ->assertJson([ 'ok' => true, 'data' => [ '5' => [ 'count' => 2, 'last_printed_at' => '2026-03-06 12:00:00', 'last_printed_by' => 1, ], ], ]); } public function test_print_status_returns_500_when_service_throws(): void { $this->authenticate(); $mock = Mockery::mock(BadgePrintLogService::class); $mock->shouldReceive('getStatus') ->once() ->andThrow(new \RuntimeException('db failed')); $this->app->instance(BadgePrintLogService::class, $mock); $response = $this->getJson('/api/badges/print-status?user_ids=5,7'); $response->assertStatus(500) ->assertJson([ 'ok' => false, 'error' => 'Failed to query status', ]); } public function test_log_print_returns_success_response(): void { $authUser = $this->authenticate(); $mock = Mockery::mock(BadgePrintLogService::class); $mock->shouldReceive('log') ->once() ->with( [10, 20], $authUser->id, '2025-2026', ['10' => 'Teacher'], ['10' => '3-A'] ) ->andReturn(2); $this->app->instance(BadgePrintLogService::class, $mock); $response = $this->postJson('/api/badges/log-print', [ 'user_ids' => [10, 20], 'school_year' => '2025-2026', 'roles' => ['10' => 'Teacher'], 'classes' => ['10' => '3-A'], ]); $response->assertOk() ->assertJson([ 'ok' => true, 'inserted' => 2, ]); } public function test_log_print_returns_500_when_service_throws(): void { $this->authenticate(); $mock = Mockery::mock(BadgePrintLogService::class); $mock->shouldReceive('log') ->once() ->andThrow(new \RuntimeException('insert failed')); $this->app->instance(BadgePrintLogService::class, $mock); $response = $this->postJson('/api/badges/log-print', [ 'user_ids' => [10], ]); $response->assertStatus(500) ->assertJson([ 'ok' => false, 'error' => 'insert failed', ]); } public function test_generate_pdf_returns_pdf_response(): void { $authUser = $this->authenticate(); $mock = Mockery::mock(BadgePdfService::class); $mock->shouldReceive('generate') ->once() ->with( [10, 20], '2025-2026', ['10' => 'Teacher'], ['10' => '3-A'], $authUser->id ) ->andReturn(response('fake-pdf-content', 200, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline; filename="Staff_Badges.pdf"', ])); $this->app->instance(BadgePdfService::class, $mock); $response = $this->post('/api/badges/pdf', [ 'user_ids' => [10, 20], 'school_year' => '2025-2026', 'roles' => ['10' => 'Teacher'], 'classes' => ['10' => '3-A'], ]); $response->assertOk(); $response->assertHeader('Content-Type', 'application/pdf'); $this->assertStringContainsString( 'inline; filename="Staff_Badges.pdf"', $response->headers->get('Content-Disposition') ); $this->assertSame('fake-pdf-content', $response->getContent()); } public function test_generate_pdf_validates_required_user_ids(): void { $this->authenticate(); $response = $this->postJson('/api/badges/pdf', [ 'school_year' => '2025-2026', ]); $response->assertStatus(422) ->assertJsonValidationErrors(['user_ids']); } public function test_log_print_validates_required_user_ids(): void { $this->authenticate(); $response = $this->postJson('/api/badges/log-print', []); $response->assertStatus(422) ->assertJsonValidationErrors(['user_ids']); } public function test_endpoints_require_authentication(): void { $this->getJson('/api/badges/form-data')->assertStatus(401); $this->getJson('/api/badges/print-status')->assertStatus(401); $this->postJson('/api/badges/log-print', ['user_ids' => [1]])->assertStatus(401); $this->postJson('/api/badges/pdf', ['user_ids' => [1]])->assertStatus(401); } }