browser()->timeout(15_000); function inventoryItemListLivewireScript(string $body): string { return << { if (entry.name === 'App\\Filament\\Resources\\InventoryItemResource\\Pages\\ListInventoryItems') { return true; } const state = entry.canonical ?? {}; return Object.prototype.hasOwnProperty.call(state, 'tableFilters') && Object.prototype.hasOwnProperty.call(state, 'tableDeferredFilters') && Object.prototype.hasOwnProperty.call(state, 'tableRecordsPerPage') && Object.prototype.hasOwnProperty.call(state, 'tableSearch'); }); if (! component) { throw new Error('ListInventoryItems Livewire component not found.'); } {$body} JS; } function seedSpec177InventoryCoverageTruthFixtures(Tenant $tenant): OperationRun { foreach (range(1, 130) as $index) { InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => sprintf('Browser Inventory %02d', $index), 'policy_type' => 'deviceConfiguration', 'external_id' => sprintf('browser-inventory-%02d', $index), 'platform' => 'windows', 'last_seen_at' => now()->subMinutes($index), ]); } InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => 'Browser Conditional Access', 'policy_type' => 'conditionalAccessPolicy', 'external_id' => 'browser-conditional-access', 'platform' => 'windows', 'last_seen_at' => now()->subMinutes(31), ]); return createInventorySyncOperationRunWithCoverage( $tenant, [ 'conditionalAccessPolicy' => 'succeeded', 'deviceConfiguration' => 'failed', 'roleScopeTag' => 'skipped', ], ['roleScopeTag'], [ 'outcome' => OperationRunOutcome::PartiallySucceeded->value, 'completed_at' => now()->subMinute(), ], ); } function seedSpec177InventoryItemFilterPaginationFixtures(Tenant $tenant): void { foreach (range(1, 45) as $index) { InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => sprintf('Windows Fresh Device %02d', $index), 'policy_type' => 'deviceConfiguration', 'external_id' => sprintf('windows-fresh-device-%02d', $index), 'platform' => 'windows', 'last_seen_at' => now()->subMinutes($index), ]); } foreach (range(1, 3) as $index) { InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => sprintf('Mac Fresh Device %02d', $index), 'policy_type' => 'deviceConfiguration', 'external_id' => sprintf('mac-fresh-device-%02d', $index), 'platform' => 'macOS', 'last_seen_at' => now()->subMinutes(45 + $index), ]); } foreach (range(1, 3) as $index) { InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => sprintf('Conditional Access Fresh %02d', $index), 'policy_type' => 'conditionalAccessPolicy', 'external_id' => sprintf('conditional-access-fresh-%02d', $index), 'platform' => 'windows', 'last_seen_at' => now()->subMinutes(48 + $index), ]); } foreach (range(46, 55) as $index) { InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => sprintf('Windows Fresh Device %02d', $index), 'policy_type' => 'deviceConfiguration', 'external_id' => sprintf('windows-fresh-device-%02d', $index), 'platform' => 'windows', 'last_seen_at' => now()->subMinutes(6 + $index), ]); } foreach (range(1, 3) as $index) { InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'display_name' => sprintf('Windows Stale Device %02d', $index), 'policy_type' => 'deviceConfiguration', 'external_id' => sprintf('windows-stale-device-%02d', $index), 'platform' => 'windows', 'last_seen_at' => now()->subDays(3)->subMinutes($index), ]); } } it('smokes inventory coverage truth surfaces with filters, pagination, and run drill-through', function (): void { $tenant = Tenant::factory()->create([ 'name' => 'Spec177 Browser Tenant', 'external_id' => 'spec177-browser-tenant', ]); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $run = seedSpec177InventoryCoverageTruthFixtures($tenant); $this->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); $searchPage = visit(InventoryItemResource::getUrl('index', tenant: $tenant)); $searchPage ->waitForText('Inventory Items') ->assertNoJavaScriptErrors() ->assertSee('Covered types') ->assertSee('Need follow-up') ->assertSee('Coverage basis') ->assertSee('Open basis run') ->assertSee('Run Inventory Sync') ->assertSee('Browser Inventory 01') ->assertDontSee('Browser Inventory 130') ->fill('main input[placeholder="Search"]', 'Browser Inventory 01') ->waitForText('Browser Inventory 01') ->assertNoJavaScriptErrors() ->assertSee('Browser Inventory 01') ->assertDontSee('Browser Inventory 02'); $page = visit(InventoryCoverage::getUrl(tenant: $tenant)); $page ->waitForText('Tenant coverage truth') ->assertNoJavaScriptErrors() ->assertSee('Latest coverage-bearing sync completed') ->assertSee('Open basis run') ->assertSee('Open inventory items') ->fill('input[placeholder="Search by type or label"]', 'Conditional Access') ->waitForText('Conditional Access') ->assertNoJavaScriptErrors() ->assertSee('Conditional Access') ->assertScript("document.querySelector('input[placeholder=\"Search by type or label\"]')?.value === 'Conditional Access'", true) ->click('Open basis run') ->waitForText('Operation #'.(int) $run->getKey()) ->assertNoJavaScriptErrors() ->assertRoute('admin.operations.view', ['run' => (int) $run->getKey()]) ->assertSee('Inventory sync coverage') ->assertSee('Need follow-up'); $page->script(<<<'JS' history.back(); JS); $page ->waitForText('Tenant coverage truth') ->assertNoJavaScriptErrors() ->click('Open inventory items') ->waitForText('Inventory Items') ->assertNoJavaScriptErrors() ->assertSee('Browser Inventory 01'); }); it('smokes inventory item pagination with stable filter combinations', function (): void { $tenant = Tenant::factory()->create([ 'name' => 'Spec177 Browser Filter Tenant', 'external_id' => 'spec177-browser-filter-tenant', ]); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); seedSpec177InventoryItemFilterPaginationFixtures($tenant); $this->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); $page = visit(InventoryItemResource::getUrl('index', tenant: $tenant)); $page ->waitForText('Inventory Items') ->assertNoJavaScriptErrors() ->assertSee('Windows Fresh Device 01') ->assertDontSee('Windows Fresh Device 30') ->assertDontSee('Mac Fresh Device 01') ->wait(1); $page->script(inventoryItemListLivewireScript(<<<'JS' component.$wire.set('tableRecordsPerPage', 50); JS)); $page ->wait(1) ->waitForText('Mac Fresh Device 01') ->assertNoJavaScriptErrors() ->assertSee('Mac Fresh Device 01') ->assertSee('Conditional Access Fresh 01') ->assertDontSee('Windows Fresh Device 46'); $page->script(inventoryItemListLivewireScript(<<<'JS' component.$wire.set('tableDeferredFilters.policy_type.value', 'deviceConfiguration'); component.$wire.set('tableDeferredFilters.platform.value', 'windows'); component.$wire.set('tableDeferredFilters.stale.value', '0'); component.$wire.call('applyTableFilters'); JS)); $page ->wait(1) ->waitForText('Active filters') ->waitForText('Windows Fresh Device 46') ->assertNoJavaScriptErrors() ->assertSee('Policy type: Device Configuration') ->assertSee('Platform: Windows') ->assertSee('Freshness: Fresh') ->assertSee('Windows Fresh Device 46') ->assertDontSee('Mac Fresh Device 01') ->assertDontSee('Conditional Access Fresh 01') ->assertDontSee('Windows Stale Device 01'); $page->script(inventoryItemListLivewireScript(<<<'JS' component.$wire.call('gotoPage', 2); JS)); $page ->wait(1) ->waitForText('Windows Fresh Device 51') ->assertNoJavaScriptErrors() ->assertSee('Windows Fresh Device 51') ->assertDontSee('Windows Fresh Device 01') ->assertDontSee('Mac Fresh Device 01'); });