spatie/pest-plugin-test-time
A Pest plugin for controlling time in tests. Freeze or advance Carbon’s current time with testTime()->freeze() and addMinute(), and use the toBeCarbon expectation to assert Carbon date and time values clearly.
Carbon::setTestNow() plus one expectation. Cost of buying is zero (MIT, --dev only, no config, no service provider, no production footprint). The real decision is standardization: one idiom across the team vs. every engineer rolling their own freeze/reset helper. Choose this package to end that drift.Consider it when:
now(), Carbon::now(), Carbon::parse()).freeze() covers the whole path).Look elsewhere / don't bother when:
Carbon::setTestNow() directly. Don't add Pest just for this.time()/mktime(), Carbon::createFromTimestamp(time()), and SQL NOW()/CURRENT_TIMESTAMP are unaffected by freezing. If that's your codebase, this package gives false confidence — fix where time is read first, or use a clock-abstraction layer.sleep() is a trap (it really waits; the clock doesn't move). Scope the expectation accordingly.Non-negotiable guardrails if adopted: add afterEach(fn () => Carbon::setTestNow()) (leaked frozen time produces "passes alone, fails in suite" bugs), and pass an explicit format to toBeCarbon in any shared helper rather than relying on shape inference.
To executives: This is a free, MIT-licensed, developer-only testing utility with zero production footprint — it can't affect customers, latency, or security surface. It buys us two things: less engineering time lost to intermittently failing tests, and higher confidence shipping revenue-adjacent date logic (trials, renewals, proration, expiries). The only real cost is a scheduling dependency: the current version tracks PHP 8.4 / Pest 5, so adopting it aligns with an upgrade we'd likely plan anyway. Exit cost is negligible — it's a thin wrapper over a Carbon built-in, so removing it is an afternoon, not a migration.
To engineering: composer require spatie/pest-plugin-test-time --dev. No config, no service provider, no Pest.php registration. Two idioms: testTime()->freeze('2024-01-01 09:00:00') then walk forward with addDays()/addMinute() (chainable, literal hops only — never compute expected values with now()->addDays(3), that makes tests tautological), and expect($x->renews_at)->toBeCarbon('2024-02-29') for readable assertions. Feature-test the whole HTTP → job → notification path under one freeze. Add the afterEach reset. Keep time reads in Carbon, not native PHP or raw SQL. Pin 2.2.x unless we're on Pest 5 / PHP 8.4 / Carbon 3 — verify the matrix before you standardize.
How can I help you explore Laravel packages today?