Search code examples
laravelstripe-paymentslaravel-cashier

Laravel Cashier - Unit Tests with creating subscriptions with payment methods


Looking deeper into this, I'm not sure it's even possible, which is a shame because I'm trying to learn TDD.

I would like to test my model with Billable being created and subscribed to a plan.

/** @test */
public function an_account_can_subscribe_to_a_plan() {
    $account = factory("App\Account")->create();

    Stripe::setApiKey('key');
    $paymentMethod = PaymentMethod::create([
        'type' => 'card',
        'card' => [
            'number' => '4242424242424242',
            'exp_month' => '2',
            'exp_year' => '2021',
            'cvc' => '314'
        ]
    ]);

    $subscription = $account->newSubscription('default', 'starter')->create($paymentMethod);
    $this->assertTrue( $subscription->valid() );  
}

The Laravel Cashier docs show how to send a token via Stripe.js, but that doesn't work for Unit Testing.

I've tried to include the Stripe library directly and create a PaymentMethod object, but this also requires me set an API key manually. Now the error I'm getting is that I have to verify my phone number to send raw credit card numbers to the stripe API.

I'm hoping there's a better way. How can I use Laravel Cashier in a TDD way and mock up fake subscriptions with fake payment methods?


Solution

  • Stripe provides not only test card numbers, but tokens and payment method's.

    https://stripe.com/docs/testing#cards

    Click the PaymentMethods tab. The value (for example pm_card_visa) can be used directly on the server-side in your tests without the need of front-end payment-intent implementation.

    This is an example of a feature test I have:

        /**
         * @test
         */
        public function a_user_can_subscribe_to_a_paid_plan()
        {
    
            $this->actingAs($this->user);
            $this->setUpBilling();
    
            $enterprise = Plan::where('name', 'Enterprise')->first()->stripe_plan_id;
    
            $response = $this->post(route('paywall.payment'), [
                'payment_method' => 'pm_card_visa',
                'stripe_plan_id' => $enterprise
            ])
            ->assertSessionDoesntHaveErrors()
            ->assertRedirect();
    
        }
    

    Your tests may vary, but you can make a normal request to your billing controller with these test payment methods and it goes through just as it would if you do it on the front-end.