events()) ->map(fn ($event): string => $event->getSummaryForDisplay()); $this->assertCount(4, $summaries); $this->assertScheduleContains($summaries, 'integrations:refresh'); $this->assertScheduleContains($summaries, 'alerts:scan'); $this->assertScheduleContains($summaries, 'etsy:sync'); $this->assertScheduleContains($summaries, 'etsy:refresh-token'); } public function test_existing_jobs_keep_their_thirty_second_cadence_and_overlap_guard(): void { $events = collect(app(Schedule::class)->events()); $refresh = $events->first(fn ($event): bool => str_contains((string) $event->command, 'integrations:refresh')); $alerts = $events->first(fn ($event): bool => str_contains((string) $event->command, 'alerts:scan')); $this->assertNotNull($refresh); $this->assertNotNull($alerts); $this->assertSame('* * * * *', $refresh->expression); $this->assertSame(30, $refresh->repeatSeconds); $this->assertSame('* * * * *', $alerts->expression); $this->assertSame(30, $alerts->repeatSeconds); $this->assertTrue($refresh->withoutOverlapping); $this->assertSame(5, $refresh->expiresAt); $this->assertTrue($alerts->withoutOverlapping); $this->assertSame(5, $alerts->expiresAt); } public function test_etsy_jobs_use_their_default_frequencies(): void { $events = collect(app(Schedule::class)->events()); $sync = $events->first(fn ($event): bool => str_contains((string) $event->command, 'etsy:sync')); $tokenRefresh = $events->first(fn ($event): bool => str_contains((string) $event->command, 'etsy:refresh-token')); $this->assertNotNull($sync); $this->assertNotNull($tokenRefresh); $this->assertSame('*/15 * * * *', $sync->expression); $this->assertSame('*/45 * * * *', $tokenRefresh->expression); } public function test_changing_a_stored_frequency_changes_what_gets_scheduled(): void { DashboardSchedule::persistRuntimeFrequencies([ 'etsy_sync' => 'hourly', 'etsy_token_refresh' => 'disabled', ]); // The schedule singleton is built once at boot (before this test writes // the settings file), so force a fresh Schedule and re-run the registry // against it to see the just-persisted frequencies take effect, the way // the next real `schedule:run` boot cycle would. app()->forgetInstance(Schedule::class); \Illuminate\Support\Facades\Schedule::clearResolvedInstance(Schedule::class); DashboardSchedule::register(); $events = collect(app(Schedule::class)->events()); $sync = $events->first(fn ($event): bool => str_contains((string) $event->command, 'etsy:sync')); $tokenRefresh = $events->first(fn ($event): bool => str_contains((string) $event->command, 'etsy:refresh-token')); $this->assertNotNull($sync); $this->assertSame('0 * * * *', $sync->expression); $this->assertNull($tokenRefresh); } private function assertScheduleContains($summaries, string $expected): void { $this->assertTrue( $summaries->contains(fn (string $summary): bool => str_contains($summary, $expected)), "Failed asserting that the scheduler contains [{$expected}]." ); } }