actingAs(Operator::factory()->role('Read-only')->create(), 'operator') ->get(route('admin.readiness')) ->assertForbidden(); }); it('lists every check, satisfied or not', function () { // Livewire::actingAs() needs the 'operator' guard spelled out — omitting it // signed the test in on the 'web' guard instead and cost Task 11 a failing // test for exactly this reason. Livewire::actingAs(Operator::factory()->role('Owner')->create(), 'operator') ->test(ReadinessPage::class) ->assertSee(__('readiness.billing.company_details')) ->assertSee(__('readiness.provisioning.usable_host')); }); it('says what breaks, not only that something is missing', function () { Livewire::actingAs(Operator::factory()->role('Owner')->create(), 'operator') ->test(ReadinessPage::class) ->assertSee(__('readiness.delivery.mailer_not_log_breaks')); }); it('runs an active check on demand and shows its answer', function () { // Die drei Prüfungen aus Task 9 sind nur dann etwas wert, wenn jemand sie // auslösen kann. Sie laufen NICHT bei jedem Seitenaufruf mit: eine davon // schreibt einen TXT-Eintrag in die echte Zone. // // Http::fake() steht hier unbedingt, nicht weil dieser eine Testpfad das // Netzwerk erreicht (DnsTokenCheck bricht schon vorher an blank($token) // || blank($zone) ab), sondern weil JEDER Test, der runCheck() anfasst, // dieselbe Absicherung tragen soll — ein Testpfad, der heute früh // ausscheidet, ist keine Garantie, dass er es morgen noch tut. Http::fake(); Livewire::actingAs(Operator::factory()->role('Owner')->create(), 'operator') ->test(ReadinessPage::class) ->call('runCheck', 'provisioning.dns_token') ->assertSet('results.provisioning.dns_token.ok', false); }); it('refuses to run a check that is not on the list', function () { // Ein Schlüssel aus dem Browser. Ohne diese Prüfung wäre das ein Weg, // beliebige Klassen aufzurufen. Http::fake(); Livewire::actingAs(Operator::factory()->role('Owner')->create(), 'operator') ->test(ReadinessPage::class) ->call('runCheck', 'etwas.erfundenes') ->assertSet('results', []); }); /** * Der Wächter dieser Spec. * * Ein künftig hinzugefügtes Zugangsdatum darf nicht still an der Übersicht * vorbeigehen. Genau das war der Befund vom 2026-07-30: eine grüne Testsuite * bei einer Installation, die keinen Host durchinstallieren konnte, weil * niemand die Liste geführt hat. */ it('covers every entry in the secret registry', function () { $covered = collect(Readiness::all())->pluck('key')->implode(' '); foreach (array_keys(SecretVault::REGISTRY) as $secret) { // `stripe.secret` → irgendein Prüfschlüssel, der `stripe_secret` enthält. $needle = str_replace('.', '_', $secret); // NICHT expect($covered)->toContain($needle, $message) — Pest's // toContain() ist variadic, ein zweites Argument ist ein zweiter // GEFORDERTER Substring, keine eigene Fehlermeldung. Genau diese Falle // dokumentiert tests/Feature/ModalHeightTest.php bereits selbst // ("asserted that the footer contains its own filename, which is why // this failed on a file that was correct") — der Brief-Code für diesen // Test tappte hinein: er scheiterte auf JEDEM Eintrag, auch auf // 'stripe_secret', das längst abgedeckt ist. str_contains() + toBeTrue() // mit Nachricht liefert die Prüfung UND den lesbaren Hinweis. expect(str_contains($covered, $needle))->toBeTrue( "Der Tresor-Eintrag [{$secret}] taucht auf der Bereitschaftsseite nicht auf." ); } });