$owner->id, 'name' => 'Гроубокс']); $sensorType = DeviceType::create([ 'code' => 'sensor_temp_humidity', 'category' => DeviceCategory::Sensor, 'capabilities' => ['temperature', 'humidity'], ]); $fanType = DeviceType::create([ 'code' => 'fan', 'category' => DeviceCategory::Actuator, 'capabilities' => ['turn_on', 'turn_off', 'set_level'], ]); $sensor = Device::forceCreate([ 'user_id' => $owner->id, 'zone_id' => $zone->id, 'device_type_id' => $sensorType->id, 'name' => 'Датчик', 'external_id' => 'sensor-1', 'protocol' => 'mqtt', ]); $fan = Device::forceCreate([ 'user_id' => $owner->id, 'zone_id' => $zone->id, 'device_type_id' => $fanType->id, 'name' => 'Вентилятор', 'external_id' => 'fan-1', 'protocol' => 'mqtt', ]); return [$zone, $sensor, $fan]; } public function test_owner_can_create_rule_with_turn_on_action(): void { $owner = User::factory()->create(['role' => UserRole::Owner]); [$zone, $sensor, $fan] = $this->makeZoneWithDevices($owner); $response = $this->actingAs($owner)->postJson('/api/v1/automation-rules', [ 'zone_id' => $zone->id, 'condition_source_device_id' => $sensor->id, 'condition_sensor_type' => 'temperature', 'condition_operator' => '>', 'condition_value' => 28, 'target_device_id' => $fan->id, 'action_type' => 'turn_on', 'is_active' => true, ]); $response->assertCreated(); // '{}', not '[]' — same PHP/Go empty-array-vs-object gotcha as the web controller. $this->assertDatabaseHas('automation_rules', [ 'target_device_id' => $fan->id, 'action_type' => 'turn_on', 'action_params' => '{}', ]); } public function test_set_level_action_requires_and_stores_level_param(): void { $owner = User::factory()->create(['role' => UserRole::Owner]); [$zone, $sensor, $fan] = $this->makeZoneWithDevices($owner); $missingLevel = $this->actingAs($owner)->postJson('/api/v1/automation-rules', [ 'zone_id' => $zone->id, 'condition_source_device_id' => $sensor->id, 'condition_sensor_type' => 'temperature', 'condition_operator' => '>', 'condition_value' => 28, 'target_device_id' => $fan->id, 'action_type' => 'set_level', ]); $missingLevel->assertJsonValidationErrors('level'); $response = $this->actingAs($owner)->postJson('/api/v1/automation-rules', [ 'zone_id' => $zone->id, 'condition_source_device_id' => $sensor->id, 'condition_sensor_type' => 'temperature', 'condition_operator' => '>', 'condition_value' => 28, 'target_device_id' => $fan->id, 'action_type' => 'set_level', 'level' => 42, ]); $response->assertCreated(); $this->assertDatabaseHas('automation_rules', [ 'target_device_id' => $fan->id, 'action_type' => 'set_level', 'action_params' => '{"level":42}', ]); } public function test_viewer_cannot_create_rule(): void { $owner = User::factory()->create(['role' => UserRole::Owner]); $viewer = User::factory()->create(['role' => UserRole::Viewer]); [$zone, $sensor, $fan] = $this->makeZoneWithDevices($owner); $response = $this->actingAs($viewer)->postJson('/api/v1/automation-rules', [ 'zone_id' => $zone->id, 'condition_source_device_id' => $sensor->id, 'condition_sensor_type' => 'temperature', 'condition_operator' => '>', 'condition_value' => 28, 'target_device_id' => $fan->id, 'action_type' => 'turn_on', ]); $response->assertForbidden(); $this->assertDatabaseCount('automation_rules', 0); } }