Управление типами устройств из UI (список + создание)
Раньше device_types заводились только через сидер — теперь owner может посмотреть все типы (карточки: иконка по категории, capabilities тегами, число устройств этого типа) и добавить новый прямо из интерфейса: код, категория, возможности вводятся тегами (можно вписать вручную и добавить по Enter/кнопке). Ссылка на список — со страницы устройств. DeviceTypePolicy зеркалит остальные Policy (view — всем, create — только owner). DeviceTypeResource получил devices_count через whenCounted — опционально, не ломает существующий API-эндпоинт (там withCount не вызывается, поле просто не появляется).
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Enums\UserRole;
|
||||
use App\Models\DeviceType;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DeviceTypeControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_owner_can_create_device_type(): void
|
||||
{
|
||||
$owner = User::factory()->create(['role' => UserRole::Owner]);
|
||||
|
||||
$response = $this->actingAs($owner)->post(route('device-types.store'), [
|
||||
'code' => 'smart_socket',
|
||||
'category' => 'actuator',
|
||||
'capabilities' => ['turn_on', 'turn_off'],
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('device-types.index'));
|
||||
$this->assertDatabaseHas('device_types', [
|
||||
'code' => 'smart_socket',
|
||||
'category' => 'actuator',
|
||||
]);
|
||||
$this->assertSame(
|
||||
['turn_on', 'turn_off'],
|
||||
DeviceType::where('code', 'smart_socket')->first()->capabilities,
|
||||
);
|
||||
}
|
||||
|
||||
public function test_viewer_cannot_create_device_type(): void
|
||||
{
|
||||
$viewer = User::factory()->create(['role' => UserRole::Viewer]);
|
||||
|
||||
$response = $this->actingAs($viewer)->post(route('device-types.store'), [
|
||||
'code' => 'smart_socket',
|
||||
'category' => 'actuator',
|
||||
]);
|
||||
|
||||
$response->assertForbidden();
|
||||
$this->assertDatabaseMissing('device_types', ['code' => 'smart_socket']);
|
||||
}
|
||||
|
||||
public function test_code_must_be_unique(): void
|
||||
{
|
||||
$owner = User::factory()->create(['role' => UserRole::Owner]);
|
||||
DeviceType::create(['code' => 'fan', 'category' => 'actuator', 'capabilities' => []]);
|
||||
|
||||
$response = $this->actingAs($owner)->post(route('device-types.store'), [
|
||||
'code' => 'fan',
|
||||
'category' => 'actuator',
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors('code');
|
||||
}
|
||||
|
||||
public function test_viewer_can_view_device_types_index(): void
|
||||
{
|
||||
$viewer = User::factory()->create(['role' => UserRole::Viewer]);
|
||||
DeviceType::create(['code' => 'fan', 'category' => 'actuator', 'capabilities' => ['turn_on']]);
|
||||
|
||||
$response = $this->actingAs($viewer)->get(route('device-types.index'));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertInertia(fn (Assert $page) => $page
|
||||
->component('DeviceTypes/Index')
|
||||
->where('deviceTypes.0.code', 'fan')
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user