shouldReceive('list') ->once() ->with(false) ->andReturn([ [ 'id' => 1, 'min_score' => 0, 'max_score' => 59, 'template_text' => 'Needs improvement', 'is_active' => true, ], [ 'id' => 2, 'min_score' => 60, 'max_score' => 79, 'template_text' => 'Good effort', 'is_active' => true, ], ]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->getJson('/api/attendance-comment-templates'); $response->assertOk() ->assertJson([ 'status' => 'success', ]) ->assertJsonCount(2, 'data') ->assertJsonPath('data.0.id', 1) ->assertJsonPath('data.1.max_score', 79); } public function test_can_list_templates_active_only(): void { $mock = Mockery::mock(AttendanceCommentTemplateService::class); $mock->shouldReceive('list') ->once() ->with(true) ->andReturn([]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->getJson('/api/attendance-comment-templates?active_only=1'); $response->assertOk() ->assertJson([ 'status' => 'success', 'data' => [], ]); } public function test_can_create_template(): void { $payload = [ 'min_score' => 80, 'max_score' => 100, 'template_text' => 'Excellent attendance and punctuality.', 'is_active' => true, ]; $mock = Mockery::mock(AttendanceCommentTemplateService::class); $mock->shouldReceive('create') ->once() ->with(Mockery::on(function ($data) use ($payload) { return (int) $data['min_score'] === 80 && (int) $data['max_score'] === 100 && $data['template_text'] === $payload['template_text'] && (bool) $data['is_active'] === true; })) ->andReturn([ 'id' => 10, 'min_score' => 80, 'max_score' => 100, 'template_text' => 'Excellent attendance and punctuality.', 'is_active' => true, ]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->postJson('/api/attendance-comment-templates', $payload); $response->assertCreated() ->assertJsonPath('status', 'success') ->assertJsonPath('data.id', 10) ->assertJsonPath('data.min_score', 80) ->assertJsonPath('data.max_score', 100); } public function test_store_validation_fails_when_max_less_than_min(): void { $payload = [ 'min_score' => 90, 'max_score' => 70, 'template_text' => 'Invalid range', 'is_active' => true, ]; $response = $this->postJson('/api/attendance-comment-templates', $payload); $response->assertStatus(422) ->assertJsonValidationErrors(['max_score']); } public function test_can_show_template(): void { $mock = Mockery::mock(AttendanceCommentTemplateService::class); $mock->shouldReceive('findOrFail') ->once() ->with(5) ->andReturn([ 'id' => 5, 'min_score' => 60, 'max_score' => 69, 'template_text' => 'Average attendance', 'is_active' => true, ]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->getJson('/api/attendance-comment-templates/5'); $response->assertOk() ->assertJsonPath('status', 'success') ->assertJsonPath('data.id', 5); } public function test_can_update_template(): void { $payload = [ 'template_text' => 'Updated comment text', 'is_active' => false, ]; $mock = Mockery::mock(AttendanceCommentTemplateService::class); $mock->shouldReceive('update') ->once() ->with(7, Mockery::on(function ($data) { return $data['template_text'] === 'Updated comment text' && (bool) $data['is_active'] === false; })) ->andReturn([ 'id' => 7, 'min_score' => 70, 'max_score' => 79, 'template_text' => 'Updated comment text', 'is_active' => false, ]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->putJson('/api/attendance-comment-templates/7', $payload); $response->assertOk() ->assertJsonPath('status', 'success') ->assertJsonPath('data.id', 7) ->assertJsonPath('data.is_active', false); } public function test_update_validation_fails_if_both_scores_invalid_relation(): void { $payload = [ 'min_score' => 50, 'max_score' => 20, ]; $response = $this->putJson('/api/attendance-comment-templates/7', $payload); $response->assertStatus(422) ->assertJsonValidationErrors(['max_score']); } public function test_can_delete_template(): void { $mock = Mockery::mock(AttendanceCommentTemplateService::class); $mock->shouldReceive('delete') ->once() ->with(12); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->deleteJson('/api/attendance-comment-templates/12'); $response->assertOk() ->assertJsonPath('status', 'success') ->assertJsonPath('message', 'Template deleted successfully.'); } public function test_legacy_list_data_endpoint_returns_templates_key(): void { $mock = Mockery::mock(AttendanceCommentTemplateService::class); $mock->shouldReceive('list') ->once() ->with(false) ->andReturn([ [ 'id' => 1, 'min_score' => 0, 'max_score' => 49, 'template_text' => 'Low attendance', 'is_active' => true, ], ]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); $response = $this->getJson('/api/attendance-comment-templates/list-data'); $response->assertOk() ->assertJsonCount(1, 'templates') ->assertJsonPath('templates.0.id', 1); } }