Laravel Wormholes

Laravel Wormholes

What is Wormhole?

A wormhole is a scientific theory, referring to shortcuts in time and space, through which a matter can instantly travel from one point to another.

Time traveling with Laravel

Implementing a similar concept, Laravel 8 has introduced the Wormhole-related class and trait to help with the event-driven development process. Though time travel is theoretical, we can experience and implement it on Laravel projects, saving time in development.

It is mostly handy while testing the time-constrained features on projects. Besides tests, the concept could be incorporated into other use cases like prediction, stock exchange, banking applications and so on.

Before Laravel 8 the idea was achieved using Carbon::setTestNow(), a feature available in the Carbon\Carbon package, which also acts as the base for the Wormhole feature.

use Carbon\Carbon;

class WormHolingTest extends TestCase
{
    public function testSomethingNow()
    {
        Carbon::setTestNow(Carbon::parse('2022-12-22 00:00:00'));
        //do something supposed to performed on 2022-12-22 00:00:00
    }
}

But the code can be made more understandable using time travel features like Wormhole class and InteractsWithTime trait.

Let's see how it helps on saving time cost for developers on testing.

InteactsWithTime trait

To start with, Laravel 8 has the InteractsWithTime trait on the namespace lluminate\Foundation\Testing\Concerns*.* Don't confuse it with the one related to Illuminate\Support and others.

We can simply use it in test classes like below

use Illuminate\Foundation\Testing\Concerns\InteractsWithTime;

class WormHolingTest extends TestCase
{
    use InteractsWithTime;
}

We get access to various utility methods once the trait is on use.

//Carbon::now() will return the date in the future 10 days from today
$this->travel(10)->days(); 
//Carbon::now() will return the time in the future 10 minutes from now
$this->travel(10)->minutes(); 
//Carbon::now() will return the time in the past 5 hours from now
$this->travel(-5)->hours(); 
// Carbon::now() will return '2019-02-14 12:00:00'
$this->travelTo('2023-01-01 12:00:00');

We always need to go/come back to present so that we are not stuck in a time loop. To do that we can call the "travelBack" method or use the callback function to return on task completion.

We can explicitly travel back to the present with the travelBack() method.

$this->travel(7)->days() // travels to after 7 days in future
//perform your task within the interval
$this->travelBack(); // return to today and Carbon::now() will return current date

Using the callback function we can implicitly travel back to the current time.

$this->travel(9)->days(function () {
    //do something on 9th day from today

    //return back to today on task completion
});

Wormhole class

Or, we can use the class to travel as an alternative to traits usage. Making Wormhole class object and passing an integer value on instantiation and chaining the methods with it to time travel.

use Illuminate\Foundation\Testing\Wormhole;
class WormHoling extends TestCase
{
    public function testSomething(){
        $wormhole = new Wormhole(1);
        $wormhole->days(); 
        // Carbon::now() will return the time of tommorow
        Wormhole::back(); // brings the traveler back to current time
    }
}

Similarly to trait, we can pass the callback function to implicitly travel back once the purpose for travel is achieved.

$wormhole = new Wormhole(1);
$wormhole->days(function () {
    //traveler can experience tommorow and come back to present
});

Conclusion

To conclude, Wormhole conceptual class and trait are introduced to mitigate the effort of manual involvement to test the time-dependent functionality like changing system time manually only to test something on expected time. Though the focus is on testing, it can be used in other use cases like prediction, stock analysis and so on.

Resources

Wormhole documentation

Wormhole laracast tutorial