tenant = Tenant::factory()->create(); $this->user = User::factory()->create(); // Associate user with tenant $this->user->tenants()->attach($this->tenant->id, ['is_active' => true, 'is_default' => true]); // Create test design model $this->model = DesignModel::factory()->create([ 'tenant_id' => $this->tenant->id, 'code' => 'TEST01', 'name' => 'Test Model', 'is_active' => true ]); // Authenticate user Sanctum::actingAs($this->user, ['*']); Auth::login($this->user); } /** @test */ public function can_create_model_parameter() { $parameterData = [ 'model_id' => $this->model->id, 'parameter_name' => 'width', 'parameter_type' => 'NUMBER', 'is_required' => true, 'default_value' => '800', 'min_value' => 100, 'max_value' => 2000, 'unit' => 'mm', 'description' => 'Width parameter for model', 'sort_order' => 1 ]; $response = $this->postJson('/api/v1/design/model-parameters', $parameterData); $response->assertStatus(201) ->assertJson([ 'success' => true, 'message' => 'message.created' ]); $this->assertDatabaseHas('model_parameters', [ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_name' => 'width', 'parameter_type' => 'NUMBER' ]); } /** @test */ public function can_list_model_parameters() { // Create test parameters ModelParameter::factory()->count(3)->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id ]); $response = $this->getJson('/api/v1/design/model-parameters?model_id=' . $this->model->id); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'message.fetched' ]) ->assertJsonStructure([ 'data' => [ 'data' => [ '*' => [ 'id', 'parameter_name', 'parameter_type', 'is_required', 'default_value', 'min_value', 'max_value', 'unit', 'description', 'sort_order' ] ] ] ]); } /** @test */ public function can_show_model_parameter() { $parameter = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_name' => 'height', 'parameter_type' => 'NUMBER' ]); $response = $this->getJson('/api/v1/design/model-parameters/' . $parameter->id); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'message.fetched', 'data' => [ 'id' => $parameter->id, 'parameter_name' => 'height', 'parameter_type' => 'NUMBER' ] ]); } /** @test */ public function can_update_model_parameter() { $parameter = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_name' => 'depth', 'min_value' => 50 ]); $updateData = [ 'parameter_name' => 'depth_updated', 'min_value' => 100, 'max_value' => 500, 'description' => 'Updated depth parameter' ]; $response = $this->putJson('/api/v1/design/model-parameters/' . $parameter->id, $updateData); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'message.updated' ]); $this->assertDatabaseHas('model_parameters', [ 'id' => $parameter->id, 'parameter_name' => 'depth_updated', 'min_value' => 100, 'max_value' => 500 ]); } /** @test */ public function can_delete_model_parameter() { $parameter = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id ]); $response = $this->deleteJson('/api/v1/design/model-parameters/' . $parameter->id); $response->assertStatus(200) ->assertJson([ 'success' => true, 'message' => 'message.deleted' ]); $this->assertSoftDeleted('model_parameters', [ 'id' => $parameter->id ]); } /** @test */ public function validates_parameter_type_and_constraints() { // Test NUMBER type with invalid range $invalidData = [ 'model_id' => $this->model->id, 'parameter_name' => 'invalid_width', 'parameter_type' => 'NUMBER', 'min_value' => 1000, 'max_value' => 500 // max < min ]; $response = $this->postJson('/api/v1/design/model-parameters', $invalidData); $response->assertStatus(422); // Test SELECT type with options $validSelectData = [ 'model_id' => $this->model->id, 'parameter_name' => 'screen_type', 'parameter_type' => 'SELECT', 'options' => ['FABRIC', 'STEEL', 'PLASTIC'], 'default_value' => 'FABRIC' ]; $response = $this->postJson('/api/v1/design/model-parameters', $validSelectData); $response->assertStatus(201); } /** @test */ public function can_validate_parameter_values() { // Create NUMBER parameter $numberParam = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_name' => 'test_number', 'parameter_type' => 'NUMBER', 'min_value' => 100, 'max_value' => 1000 ]); // Test valid value $this->assertTrue($numberParam->validateValue(500)); // Test invalid values $this->assertFalse($numberParam->validateValue(50)); // below min $this->assertFalse($numberParam->validateValue(1500)); // above max $this->assertFalse($numberParam->validateValue('abc')); // non-numeric // Create SELECT parameter $selectParam = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_name' => 'test_select', 'parameter_type' => 'SELECT', 'options' => ['OPTION1', 'OPTION2', 'OPTION3'] ]); // Test valid and invalid options $this->assertTrue($selectParam->validateValue('OPTION1')); $this->assertFalse($selectParam->validateValue('INVALID')); } /** @test */ public function can_cast_parameter_values() { $numberParam = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_type' => 'NUMBER' ]); $booleanParam = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_type' => 'BOOLEAN' ]); $textParam = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'parameter_type' => 'TEXT' ]); // Test casting $this->assertSame(123.5, $numberParam->castValue('123.5')); $this->assertSame(true, $booleanParam->castValue('1')); $this->assertSame('test', $textParam->castValue('test')); } /** @test */ public function enforces_tenant_isolation() { // Create parameter for different tenant $otherTenant = Tenant::factory()->create(); $otherParameter = ModelParameter::factory()->create([ 'tenant_id' => $otherTenant->id ]); // Should not be able to access other tenant's parameter $response = $this->getJson('/api/v1/design/model-parameters/' . $otherParameter->id); $response->assertStatus(404); // Should not be able to list other tenant's parameters $response = $this->getJson('/api/v1/design/model-parameters'); $response->assertStatus(200); $data = $response->json('data.data'); $this->assertEmpty(collect($data)->where('tenant_id', $otherTenant->id)); } /** @test */ public function can_reorder_parameters() { $param1 = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'sort_order' => 1 ]); $param2 = ModelParameter::factory()->create([ 'tenant_id' => $this->tenant->id, 'model_id' => $this->model->id, 'sort_order' => 2 ]); $reorderData = [ ['id' => $param1->id, 'sort_order' => 2], ['id' => $param2->id, 'sort_order' => 1] ]; $response = $this->postJson('/api/v1/design/model-parameters/reorder', [ 'items' => $reorderData ]); $response->assertStatus(200); $this->assertDatabaseHas('model_parameters', [ 'id' => $param1->id, 'sort_order' => 2 ]); $this->assertDatabaseHas('model_parameters', [ 'id' => $param2->id, 'sort_order' => 1 ]); } }