withHeaders(['Accept-Language' => 'es']); } #[Test] public function the_public_api_answers_503_with_the_notice(): void { Project::factory()->published()->create(); Maintenance::enable(message: ['es' => 'Volvemos en una hora.']); $response = $this->getJson('/api/public/v1/projects'); $response->assertStatus(503) ->assertJsonPath('maintenance', true) ->assertJsonPath('message', 'Volvemos en una hora.'); $this->assertNotNull($response->headers->get('Retry-After')); // A cached 503 would outlive the maintenance itself. $this->assertSame('no-store, private', $response->headers->get('Cache-Control')); } #[Test] public function the_notice_is_returned_in_the_requested_language(): void { Maintenance::enable(message: [ 'es' => 'Estamos de obras.', 'ca' => 'Estem d\'obres.', ]); $this->getJson('/api/public/v1/site?lang=ca') ->assertStatus(503) ->assertJsonPath('message', 'Estem d\'obres.'); } #[Test] public function a_language_without_a_written_notice_falls_back(): void { Maintenance::enable(message: ['es' => 'Solo en castellano.']); // Falls back to the default locale's wording rather than showing // nothing to an English visitor. $this->getJson('/api/public/v1/site?lang=en') ->assertStatus(503) ->assertJsonPath('message', 'Solo en castellano.'); } #[Test] public function with_no_notice_written_a_translated_default_is_used(): void { Maintenance::enable(); $this->getJson('/api/public/v1/site?lang=en') ->assertStatus(503) ->assertJsonPath('message', __('maintenance.default_message', [], 'en')); } #[Test] public function the_panel_keeps_working_while_the_site_is_down(): void { $this->seed(RolePermissionSeeder::class); Maintenance::enable(); // The whole point: the collective must be able to fix whatever caused // the maintenance. $this->actingAs($this->userWithRoles('admin')) ->get('/admin') ->assertSuccessful(); } #[Test] public function the_admin_api_keeps_working_while_the_site_is_down(): void { $this->seed(RolePermissionSeeder::class); Maintenance::enable(); $user = $this->userWithRoles('editor'); $this->getJson('/api/v1/me', $this->apiHeadersFor($user))->assertOk(); } #[Test] public function the_preview_secret_lets_the_team_see_the_real_site(): void { config()->set('site.preview_token', 'the-secret'); Project::factory()->published()->create(); Maintenance::enable(); $this->getJson('/api/public/v1/projects', ['X-Preview-Token' => 'the-secret']) ->assertOk() ->assertJsonCount(1, 'data'); } #[Test] public function a_trusted_ip_also_bypasses_it(): void { config()->set('site.trusted_ips', ['127.0.0.1']); Project::factory()->published()->create(); Maintenance::enable(); $this->getJson('/api/public/v1/projects')->assertOk(); } #[Test] public function it_lifts_itself_once_the_window_has_passed(): void { Maintenance::enable(until: now()->addHour()->toImmutable()); $this->assertTrue(Maintenance::isEnabled()); $this->travel(2)->hours(); // A forgotten flag must not keep the site down forever. $this->assertFalse(Maintenance::isEnabled()); $this->getJson('/api/public/v1/site')->assertOk(); } #[Test] public function retry_after_reflects_the_remaining_window(): void { Maintenance::enable(until: now()->addMinutes(10)->toImmutable()); $retryAfter = (int) $this->getJson('/api/public/v1/site') ->assertStatus(503) ->headers->get('Retry-After'); $this->assertGreaterThan(500, $retryAfter); $this->assertLessThanOrEqual(600, $retryAfter); } #[Test] public function disabling_brings_the_site_back(): void { Maintenance::enable(); $this->getJson('/api/public/v1/site')->assertStatus(503); Maintenance::disable(); $this->getJson('/api/public/v1/site')->assertOk(); } #[Test] public function the_setting_is_cached_but_a_change_takes_effect_at_once(): void { $this->getJson('/api/public/v1/site')->assertOk(); Maintenance::enable(); // Writes clear the cache entry, so there is no stale window in which // the site stays up after someone flipped the switch. $this->getJson('/api/public/v1/site')->assertStatus(503); } #[Test] public function toggling_it_needs_its_own_permission(): void { $this->seed(RolePermissionSeeder::class); $editor = $this->userWithRoles('editor'); $admin = $this->userWithRoles('admin'); // Editors can see the state but not take the site down. $this->assertTrue($editor->can('settings.view')); $this->assertFalse($editor->can('settings.maintenance')); $this->assertTrue($admin->can('settings.maintenance')); } #[Test] public function the_command_reports_and_toggles(): void { $this->artisan('site:maintenance', ['--message' => 'Obras']) ->assertSuccessful(); $this->assertTrue(Maintenance::isEnabled()); $this->assertSame('Obras', Maintenance::message('es')); $this->artisan('site:maintenance', ['--up' => true])->assertSuccessful(); $this->assertFalse(Maintenance::isEnabled()); } }