340 lines
11 KiB
PHP
340 lines
11 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Feature\Design;
|
||
|
|
|
||
|
|
use Tests\TestCase;
|
||
|
|
use App\Models\Design\DesignModel;
|
||
|
|
use App\Models\Design\ModelParameter;
|
||
|
|
use App\Models\User;
|
||
|
|
use App\Models\Tenant;
|
||
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
|
use Illuminate\Support\Facades\Auth;
|
||
|
|
use Laravel\Sanctum\Sanctum;
|
||
|
|
|
||
|
|
class ModelParameterTest extends TestCase
|
||
|
|
{
|
||
|
|
use RefreshDatabase;
|
||
|
|
|
||
|
|
private User $user;
|
||
|
|
private Tenant $tenant;
|
||
|
|
private DesignModel $model;
|
||
|
|
|
||
|
|
protected function setUp(): void
|
||
|
|
{
|
||
|
|
parent::setUp();
|
||
|
|
|
||
|
|
// Create test tenant and user
|
||
|
|
$this->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
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|