TenantAtlas/apps/platform/tests/Browser/Spec353ProviderReadinessGuidanceSmokeTest.php
ahmido d2876af95b feat: provider connections resolution guidance v1 (spec 353) (#424)
Implemented the first version of provider readiness resolution guidance. Added the ProviderReadinessResolutionAdapter, provider readiness guidance card, and updated EnvironmentRequiredPermissions, ProviderConnectionResource, and ListProviderConnections/ViewProviderConnection. Added tests and updated the design coverage matrix.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #424
2026-06-04 22:41:04 +00:00

270 lines
10 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\EnvironmentDashboard;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentPermission;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\User;
use App\Models\Workspace;
use App\Support\ManagedEnvironmentLinks;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Providers\ProviderVerificationStatus;
use App\Support\Workspaces\WorkspaceContext;
pest()->browser()->timeout(40_000);
beforeEach(function (): void {
config()->set('graph.client_id', 'spec353-platform-client');
config()->set('graph.client_secret', 'spec353-platform-secret');
config()->set('graph.managed_environment_id', 'organizations');
});
function spec353BrowserApplicationPermissionKey(): string
{
$permission = collect(spec283ConfiguredPermissionRows())
->first(static fn (mixed $row): bool => is_array($row) && ($row['type'] ?? null) === 'application');
expect($permission)->not->toBeNull();
return (string) $permission['key'];
}
function spec353BrowserSeedPermissionRows(
ManagedEnvironment $environment,
array $missingKeys = [],
array $errorKeys = [],
?\DateTimeInterface $lastCheckedAt = null,
): void {
foreach (spec283ConfiguredPermissionRows() as $permission) {
if (! is_array($permission)) {
continue;
}
$permissionKey = (string) ($permission['key'] ?? '');
if ($permissionKey === '') {
continue;
}
ManagedEnvironmentPermission::query()->updateOrCreate(
[
'managed_environment_id' => (int) $environment->getKey(),
'permission_key' => $permissionKey,
'workspace_id' => (int) $environment->workspace_id,
],
[
'status' => in_array($permissionKey, $errorKeys, true)
? 'error'
: (in_array($permissionKey, $missingKeys, true) ? 'missing' : 'granted'),
'details' => ['source' => 'spec353-browser-test'],
'last_checked_at' => $lastCheckedAt ?? now(),
],
);
}
}
/**
* @return array{
* user: User,
* workspace: Workspace,
* blockedEnvironment: ManagedEnvironment,
* blockedConnection: ProviderConnection,
* failedEnvironment: ManagedEnvironment,
* failedConnection: ProviderConnection,
* readyEnvironment: ManagedEnvironment,
* readyConnection: ProviderConnection,
* }
*/
function spec353BrowserFixture(): array
{
[$user, $blockedEnvironment] = createUserWithTenant(
role: 'owner',
workspaceRole: 'owner',
ensureDefaultMicrosoftProviderConnection: false,
);
$workspace = $blockedEnvironment->workspace()->firstOrFail();
$failedEnvironment = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'name' => 'Spec353 Verification Failed',
]);
$readyEnvironment = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'name' => 'Spec353 Provider Ready',
]);
$user->tenants()->syncWithoutDetaching([
(int) $failedEnvironment->getKey() => ['role' => 'owner'],
(int) $readyEnvironment->getKey() => ['role' => 'owner'],
]);
$blockedConnection = ProviderConnection::factory()->platform()->verifiedHealthy()->create([
'managed_environment_id' => (int) $blockedEnvironment->getKey(),
'workspace_id' => (int) $workspace->getKey(),
'display_name' => 'Spec353 Blocked Connection',
'is_default' => true,
]);
$failedConnection = ProviderConnection::factory()->platform()->consentGranted()->create([
'managed_environment_id' => (int) $failedEnvironment->getKey(),
'workspace_id' => (int) $workspace->getKey(),
'display_name' => 'Spec353 Failed Connection',
'is_default' => true,
'verification_status' => ProviderVerificationStatus::Error->value,
'last_error_message' => 'Spec353 verification failed during health check.',
]);
$readyConnection = ProviderConnection::factory()->platform()->verifiedHealthy()->create([
'managed_environment_id' => (int) $readyEnvironment->getKey(),
'workspace_id' => (int) $workspace->getKey(),
'display_name' => 'Spec353 Ready Connection',
'is_default' => true,
'last_health_check_at' => now(),
]);
$missingPermissionKey = spec353BrowserApplicationPermissionKey();
spec353BrowserSeedPermissionRows($blockedEnvironment, missingKeys: [$missingPermissionKey]);
spec353BrowserSeedPermissionRows($failedEnvironment);
spec353BrowserSeedPermissionRows($readyEnvironment);
OperationRun::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'managed_environment_id' => (int) $failedEnvironment->getKey(),
'type' => 'provider.connection.check',
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Failed->value,
'context' => [
'provider_connection_id' => (int) $failedConnection->getKey(),
],
]);
return [
'user' => $user,
'workspace' => $workspace,
'blockedEnvironment' => $blockedEnvironment,
'blockedConnection' => $blockedConnection,
'failedEnvironment' => $failedEnvironment,
'failedConnection' => $failedConnection,
'readyEnvironment' => $readyEnvironment,
'readyConnection' => $readyConnection,
];
}
function spec353BrowserActAs(User $user, Workspace $workspace, ManagedEnvironment $environment): void
{
test()->actingAs($user)->withSession([
WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
(string) $workspace->getKey() => (int) $environment->getKey(),
],
]);
}
function spec353BrowserScreenshot(string $name): string
{
return 'spec353-'.$name;
}
function spec353CopyBrowserScreenshot(string $name): void
{
$filename = spec353BrowserScreenshot($name).'.png';
$source = \Pest\Browser\Support\Screenshot::path($filename);
$targetDirectory = repo_path('specs/353-provider-connections-resolution-guidance-v1/artifacts/screenshots');
if (! is_dir($targetDirectory)) {
@mkdir($targetDirectory, 0755, true);
}
if (! is_dir($targetDirectory) || ! is_writable($targetDirectory)) {
return;
}
if (is_file($source)) {
@copy($source, $targetDirectory.DIRECTORY_SEPARATOR.$filename);
}
}
function spec353BrowserTextContainsScript(string $selector, string $text): string
{
$encodedSelector = json_encode($selector);
$encodedText = json_encode($text);
return <<<JS
(() => {
const element = document.querySelector($encodedSelector);
if (! element) {
return false;
}
return element.textContent.replace(/\\s+/g, ' ').trim().includes($encodedText);
})()
JS;
}
it('smokes provider readiness guidance across dashboard, required permissions, provider connections, and screenshots', function (): void {
$fixture = spec353BrowserFixture();
spec353BrowserActAs($fixture['user'], $fixture['workspace'], $fixture['blockedEnvironment']);
$blockedPermissionsPage = visit(ManagedEnvironmentLinks::requiredPermissionsUrl($fixture['blockedEnvironment']))
->resize(1440, 1100)
->waitForText(__('localization.provider_guidance.required_permissions_missing_title'))
->assertScript(
spec353BrowserTextContainsScript(
'[data-testid="provider-readiness-reason"]',
__('localization.provider_guidance.required_application_permissions_reason'),
),
true,
)
->assertSee(__('localization.provider_guidance.action_open_admin_consent'))
->assertScript('document.querySelector("[data-testid=\"provider-readiness-details\"]")?.open === false', true)
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec353BrowserScreenshot('01-required-permissions-blocked'));
spec353CopyBrowserScreenshot('01-required-permissions-blocked');
$blockedPermissionsPage->resize(900, 1100)
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
visit(EnvironmentDashboard::getUrl(panel: 'admin', tenant: $fixture['blockedEnvironment']))
->waitForText('Provider readiness blocks evidence refresh')
->click('[data-testid="tenant-dashboard-primary-next-action"] a')
->waitForText(__('localization.provider_guidance.required_permissions_missing_title'))
->assertScript(
spec353BrowserTextContainsScript(
'[data-testid="provider-readiness-reason"]',
__('localization.provider_guidance.required_application_permissions_reason'),
),
true,
)
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
visit(ManagedEnvironmentLinks::providerConnectionUrl($fixture['failedConnection'], 'view', $fixture['failedEnvironment']))
->resize(1440, 1100)
->waitForText(__('localization.provider_guidance.verification_failed_title'))
->assertSee(__('localization.provider_guidance.action_open_verification_operation'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec353BrowserScreenshot('02-provider-connection-verification-failed'));
spec353CopyBrowserScreenshot('02-provider-connection-verification-failed');
visit(ManagedEnvironmentLinks::providerConnectionUrl($fixture['readyConnection'], 'view', $fixture['readyEnvironment']))
->resize(1440, 1100)
->waitForText(__('localization.provider_guidance.ready_title'))
->assertSee(__('localization.provider_guidance.ready_reason'))
->assertSee(__('localization.provider_guidance.action_open_environment_dashboard'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec353BrowserScreenshot('03-provider-connection-ready'));
spec353CopyBrowserScreenshot('03-provider-connection-ready');
});