actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $sync = app(InventorySyncService::class); $allTypes = $sync->defaultSelectionPayload()['policy_types']; Livewire::test(ListInventoryItems::class) ->callAction('run_inventory_sync', data: ['policy_types' => $allTypes]) ->assertDispatchedTo(BulkOperationProgress::class, OpsUxBrowserEvents::RunEnqueued, tenantId: (int) $tenant->getKey()); Queue::assertPushed(RunInventorySyncJob::class); $run = InventorySyncRun::query()->where('tenant_id', $tenant->id)->latest('id')->first(); expect($run)->not->toBeNull(); expect($run->user_id)->toBe($user->id); expect($run->status)->toBe(InventorySyncRun::STATUS_PENDING); $opRun = OperationRun::query() ->where('tenant_id', $tenant->id) ->where('user_id', $user->id) ->where('type', 'inventory.sync') ->latest('id') ->first(); expect($opRun)->not->toBeNull(); }); it('dispatches inventory sync for selected policy types', function () { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $sync = app(InventorySyncService::class); $allTypes = $sync->defaultSelectionPayload()['policy_types']; $selectedTypes = array_slice($allTypes, 0, min(2, count($allTypes))); Livewire::test(ListInventoryItems::class) ->mountAction('run_inventory_sync') ->set('mountedActions.0.data.policy_types', $selectedTypes) ->assertActionDataSet(['policy_types' => $selectedTypes]) ->callMountedAction() ->assertHasNoActionErrors(); Queue::assertPushed(RunInventorySyncJob::class); $run = InventorySyncRun::query()->where('tenant_id', $tenant->id)->latest('id')->first(); expect($run)->not->toBeNull(); expect($run->selection_payload['policy_types'] ?? [])->toEqualCanonicalizing($selectedTypes); }); it('persists include dependencies toggle into the run selection payload', function () { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $sync = app(InventorySyncService::class); $allTypes = $sync->defaultSelectionPayload()['policy_types']; $selectedTypes = array_slice($allTypes, 0, min(2, count($allTypes))); Livewire::test(ListInventoryItems::class) ->callAction('run_inventory_sync', data: [ 'policy_types' => $selectedTypes, 'include_dependencies' => false, ]) ->assertHasNoActionErrors(); $run = InventorySyncRun::query()->where('tenant_id', $tenant->id)->latest('id')->first(); expect($run)->not->toBeNull(); expect((bool) ($run->selection_payload['include_dependencies'] ?? true))->toBeFalse(); }); it('defaults include foundations toggle to true and persists it into the run selection payload', function () { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $sync = app(InventorySyncService::class); $allTypes = $sync->defaultSelectionPayload()['policy_types']; $selectedTypes = array_slice($allTypes, 0, min(2, count($allTypes))); Livewire::test(ListInventoryItems::class) ->mountAction('run_inventory_sync') ->set('mountedActions.0.data.policy_types', $selectedTypes) ->assertActionDataSet(['include_foundations' => true]) ->callMountedAction() ->assertHasNoActionErrors(); $run = InventorySyncRun::query()->where('tenant_id', $tenant->id)->latest('id')->first(); expect($run)->not->toBeNull(); expect((bool) ($run->selection_payload['include_foundations'] ?? false))->toBeTrue(); }); it('persists include foundations toggle into the run selection payload', function () { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $sync = app(InventorySyncService::class); $allTypes = $sync->defaultSelectionPayload()['policy_types']; $selectedTypes = array_slice($allTypes, 0, min(2, count($allTypes))); Livewire::test(ListInventoryItems::class) ->callAction('run_inventory_sync', data: [ 'policy_types' => $selectedTypes, 'include_foundations' => false, ]) ->assertHasNoActionErrors(); $run = InventorySyncRun::query()->where('tenant_id', $tenant->id)->latest('id')->first(); expect($run)->not->toBeNull(); expect((bool) ($run->selection_payload['include_foundations'] ?? true))->toBeFalse(); }); it('rejects cross-tenant initiation attempts (403) with no side effects', function () { Queue::fake(); [$user, $tenantA] = createUserWithTenant(role: 'owner'); $tenantB = Tenant::factory()->create(); $this->actingAs($user); Filament::setTenant($tenantA, true); $sync = app(InventorySyncService::class); $allTypes = $sync->defaultSelectionPayload()['policy_types']; Livewire::test(ListInventoryItems::class) ->callAction('run_inventory_sync', data: ['tenant_id' => $tenantB->getKey(), 'policy_types' => $allTypes]) ->assertStatus(403); Queue::assertNothingPushed(); expect(InventorySyncRun::query()->where('tenant_id', $tenantB->id)->exists())->toBeFalse(); expect(OperationRun::query()->where('tenant_id', $tenantB->id)->exists())->toBeFalse(); }); it('blocks dispatch when a matching run is already pending or running', function () { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $sync = app(InventorySyncService::class); $selectionPayload = $sync->defaultSelectionPayload(); $computed = $sync->normalizeAndHashSelection($selectionPayload); InventorySyncRun::query()->create([ 'tenant_id' => $tenant->getKey(), 'user_id' => $user->getKey(), 'selection_hash' => $computed['selection_hash'], 'selection_payload' => $computed['selection'], 'status' => InventorySyncRun::STATUS_RUNNING, 'had_errors' => false, 'error_codes' => [], 'error_context' => null, 'started_at' => now(), 'finished_at' => null, 'items_observed_count' => 0, 'items_upserted_count' => 0, 'errors_count' => 0, ]); Livewire::test(ListInventoryItems::class) ->callAction('run_inventory_sync', data: ['policy_types' => $computed['selection']['policy_types']]); Queue::assertNothingPushed(); expect(InventorySyncRun::query()->where('tenant_id', $tenant->id)->count())->toBe(1); expect(OperationRun::query()->where('tenant_id', $tenant->id)->where('type', 'inventory.sync')->count())->toBe(1); }); it('forbids unauthorized users from starting inventory sync', function () { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'readonly'); $this->actingAs($user); Filament::setTenant($tenant, true); Livewire::test(ListInventoryItems::class) ->assertActionHidden('run_inventory_sync'); Queue::assertNothingPushed(); expect(InventorySyncRun::query()->where('tenant_id', $tenant->id)->exists())->toBeFalse(); });