This blog post is a continuation. Here is part I of testing Stripe with codeception.
For our Stripe setup needs I created a utility class TestStripeCommons, which each test that requires a Stripe setup can call specific static methods. Alternatively you could add them to Codeception’s generated suite helper via Codeception’s build command.
The first scenario we encountered was needing a Stripe account to have a subscription to a specific plan. So in TestStripeCommons I created the following method:
/** * Delete all subscriptions, cards, and discounts from Stripe associated with the $accountId * * @param $accountId - the PK of the account record in our database. */ public static function refreshSubscriptions( $accountId ) { $account = \Account::find( $accountId ); if ( $account->stripe_id ) { $customer = \Stripe_Customer::retrieve( $account->stripe_id ); self::clearCardsAndSubscriptionsFromStripe( $customer ); self::clearCustomerDiscount( $customer ); } self::clearSubscriptionsFromLocalDb( $account ); self::subscribe( $account ); } /** * Delete all subscriptions and cards from Stripe for $customer * * @param $customer */ private static function clearCardsAndSubscriptionsFromStripe(\Stripe_Customer $customer) { $subs = $customer->subscriptions->all()->__toArray()['data']; foreach ($subs as $sub) { $customer->subscriptions->retrieve($sub->id)->cancel(); } $cards = $customer->cards->all()->__toArray()['data']; foreach ($cards as $card) { $customer->cards->retrieve($card->id)->delete(); } } /** * Delete all discounts from Stripe associated with $customer * * @param \Stripe_Customer $customer */ private static function clearCustomerDiscount(\Stripe_Customer $customer) { if (!is_null($customer->discount)) { $customer->deleteDiscount(); } }
The code:
- Gets the account object for the parameter $accountId
- Verifies account has a Stripe ID
- If it does, it retrieves the Stripe_Customer object from Stripe
- Calls
clearCardsAndSubscriptionsFrom Stripe: - Retrieve all the subscriptions from Stripe associated with $customer
- Cancel each retrieved subscription
- Retrieve all the cards from Stripe associated with $customer
- Delete each retrieved card
- Calls clearCustomerDiscount:
- If $customer has a discount, delete it
- Calls
clearSubscriptionsFromLocalDb, which simply sets $account in our database in a state where it does not have a Stripe subscription - Calls subscribe, which creates a subscription in Stripe. (I’ll go into more detail below because it gets a little complex.)
\commons\TestStripeCommons::refreshSubscriptions($accountId);
Back to TestStripeCommons::subscribe($
** * Create Stripe subscription for $account * * @param \Account $account */ public static function subscribe(\Account $account) { if (!$account->stripe_id) { \Illuminate\Support\Facades\Log::error('Cannot create subscription for Account Id: ' . $account->id . ', since it has no stripe_id'); return; } $cardData = [ 'number' => '4242424242424242', 'name' => 'Bob Test', 'exp_month' => '12', 'exp_year' => \Carbon\Carbon::today()->addYears(2)->year, 'cvc' => '234', ]; if ($account->hasDiscount()) { $account->planSubscription()->withCoupon($account->named_discount_id) ->create($cardData , ['metadata' => ['accountId' => $account->id]] , \Stripe_Customer::retrieve($account->stripe_id) ); } else { $account->planSubscription()->create($cardData , ['metadata' => ['accountId' => $account->id]] , \Stripe_Customer::retrieve($account->stripe_id) ); } }
The code:
- Verifies account has a Stripe ID
- Create an array with credit card info
- Our account class has a method to determine if it should get a discount
- Create the subscription in Stripe
In future posts I will show you how I handled other scenarios and coupons.