603 lines
21 KiB
PHP
603 lines
21 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Core PHP Framework
|
||
|
|
*
|
||
|
|
* Licensed under the European Union Public Licence (EUPL) v1.2.
|
||
|
|
* See LICENSE file for details.
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
use Livewire\Attributes\Computed;
|
||
|
|
use Livewire\Component;
|
||
|
|
use Livewire\Livewire;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Tests for PlatformUser modal component patterns.
|
||
|
|
*
|
||
|
|
* These tests verify the PlatformUser admin panel behaviour using test doubles:
|
||
|
|
* tab navigation, tier management, verification toggling, delete confirmation
|
||
|
|
* flows, package/entitlement modals, and GDPR data export.
|
||
|
|
*/
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Test Double Components
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* PlatformUser-style component for admin user management.
|
||
|
|
*/
|
||
|
|
class PlatformUserModalDouble extends Component
|
||
|
|
{
|
||
|
|
// User data
|
||
|
|
public int $userId = 0;
|
||
|
|
|
||
|
|
public string $userName = '';
|
||
|
|
|
||
|
|
public string $userEmail = '';
|
||
|
|
|
||
|
|
// Editable fields
|
||
|
|
public string $editingTier = 'free';
|
||
|
|
|
||
|
|
public bool $editingVerified = false;
|
||
|
|
|
||
|
|
// Action state
|
||
|
|
public string $actionMessage = '';
|
||
|
|
|
||
|
|
public string $actionType = '';
|
||
|
|
|
||
|
|
// Tab navigation
|
||
|
|
public string $activeTab = 'overview';
|
||
|
|
|
||
|
|
// Delete confirmation flow
|
||
|
|
public bool $showDeleteConfirm = false;
|
||
|
|
|
||
|
|
public bool $immediateDelete = false;
|
||
|
|
|
||
|
|
public string $deleteReason = '';
|
||
|
|
|
||
|
|
// Package provisioning modal
|
||
|
|
public bool $showPackageModal = false;
|
||
|
|
|
||
|
|
public ?int $selectedWorkspaceId = null;
|
||
|
|
|
||
|
|
public string $selectedPackageCode = '';
|
||
|
|
|
||
|
|
// Entitlement provisioning modal
|
||
|
|
public bool $showEntitlementModal = false;
|
||
|
|
|
||
|
|
public ?int $entitlementWorkspaceId = null;
|
||
|
|
|
||
|
|
public string $entitlementFeatureCode = '';
|
||
|
|
|
||
|
|
public string $entitlementType = 'enable';
|
||
|
|
|
||
|
|
public ?int $entitlementLimit = null;
|
||
|
|
|
||
|
|
public string $entitlementDuration = 'permanent';
|
||
|
|
|
||
|
|
public ?string $entitlementExpiresAt = null;
|
||
|
|
|
||
|
|
// Export tracking
|
||
|
|
public bool $dataExported = false;
|
||
|
|
|
||
|
|
public function mount(int $id = 1): void
|
||
|
|
{
|
||
|
|
$this->userId = $id;
|
||
|
|
$this->userName = 'Test User';
|
||
|
|
$this->userEmail = 'test@example.com';
|
||
|
|
$this->editingTier = 'free';
|
||
|
|
$this->editingVerified = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setTab(string $tab): void
|
||
|
|
{
|
||
|
|
if (in_array($tab, ['overview', 'workspaces', 'entitlements', 'data', 'danger'])) {
|
||
|
|
$this->activeTab = $tab;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public function saveTier(): void
|
||
|
|
{
|
||
|
|
$this->actionMessage = "Tier updated to {$this->editingTier}.";
|
||
|
|
$this->actionType = 'success';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function saveVerification(): void
|
||
|
|
{
|
||
|
|
$this->actionMessage = $this->editingVerified
|
||
|
|
? 'Email marked as verified.'
|
||
|
|
: 'Email verification removed.';
|
||
|
|
$this->actionType = 'success';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function resendVerification(): void
|
||
|
|
{
|
||
|
|
if ($this->editingVerified) {
|
||
|
|
$this->actionMessage = 'User email is already verified.';
|
||
|
|
$this->actionType = 'warning';
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->actionMessage = 'Verification email sent.';
|
||
|
|
$this->actionType = 'success';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function confirmDelete(bool $immediate = false): void
|
||
|
|
{
|
||
|
|
$this->immediateDelete = $immediate;
|
||
|
|
$this->showDeleteConfirm = true;
|
||
|
|
$this->deleteReason = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function cancelDelete(): void
|
||
|
|
{
|
||
|
|
$this->showDeleteConfirm = false;
|
||
|
|
$this->immediateDelete = false;
|
||
|
|
$this->deleteReason = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function scheduleDelete(): void
|
||
|
|
{
|
||
|
|
if ($this->immediateDelete) {
|
||
|
|
$this->actionMessage = 'User has been permanently deleted.';
|
||
|
|
$this->actionType = 'success';
|
||
|
|
} else {
|
||
|
|
$this->actionMessage = 'Account deletion scheduled. Will be deleted in 7 days unless cancelled.';
|
||
|
|
$this->actionType = 'warning';
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->showDeleteConfirm = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function anonymizeUser(): void
|
||
|
|
{
|
||
|
|
$this->userName = 'Anonymized User';
|
||
|
|
$this->userEmail = "anon_{$this->userId}@anonymized.local";
|
||
|
|
$this->editingTier = 'free';
|
||
|
|
$this->editingVerified = false;
|
||
|
|
|
||
|
|
$this->actionMessage = 'User data has been anonymized.';
|
||
|
|
$this->actionType = 'success';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function openPackageModal(int $workspaceId): void
|
||
|
|
{
|
||
|
|
$this->selectedWorkspaceId = $workspaceId;
|
||
|
|
$this->selectedPackageCode = '';
|
||
|
|
$this->showPackageModal = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function closePackageModal(): void
|
||
|
|
{
|
||
|
|
$this->showPackageModal = false;
|
||
|
|
$this->selectedWorkspaceId = null;
|
||
|
|
$this->selectedPackageCode = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function provisionPackage(): void
|
||
|
|
{
|
||
|
|
if (! $this->selectedWorkspaceId || ! $this->selectedPackageCode) {
|
||
|
|
$this->actionMessage = 'Please select a workspace and package.';
|
||
|
|
$this->actionType = 'warning';
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->actionMessage = "Package provisioned to workspace.";
|
||
|
|
$this->actionType = 'success';
|
||
|
|
$this->closePackageModal();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function openEntitlementModal(int $workspaceId): void
|
||
|
|
{
|
||
|
|
$this->entitlementWorkspaceId = $workspaceId;
|
||
|
|
$this->entitlementFeatureCode = '';
|
||
|
|
$this->entitlementType = 'enable';
|
||
|
|
$this->entitlementLimit = null;
|
||
|
|
$this->entitlementDuration = 'permanent';
|
||
|
|
$this->entitlementExpiresAt = null;
|
||
|
|
$this->showEntitlementModal = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function closeEntitlementModal(): void
|
||
|
|
{
|
||
|
|
$this->showEntitlementModal = false;
|
||
|
|
$this->entitlementWorkspaceId = null;
|
||
|
|
$this->entitlementFeatureCode = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function provisionEntitlement(): void
|
||
|
|
{
|
||
|
|
if (! $this->entitlementWorkspaceId || ! $this->entitlementFeatureCode) {
|
||
|
|
$this->actionMessage = 'Please select a workspace and feature.';
|
||
|
|
$this->actionType = 'warning';
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->actionMessage = "Entitlement added to workspace.";
|
||
|
|
$this->actionType = 'success';
|
||
|
|
$this->closeEntitlementModal();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function exportUserData(): void
|
||
|
|
{
|
||
|
|
$this->dataExported = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Computed]
|
||
|
|
public function collectUserData(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'export_info' => [
|
||
|
|
'exported_at' => now()->toIso8601String(),
|
||
|
|
'exported_by' => 'Platform Administrator',
|
||
|
|
],
|
||
|
|
'account' => [
|
||
|
|
'id' => $this->userId,
|
||
|
|
'name' => $this->userName,
|
||
|
|
'email' => $this->userEmail,
|
||
|
|
'tier' => $this->editingTier,
|
||
|
|
],
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
public function render(): string
|
||
|
|
{
|
||
|
|
return <<<'HTML'
|
||
|
|
<div>
|
||
|
|
<h1>User: {{ $userName }}</h1>
|
||
|
|
<span>Tab: {{ $activeTab }}</span>
|
||
|
|
<span>Tier: {{ $editingTier }}</span>
|
||
|
|
@if($showDeleteConfirm)
|
||
|
|
<div class="delete-confirm">Delete Confirm</div>
|
||
|
|
@endif
|
||
|
|
@if($showPackageModal)
|
||
|
|
<div class="package-modal">Package Modal</div>
|
||
|
|
@endif
|
||
|
|
@if($showEntitlementModal)
|
||
|
|
<div class="entitlement-modal">Entitlement Modal</div>
|
||
|
|
@endif
|
||
|
|
@if($actionMessage)
|
||
|
|
<div class="action-message {{ $actionType }}">{{ $actionMessage }}</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
HTML;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Tab Navigation Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser tab navigation', function () {
|
||
|
|
it('defaults to overview tab', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->assertSet('activeTab', 'overview');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('switches to valid tabs', function () {
|
||
|
|
$validTabs = ['overview', 'workspaces', 'entitlements', 'data', 'danger'];
|
||
|
|
|
||
|
|
foreach ($validTabs as $tab) {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('setTab', $tab)
|
||
|
|
->assertSet('activeTab', $tab);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('ignores invalid tab names', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('setTab', 'nonexistent')
|
||
|
|
->assertSet('activeTab', 'overview');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders current tab label', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('setTab', 'workspaces')
|
||
|
|
->assertSee('Tab: workspaces');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Tier Management Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser tier management', function () {
|
||
|
|
it('loads user tier on mount', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->assertSet('editingTier', 'free');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('can change tier to apollo', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingTier', 'apollo')
|
||
|
|
->call('saveTier')
|
||
|
|
->assertSet('actionMessage', 'Tier updated to apollo.')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('can change tier to hades', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingTier', 'hades')
|
||
|
|
->call('saveTier')
|
||
|
|
->assertSet('actionMessage', 'Tier updated to hades.')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders tier value', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingTier', 'apollo')
|
||
|
|
->assertSee('Tier: apollo');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Verification Management Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser verification management', function () {
|
||
|
|
it('can mark email as verified', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingVerified', true)
|
||
|
|
->call('saveVerification')
|
||
|
|
->assertSet('actionMessage', 'Email marked as verified.')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('can remove email verification', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingVerified', false)
|
||
|
|
->call('saveVerification')
|
||
|
|
->assertSet('actionMessage', 'Email verification removed.')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('warns when resending to already verified user', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingVerified', true)
|
||
|
|
->call('resendVerification')
|
||
|
|
->assertSet('actionMessage', 'User email is already verified.')
|
||
|
|
->assertSet('actionType', 'warning');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('sends verification email for unverified user', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingVerified', false)
|
||
|
|
->call('resendVerification')
|
||
|
|
->assertSet('actionMessage', 'Verification email sent.')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Delete Confirmation Flow Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser delete confirmation flow', function () {
|
||
|
|
it('opens delete confirmation with scheduled mode', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('confirmDelete', false)
|
||
|
|
->assertSet('showDeleteConfirm', true)
|
||
|
|
->assertSet('immediateDelete', false)
|
||
|
|
->assertSet('deleteReason', '')
|
||
|
|
->assertSee('Delete Confirm');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('opens delete confirmation with immediate mode', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('confirmDelete', true)
|
||
|
|
->assertSet('showDeleteConfirm', true)
|
||
|
|
->assertSet('immediateDelete', true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('cancels delete confirmation', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('confirmDelete', true)
|
||
|
|
->set('deleteReason', 'GDPR request')
|
||
|
|
->call('cancelDelete')
|
||
|
|
->assertSet('showDeleteConfirm', false)
|
||
|
|
->assertSet('immediateDelete', false)
|
||
|
|
->assertSet('deleteReason', '')
|
||
|
|
->assertDontSee('Delete Confirm');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('schedules deletion (non-immediate)', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('confirmDelete', false)
|
||
|
|
->set('deleteReason', 'User request')
|
||
|
|
->call('scheduleDelete')
|
||
|
|
->assertSet('showDeleteConfirm', false)
|
||
|
|
->assertSet('actionMessage', 'Account deletion scheduled. Will be deleted in 7 days unless cancelled.')
|
||
|
|
->assertSet('actionType', 'warning');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('executes immediate deletion', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('confirmDelete', true)
|
||
|
|
->call('scheduleDelete')
|
||
|
|
->assertSet('showDeleteConfirm', false)
|
||
|
|
->assertSet('actionMessage', 'User has been permanently deleted.')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Anonymization Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser anonymization', function () {
|
||
|
|
it('anonymizes user data', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class, ['id' => 42])
|
||
|
|
->call('anonymizeUser')
|
||
|
|
->assertSet('userName', 'Anonymized User')
|
||
|
|
->assertSet('userEmail', 'anon_42@anonymized.local')
|
||
|
|
->assertSet('editingTier', 'free')
|
||
|
|
->assertSet('editingVerified', false)
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('displays anonymized name after anonymization', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('anonymizeUser')
|
||
|
|
->assertSee('Anonymized User');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Package Modal Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser package modal', function () {
|
||
|
|
it('opens package modal for a workspace', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openPackageModal', 5)
|
||
|
|
->assertSet('showPackageModal', true)
|
||
|
|
->assertSet('selectedWorkspaceId', 5)
|
||
|
|
->assertSet('selectedPackageCode', '')
|
||
|
|
->assertSee('Package Modal');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('closes package modal and resets state', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openPackageModal', 5)
|
||
|
|
->set('selectedPackageCode', 'pro-plan')
|
||
|
|
->call('closePackageModal')
|
||
|
|
->assertSet('showPackageModal', false)
|
||
|
|
->assertSet('selectedWorkspaceId', null)
|
||
|
|
->assertSet('selectedPackageCode', '')
|
||
|
|
->assertDontSee('Package Modal');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('warns when provisioning without workspace or package', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openPackageModal', 5)
|
||
|
|
->call('provisionPackage')
|
||
|
|
->assertSet('actionMessage', 'Please select a workspace and package.')
|
||
|
|
->assertSet('actionType', 'warning');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('provisions package and closes modal on success', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openPackageModal', 5)
|
||
|
|
->set('selectedPackageCode', 'pro-plan')
|
||
|
|
->call('provisionPackage')
|
||
|
|
->assertSet('showPackageModal', false)
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Entitlement Modal Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser entitlement modal', function () {
|
||
|
|
it('opens entitlement modal with defaults', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openEntitlementModal', 7)
|
||
|
|
->assertSet('showEntitlementModal', true)
|
||
|
|
->assertSet('entitlementWorkspaceId', 7)
|
||
|
|
->assertSet('entitlementFeatureCode', '')
|
||
|
|
->assertSet('entitlementType', 'enable')
|
||
|
|
->assertSet('entitlementLimit', null)
|
||
|
|
->assertSet('entitlementDuration', 'permanent')
|
||
|
|
->assertSet('entitlementExpiresAt', null)
|
||
|
|
->assertSee('Entitlement Modal');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('closes entitlement modal and resets state', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openEntitlementModal', 7)
|
||
|
|
->set('entitlementFeatureCode', 'core.srv.bio')
|
||
|
|
->call('closeEntitlementModal')
|
||
|
|
->assertSet('showEntitlementModal', false)
|
||
|
|
->assertSet('entitlementWorkspaceId', null)
|
||
|
|
->assertSet('entitlementFeatureCode', '')
|
||
|
|
->assertDontSee('Entitlement Modal');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('warns when provisioning without workspace or feature', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openEntitlementModal', 7)
|
||
|
|
->call('provisionEntitlement')
|
||
|
|
->assertSet('actionMessage', 'Please select a workspace and feature.')
|
||
|
|
->assertSet('actionType', 'warning');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('provisions entitlement and closes modal on success', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openEntitlementModal', 7)
|
||
|
|
->set('entitlementFeatureCode', 'core.srv.bio')
|
||
|
|
->call('provisionEntitlement')
|
||
|
|
->assertSet('showEntitlementModal', false)
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('supports different entitlement types', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openEntitlementModal', 7)
|
||
|
|
->set('entitlementType', 'add_limit')
|
||
|
|
->set('entitlementLimit', 100)
|
||
|
|
->assertSet('entitlementType', 'add_limit')
|
||
|
|
->assertSet('entitlementLimit', 100);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('supports duration-based entitlements', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->call('openEntitlementModal', 7)
|
||
|
|
->set('entitlementDuration', 'duration')
|
||
|
|
->set('entitlementExpiresAt', '2026-12-31')
|
||
|
|
->assertSet('entitlementDuration', 'duration')
|
||
|
|
->assertSet('entitlementExpiresAt', '2026-12-31');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Data Export Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser data export', function () {
|
||
|
|
it('collects user data for export', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class, ['id' => 42])
|
||
|
|
->assertSet(fn ($component) => $component->collectUserData['account']['id'] === 42
|
||
|
|
&& $component->collectUserData['account']['name'] === 'Test User'
|
||
|
|
&& $component->collectUserData['account']['email'] === 'test@example.com');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('triggers data export', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->assertSet('dataExported', false)
|
||
|
|
->call('exportUserData')
|
||
|
|
->assertSet('dataExported', true);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Action Message Tests
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
describe('PlatformUser action messages', function () {
|
||
|
|
it('clears action message between operations', function () {
|
||
|
|
$component = Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingTier', 'apollo')
|
||
|
|
->call('saveTier')
|
||
|
|
->assertSet('actionType', 'success');
|
||
|
|
|
||
|
|
// Next operation replaces the message
|
||
|
|
$component->set('editingVerified', true)
|
||
|
|
->call('resendVerification')
|
||
|
|
->assertSet('actionType', 'warning')
|
||
|
|
->assertSet('actionMessage', 'User email is already verified.');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders action message in view', function () {
|
||
|
|
Livewire::test(PlatformUserModalDouble::class)
|
||
|
|
->set('editingTier', 'hades')
|
||
|
|
->call('saveTier')
|
||
|
|
->assertSee('Tier updated to hades.');
|
||
|
|
});
|
||
|
|
});
|