To mock the chain of method calls on the User model that uses the Billable trait, you need to mock the intermediate objects that are returned by each method in the chain. In this case, you need to mock the subscription builder that is returned by newSubscription(), and then mock the checkout() method on that builder.
Here's how you can do it using Mockery:
use Mockery;
use Laravel\Cashier\SubscriptionBuilder;
// Create a partial mock of the User model
$userMock = Mockery::mock(User::class)->makePartial();
// Mock the SubscriptionBuilder that is returned by newSubscription()
$subscriptionBuilderMock = Mockery::mock(SubscriptionBuilder::class);
// Define the chain of methods and their return values
$userMock->shouldReceive('newSubscription')
->with($name, $price)
->andReturn($subscriptionBuilderMock);
$subscriptionBuilderMock->shouldReceive('trialUntil')
->with(Mockery::type(Carbon\Carbon::class))
->andReturnSelf(); // Return the same builder to allow chaining
$subscriptionBuilderMock->shouldReceive('allowPromotionCodes')
->andReturnSelf(); // Return the same builder to allow chaining
// Mock the checkout method to return a fake response
$checkoutResponse = new stdClass;
$checkoutResponse->url = 'https://chicken.com';
$subscriptionBuilderMock->shouldReceive('checkout')
->with(Mockery::on(function ($argument) {
// Optionally, you can add checks to the argument here
return true;
}))
->andReturn($checkoutResponse);
// Now you can call the method chain on the user mock
$response = $userMock->newSubscription($name, $price)
->trialUntil(Carbon::now()->addDays(7)->addMinutes(1))
->allowPromotionCodes()
->checkout([
'success_url' => $successUrl,
'cancel_url' => $cancelUrl,
'consent_collection' => [
'terms_of_service' => 'required',
],
]);
// Assert that the response URL is the mocked one
$this->assertEquals('https://chicken.com', $response->url);
In this example, we're using andReturnSelf() to return the same mock object, allowing us to chain the method calls. When we reach the checkout() method, we return a fake response object with the URL we want to test against.
Remember to include the necessary use statements for any classes you're using in your test, and replace $name, $price, $successUrl, and $cancelUrl with the actual values you're using in your test.