browser()->timeout(60_000); it('Spec422 smokes the Coverage v2 inspect surface for Exchange and Teams comparable renderable evidence', function (): void { [$user, $environment] = spec422CoverageV2BrowserFixture(); spec422AuthenticateCoverageV2Browser($this, $user, $environment); $page = visit(CoverageV2Readiness::getUrl(tenant: $environment, panel: 'admin')) ->resize(768, 1100) ->waitForText('Coverage v2 Readiness') ->waitForText('Spec422 Browser Meeting Policy') ->assertSee('Resource type registry') ->assertSee('Resource instances') ->assertSee('Transport rule') ->assertSee('Meeting policy') ->assertSee('Coverage level') ->assertSee('Renderable') ->assertSee('Internal only') ->assertDontSee('meetingPolicy:provider_external_id:spec422-browser') ->assertDontSee('transportRule:provider_external_id:spec422-browser') ->assertDontSee('Exchange covered') ->assertDontSee('Teams covered') ->assertDontSee('certified') ->assertDontSee('restore-ready') ->assertDontSee('customer-ready') ->assertDontSee('full Exchange coverage') ->assertDontSee('100% Teams') ->assertDontSee('spec422-browser-raw-secret') ->assertDontSee('spec422-browser-chat-secret') ->assertScript('typeof window.Livewire !== "undefined"', true) ->assertScript('(() => document.querySelectorAll("table tbody tr").length > 0)()', true) ->assertScript(<<<'JS' (() => { const row = Array.from(document.querySelectorAll('table tbody tr')) .find((candidate) => candidate.textContent.includes('Spec422 Browser Meeting Policy')); const resourceTypeCellText = row?.querySelectorAll('td')?.[1]?.innerText ?? ''; return resourceTypeCellText.includes('Meeting policy') && ! resourceTypeCellText.includes('meetingPolicy'); })() JS, true) ->assertScript("(() => performance.getEntriesByType('resource').filter((entry) => /graph\\.microsoft\\.com|\\/tcm\\b|provider-remote/i.test(entry.name)).length)()", 0) ->assertScript("(() => Array.from(document.querySelectorAll('main button, main a')).map((element) => element.textContent.trim()).filter(Boolean).some((label) => /^(Capture|Restore|Certify|Export|Download)$/i.test(label)))()", false) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); $page->script(<<<'JS' (() => { const rows = Array.from(document.querySelectorAll('table tbody tr')); const row = rows.find((candidate) => candidate.textContent.includes('Spec422 Browser Meeting Policy')); const inspect = Array.from(row?.querySelectorAll('button, a') ?? []) .find((element) => element.textContent.includes('Spec422 Browser Meeting Policy')); inspect?.click(); })() JS); $page ->waitForText('Coverage: Renderable') ->assertSee('Teams meeting policy') ->assertSee('Display name') ->assertSee('Spec422 Browser Meeting Policy') ->assertSee('Recording / transcription') ->assertSee('Allow Transcription: yes') ->assertSee('Content sharing') ->assertSee('Screen Sharing Mode: EntireScreen') ->assertSee('Compare summary') ->assertSee('Material changes detected') ->assertSee('Previous comparable evidence') ->assertSee('Recording Transcription Allow Transcription') ->assertSee('Redacted fields') ->assertSee('chatContent') ->assertSee('Evidence: Content backed') ->assertSee('Identity: Stable') ->assertSee('Claim: Internal only') ->assertSee('View technical details') ->assertDontSee('Source: TCM') ->assertDontSee('Evidence hash') ->assertDontSee('Source contract') ->assertDontSee('Source schema hash') ->assertDontSee('Operation #') ->assertDontSee('meetingPolicy:provider_external_id:spec422-browser') ->assertScript('(() => document.querySelector("details")?.open === false)()', true) ->assertScript(<<<'JS' (() => { const technicalDetails = document.querySelector('details')?.textContent ?? ''; return technicalDetails.includes('Source: TCM') && technicalDetails.includes('Evidence hash') && technicalDetails.includes('Source contract') && technicalDetails.includes('Source schema hash') && technicalDetails.includes('Operation #'); })() JS, true) ->assertDontSee('Exchange covered') ->assertDontSee('Teams covered') ->assertDontSee('certified') ->assertDontSee('restore-ready') ->assertDontSee('customer-ready') ->assertDontSee('full Exchange coverage') ->assertDontSee('100% Teams') ->assertDontSee('spec422-browser-raw-secret') ->assertDontSee('spec422-browser-chat-secret') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs() ->screenshot(true, 'spec422-exchange-teams-comparable-renderable-operator-surface'); }); /** * @return array{0: User, 1: ManagedEnvironment} */ function spec422CoverageV2BrowserFixture(): array { app(ResourceTypeRegistry::class)->syncDefaults(); $environment = ManagedEnvironment::factory()->active()->create([ 'name' => 'Spec422 Browser Environment', 'external_id' => 'spec422-browser-environment', ]); [$user, $environment] = createUserWithTenant( tenant: $environment, role: 'owner', workspaceRole: 'owner', clearCapabilityCaches: true, ); $connection = ProviderConnection::factory()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'display_name' => 'Spec422 Browser Microsoft provider', ]); TenantConfigurationSupportedScope::factory()->create([ 'scope_key' => 'spec422_browser_internal_exchange_teams_scope', 'display_name' => 'Spec422 Browser internal Exchange Teams scope', 'minimum_coverage_level' => CoverageLevel::ContentBacked->value, 'included_resource_types' => ['transportRule', 'meetingPolicy'], 'allow_graph_fallback' => false, 'allow_beta' => false, 'customer_claims_allowed' => false, ]); spec422BrowserEvidenceResource( environment: $environment, user: $user, connection: $connection, canonicalType: 'transportRule', displayName: 'Spec422 Browser Transport Rule', previousPayload: [ 'DisplayName' => 'Spec422 Browser Transport Rule', 'Enabled' => true, 'Actions' => ['RedirectMessageTo' => ['old-security@example.com']], ], latestPayload: [ 'DisplayName' => 'Spec422 Browser Transport Rule', 'Enabled' => true, 'Actions' => ['RedirectMessageTo' => ['security@example.com']], ], hashSeed: 'a', ); spec422BrowserEvidenceResource( environment: $environment, user: $user, connection: $connection, canonicalType: 'meetingPolicy', displayName: 'Spec422 Browser Meeting Policy', previousPayload: [ 'DisplayName' => 'Spec422 Browser Meeting Policy', 'AllowTranscription' => false, 'ScreenSharingMode' => 'SingleApplication', ], latestPayload: [ 'DisplayName' => 'Spec422 Browser Meeting Policy', 'AllowTranscription' => true, 'ScreenSharingMode' => 'EntireScreen', 'chatContent' => 'spec422-browser-chat-secret', ], hashSeed: 'b', ); return [$user, $environment->refresh()]; } function spec422BrowserEvidenceResource( ManagedEnvironment $environment, User $user, ProviderConnection $connection, string $canonicalType, string $displayName, array $previousPayload, array $latestPayload, string $hashSeed, ): TenantConfigurationResource { $resourceType = TenantConfigurationResourceType::query() ->where('canonical_type', $canonicalType) ->where('source_class', SourceClass::Tcm->value) ->firstOrFail(); $previousRun = spec422BrowserRun($environment, $user, $connection, $canonicalType, minutesAgo: 5); $run = spec422BrowserRun($environment, $user, $connection, $canonicalType); $resource = TenantConfigurationResource::factory()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), 'resource_type_id' => (int) $resourceType->getKey(), 'canonical_type' => $canonicalType, 'canonical_resource_key' => $canonicalType.':provider_external_id:spec422-browser', 'canonical_key_kind' => CanonicalKeyKind::ProviderExternalId->value, 'source_resource_id' => 'spec422-browser', 'source_display_name' => $displayName, 'source_class' => SourceClass::Tcm->value, 'source_metadata' => [ 'source_contract_key' => 'spec422.synthetic.'.$canonicalType, 'source_endpoint' => '/spec422/synthetic/'.$canonicalType, 'source_version' => 'v1.0', 'registry_source_class' => SourceClass::Tcm->value, 'registry_support_state' => 'out_of_scope', ], 'identity_strategy' => 'provider.external.id.v1', 'source_identity' => [ 'primary_field' => 'id', 'primary_value' => 'spec422-browser', ], 'identity_diagnostics' => [ 'reason_code' => 'provider_external_id', ], 'identity_evaluated_at' => now(), 'latest_evidence_state' => EvidenceState::ContentBacked->value, 'latest_identity_state' => IdentityState::Stable->value, 'latest_claim_state' => ClaimState::InternalOnly->value, 'latest_captured_at' => now(), ]); TenantConfigurationResourceEvidence::factory()->create([ 'resource_id' => (int) $resource->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), 'resource_type_id' => (int) $resourceType->getKey(), 'operation_run_id' => (int) $previousRun->getKey(), 'source_contract_key' => 'spec422.synthetic.'.$canonicalType, 'source_endpoint' => '/spec422/synthetic/'.$canonicalType, 'source_version' => 'v1.0', 'source_schema_hash' => 'spec422-browser-previous-schema-hash', 'source_metadata' => [ 'registry_source_class' => SourceClass::Tcm->value, 'registry_support_state' => 'out_of_scope', ], 'raw_payload' => ['id' => 'spec422-browser'], 'normalized_payload' => $previousPayload, 'payload_hash' => str_repeat($hashSeed, 64), 'permission_context' => ['scopes_granted' => []], 'evidence_state' => EvidenceState::ContentBacked->value, 'coverage_level' => CoverageLevel::Comparable->value, 'capture_outcome' => CaptureOutcome::Captured->value, 'captured_at' => now()->subMinutes(5), ]); $evidence = TenantConfigurationResourceEvidence::factory()->create([ 'resource_id' => (int) $resource->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), 'resource_type_id' => (int) $resourceType->getKey(), 'operation_run_id' => (int) $run->getKey(), 'source_contract_key' => 'spec422.synthetic.'.$canonicalType, 'source_endpoint' => '/spec422/synthetic/'.$canonicalType, 'source_version' => 'v1.0', 'source_schema_hash' => 'spec422-browser-schema-hash', 'source_metadata' => [ 'registry_source_class' => SourceClass::Tcm->value, 'registry_support_state' => 'out_of_scope', ], 'raw_payload' => ['id' => 'spec422-browser', 'secret' => 'spec422-browser-raw-secret'], 'normalized_payload' => $latestPayload, 'payload_hash' => str_repeat(strtoupper($hashSeed), 64), 'permission_context' => ['scopes_granted' => []], 'evidence_state' => EvidenceState::ContentBacked->value, 'coverage_level' => CoverageLevel::Renderable->value, 'capture_outcome' => CaptureOutcome::Captured->value, 'captured_at' => now(), ]); $resource->forceFill([ 'latest_evidence_id' => (int) $evidence->getKey(), 'latest_payload_hash' => (string) $evidence->payload_hash, ])->save(); return $resource->refresh(); } function spec422BrowserRun( ManagedEnvironment $environment, User $user, ProviderConnection $connection, string $canonicalType, int $minutesAgo = 0, ): OperationRun { $timestamp = $minutesAgo > 0 ? now()->subMinutes($minutesAgo) : now(); return OperationRun::factory()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'user_id' => (int) $user->getKey(), 'initiator_name' => (string) $user->name, 'type' => OperationRunType::TenantConfigurationCapture->value, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'summary_counts' => [ 'total' => 1, 'processed' => 1, 'succeeded' => 1, 'skipped' => 0, 'failed' => 0, 'errors_recorded' => 0, ], 'context' => [ 'requested_resource_types' => [$canonicalType], 'outcomes' => [ ['canonical_type' => $canonicalType, 'outcome' => CaptureOutcome::Captured->value], ], 'target_scope' => [ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), ], ], 'started_at' => $timestamp, 'completed_at' => $timestamp, ]); } function spec422AuthenticateCoverageV2Browser( mixed $test, User $user, ManagedEnvironment $environment, ): void { $workspaceId = (int) $environment->workspace_id; $test->actingAs($user)->withSession([ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [ (string) $workspaceId => (int) $environment->getKey(), ], ]); session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [ (string) $workspaceId => (int) $environment->getKey(), ]); }