## Summary - harden nested Filament and Livewire tenant-context handling across the backup schedule operation runs relation manager, managed-environment triage arrival continuity, the backup set policy picker table, and the Operate Hub shell - add architecture, feature, and browser coverage for nested Filament tenant-context continuity and restore-run resource behavior - add the Spec 334 artifacts (`spec.md`, `plan.md`, `tasks.md`, and the requirements checklist) ## Testing - Not run as part of this commit/push/PR workflow Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #395
141 lines
4.9 KiB
PHP
141 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Resources\BackupSetResource;
|
|
use App\Filament\Resources\RestoreRunResource;
|
|
use App\Models\BackupSet;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\Policy;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
pest()->browser()->timeout(20_000);
|
|
|
|
function spec334SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $redirect = ''): string
|
|
{
|
|
$tenant->loadMissing('workspace');
|
|
|
|
$redirect = trim($redirect);
|
|
|
|
if ($redirect !== '') {
|
|
$parsed = parse_url($redirect);
|
|
|
|
if (is_array($parsed) && ! isset($parsed['scheme'], $parsed['host'])) {
|
|
$redirect = '/'.ltrim((string) ($parsed['path'] ?? ''), '/');
|
|
$query = isset($parsed['query']) ? '?'.$parsed['query'] : '';
|
|
$fragment = isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
|
|
$redirect = $redirect.$query.$fragment;
|
|
} elseif (is_array($parsed)) {
|
|
$redirect = '/'.ltrim((string) ($parsed['path'] ?? ''), '/');
|
|
$query = isset($parsed['query']) ? '?'.$parsed['query'] : '';
|
|
$fragment = isset($parsed['fragment']) ? '#'.$parsed['fragment'] : '';
|
|
$redirect = $redirect.$query.$fragment;
|
|
}
|
|
}
|
|
|
|
return route('admin.local.smoke-login', array_filter([
|
|
'email' => (string) $user->email,
|
|
'tenant' => (string) $tenant->external_id,
|
|
'workspace' => (string) ($tenant->workspace?->slug ?? ''),
|
|
'redirect' => $redirect,
|
|
], static fn (?string $value): bool => filled($value)));
|
|
}
|
|
|
|
it('smokes the backup set add policies picker without selection-column regressions', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
config()->set('queue.default', 'database');
|
|
|
|
$backupSet = BackupSet::factory()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'name' => 'Spec334 Browser Backup Set',
|
|
]);
|
|
|
|
Policy::factory()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'display_name' => 'Spec334 Browser Policy A',
|
|
'ignored_at' => null,
|
|
'missing_from_provider_at' => null,
|
|
'last_synced_at' => now(),
|
|
]);
|
|
|
|
Policy::factory()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'display_name' => 'Spec334 Browser Policy B',
|
|
'ignored_at' => null,
|
|
'missing_from_provider_at' => null,
|
|
'last_synced_at' => now(),
|
|
]);
|
|
|
|
$backupSetUrl = BackupSetResource::getUrl('view', ['record' => $backupSet], panel: 'admin', tenant: $tenant);
|
|
|
|
$page = visit(spec334SmokeLoginUrl($user, $tenant, $backupSetUrl))
|
|
->waitForText('Spec334 Browser Backup Set')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee('Related context');
|
|
|
|
$page->script('window.scrollTo(0, document.body.scrollHeight);');
|
|
|
|
$page
|
|
->waitForText('Add Policies')
|
|
->click('Add Policies')
|
|
->waitForText('Spec334 Browser Policy A')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
expect($page->script(<<<'JS'
|
|
(() => {
|
|
const visibleTables = Array.from(document.querySelectorAll('.fi-ta')).filter((table) => table && table.offsetParent !== null);
|
|
const table = visibleTables.at(-1);
|
|
|
|
if (!table) {
|
|
return { selectable: 0, total: 0 };
|
|
}
|
|
|
|
const rows = Array.from(table.querySelectorAll('tbody tr.fi-ta-row'));
|
|
const selectable = rows.filter((row) => row.querySelector('input[type="checkbox"]:not([disabled])')).length;
|
|
|
|
return { selectable, total: rows.length };
|
|
})();
|
|
JS))->toMatchArray([
|
|
'total' => 2,
|
|
'selectable' => 2,
|
|
]);
|
|
|
|
$page
|
|
->click('.fi-ta:visible tbody tr.fi-ta-row:has-text("Spec334 Browser Policy A") input[type="checkbox"]')
|
|
->waitForText('Add selected')
|
|
->click('Add selected')
|
|
->waitForText('Backup set update queued')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
});
|
|
|
|
it('smokes the restore run create wizard without tenantless Livewire update crashes', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$backupSet = BackupSet::factory()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'name' => 'Spec334 Restore Fixture Backup Set',
|
|
]);
|
|
|
|
$createUrl = RestoreRunResource::getUrl('create', panel: 'admin', tenant: $tenant)
|
|
.'?backup_set_id='.(int) $backupSet->getKey();
|
|
|
|
visit(spec334SmokeLoginUrl($user, $tenant, $createUrl))
|
|
->waitForText('Select Backup Set')
|
|
->waitForText('Backup set')
|
|
->assertDontSee('No tenant context selected')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->click('button:has-text("Next")')
|
|
->waitForText('Define Restore Scope')
|
|
->assertDontSee('No tenant context selected')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
});
|