create(['name' => 'Alpha Tenant']); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly'); $tenantDenied = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Denied Tenant', ]); $otherOwner = User::factory()->create(); createUserWithTenant(tenant: $tenantDenied, user: $otherOwner, role: 'owner'); $tenantASnapshot = seedTenantReviewEvidence($tenantA); $tenantBSnapshot = seedTenantReviewEvidence($tenantB); $tenantDeniedSnapshot = seedTenantReviewEvidence($tenantDenied); $olderPublishedReview = composeTenantReviewForTest($tenantA, $user, $tenantASnapshot); $olderPublishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'generated_at' => now()->subDays(3), 'published_at' => now()->subDays(3), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $newerInternalReview = $olderPublishedReview->replicate(); $newerInternalReview->forceFill([ 'tenant_id' => (int) $tenantA->getKey(), 'workspace_id' => (int) $tenantA->workspace_id, 'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(), 'status' => TenantReviewStatus::Ready->value, 'generated_at' => now()->subDay(), 'published_at' => null, 'published_by_user_id' => null, ])->save(); $latestPublishedReview = $olderPublishedReview->replicate(); $latestPublishedReview->forceFill([ 'tenant_id' => (int) $tenantA->getKey(), 'workspace_id' => (int) $tenantA->workspace_id, 'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(), 'status' => TenantReviewStatus::Published->value, 'generated_at' => now(), 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $betaPublishedReview = composeTenantReviewForTest($tenantB, $user, $tenantBSnapshot); $betaPublishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'generated_at' => now()->subHours(2), 'published_at' => now()->subHours(2), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $deniedPublishedReview = composeTenantReviewForTest($tenantDenied, $otherOwner, $tenantDeniedSnapshot); $deniedPublishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'generated_at' => now()->subHours(3), 'published_at' => now()->subHours(3), 'published_by_user_id' => (int) $otherOwner->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertCanSeeTableRecords([$tenantA->fresh(), $tenantB->fresh()]) ->assertCanNotSeeTableRecords([$tenantDenied->fresh()]) ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $latestPublishedReview->fresh()], $tenantA), false) ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $betaPublishedReview->fresh()], $tenantB), false) ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $olderPublishedReview->fresh()], $tenantA), false) ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $newerInternalReview->fresh()], $tenantA), false) ->assertDontSee('Publish review') ->assertDontSee('Refresh review') ->assertDontSee('Create next review') ->assertDontSee('Regenerate') ->assertDontSee('Expire snapshot') ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $deniedPublishedReview->fresh()], $tenantDenied), false); }); it('shows entitled tenants without a published review as calm absence rows', function (): void { $tenantPublished = Tenant::factory()->create(['name' => 'Published Tenant']); [$user, $tenantPublished] = createUserWithTenant(tenant: $tenantPublished, role: 'readonly'); $tenantWithoutPublished = Tenant::factory()->create([ 'workspace_id' => (int) $tenantPublished->workspace_id, 'name' => 'No Published Tenant', ]); createUserWithTenant(tenant: $tenantWithoutPublished, user: $user, role: 'readonly'); $publishedSnapshot = seedTenantReviewEvidence($tenantPublished); $noPublishedSnapshot = seedTenantReviewEvidence($tenantWithoutPublished); $publishedReview = composeTenantReviewForTest($tenantPublished, $user, $publishedSnapshot); $publishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now()->subHour(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $internalOnlyReview = composeTenantReviewForTest($tenantWithoutPublished, $user, $noPublishedSnapshot); $internalOnlyReview->forceFill([ 'status' => TenantReviewStatus::Ready->value, 'published_at' => null, 'published_by_user_id' => null, ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantPublished->workspace_id); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertCanSeeTableRecords([$tenantPublished->fresh(), $tenantWithoutPublished->fresh()]) ->assertSee('No published review') ->assertSee('No published review available yet') ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenantWithoutPublished), false) ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $publishedReview->fresh()], $tenantPublished), false); }); it('defaults the customer review workspace to the remembered tenant when tenant context is available', function (): void { $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly'); $snapshotA = seedTenantReviewEvidence($tenantA); $snapshotB = seedTenantReviewEvidence($tenantB); $reviewA = composeTenantReviewForTest($tenantA, $user, $snapshotA); $reviewA->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now()->subDay(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $reviewB = composeTenantReviewForTest($tenantB, $user, $snapshotB); $reviewB->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $tenantA->workspace_id => (int) $tenantB->getKey(), ]); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertSet('tableFilters.tenant_id.value', (string) $tenantB->getKey()) ->filterTable('tenant_id', (string) $tenantB->getKey()) ->assertCanSeeTableRecords([$tenantB->fresh()]) ->assertCanNotSeeTableRecords([$tenantA->fresh()]); }); it('prefilters the customer review workspace from an explicit tenant query parameter and accepts external tenant identifiers', function (): void { $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly'); $snapshotA = seedTenantReviewEvidence($tenantA); $snapshotB = seedTenantReviewEvidence($tenantB); $reviewA = composeTenantReviewForTest($tenantA, $user, $snapshotA); $reviewA->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $reviewB = composeTenantReviewForTest($tenantB, $user, $snapshotB); $reviewB->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now()->subDay(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); Livewire::withQueryParams(['tenant' => (string) $tenantA->external_id]) ->test(CustomerReviewWorkspace::class) ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey()) ->filterTable('tenant_id', (string) $tenantA->getKey()) ->assertCanSeeTableRecords([$tenantA->fresh()]) ->assertCanNotSeeTableRecords([$tenantB->fresh()]); });