Spreedly Integration Testing with Cucumber

We recently set up Spreedly for managing subscriptions on a client project. I just want to chronicle a few the steps that we took along the way integrating Spreedly and testing it with Cucumber.

Let’s walk through the following steps:

  1. Spreedly set up
  2. Creating a Subscriber
  3. Comping a Subscriber
  4. User sign up and redirect to Spreedly subscription url

First things first, install the spreedly gem and get your env.rb in order.

Gemfile

gem 'spreedly', '1.3.4', :require => false

The :require => false is important because we’re going to require different files depending on the environment.

config/initializers/spreedly.rb

if Rails.env.test?
  require 'spreedly/mock'
else
  require 'spreedly'
end

Spreedly.configure('site short name', 'crazy hash token')

Now that the initializer is set up, let’s move our attention to env.rb. We’re going to tag the Spreedly stories so that we can wipe the subscribers and make sure we have a clean slate before we run the features.

Also, Spreedly has a couple mock plans defined, but I want our tests to reflect the data we have set up on our account. So, override the mock plans with our plan data from Spreedly! Ugly. But it works, and now we’re speaking our clients language in terms of which plan the subscriber will be on.

env.rb

Before('@spreedly') do
  Spreedly::Subscriber.wipe!
end

module Spreedly
  class Spreedly::SubscriptionPlan
    def self.plans
     @plans || = {
        1 => new(
          :id => 1, 
          :name => 'Free Plan', 
          :plan_type => 'free_trial', 
          :duration_quantity => 0, 
          :duration_units => 'months', 
          :feature_level => 'free', 
          :terms => 'Lifetime', 
          :price => '0.0'
        ),
        2 => new(
          :id => 2, 
          :name => 'Basic Plan Monthly', 
          :plan_type => 'regular', 
          :duration_quantity => 0, 
          :duration_units => 'months', 
          :feature_level => 'basic', 
          :terms => '1 month', 
          :price => '15.00'
        ),
        3 => new(
          :id => 3, 
          :name => 'Premium Plan Monthly', 
          :plan_type => 'regular', 
          :duration_quantity => 0, 
          :duration_units => 'months', 
          :feature_level => 'premium', 
          :terms => '1 month', 
          :price => '30.00'
        )
      }
    end
  end
end

At some point, you might have an admin that needs to manage customers in the app. In our case, we wanted an admin to be able to create a new subscriber and give that new subscriber a complimentary subscription.

Creating a Subscriber

@spreedly
Scenario: An admin creating a customer
  Given I am an admin signed in as "admin@example.com/password"
  When I follow "New Customer"
  And I fill in "First name" with "Brian"
  And I fill in "Last name" with "Ryckbost"
  And I fill in "Email address" with "brian@collectiveidea.com"
  And I fill in "Password" with "password"
  And I fill in "Password confirmation" with "password"
  And I press "Save Customer"

  Then "brian@collectiveidea.com" should be a subscriber
 

Then '"$email" should be a subscriber' do |email|
  user = User.find_by_email!(email)

  sp_user = Spreedly::Subscriber.find(user.id)
  sp_user.active.should be_false
  sp_user.email.should == email
end

Our Then step is testing an inactive spreedly subscriber was created. Pretty simple. Next!

Comping a subscriber

Note: this feature is a bit more involved.

@spreedly
Scenario: An admin comping a newly created provider
  Given the following plans exist:
    | level |
    | free  |
    | basic |
  And the following providers exist:
    | company name           | user                     | active | plan |
    | Brian's House of Cards | email: brian@example.com | false  | nil  |
  And "brian@example.com" is a subscriber
  And I am an admin signed in as "admin@example.com/password"

  When I follow "All Customers"
  And I follow "Brian's House of Cards"
  And I follow "Comp a subscription"
  And I choose "Basic"
  And I fill in "Quantity" with "3"
  And I press "Comp Customer"
  And "brian@example.com" gets refreshed from spreedly

  Then "brian@example.com" should have a "Basic" subscription for "3" months

We can’t use a factory for the subscriber, so we create a subscriber through a custom step.

Given '"$email" is a subscriber' do |email|
  user = User.find_by_email!(email)
  Spreedly::Subscriber.create!(user.id, user.email, nil,
    :billing_first_name => user.first_name,
    :billing_last_name => user.last_name
  )
end

You might be wonder what the ‘gets refreshed from spreedly’ step is all about. You can read all about it in Spreedly’s integration guide. It’s an aspect of listening for changes to your users. If the Spreedly subscriber exists, it’ll find it and set some attributes.

When '"$email" gets refreshed from spreedly' do |email|
  user = User.find_by_email(email)
  user.refresh_from_spreedly
end

user.rb

def refresh_from_spreedly
  subscriber = Spreedly::Subscriber.find(self.id)
  if subscriber
    update_attributes :active         => subscriber.active,
                      :spreedly_token => subscriber.token,
                      :plan           => Plan.find_by_level(subscriber.feature_level)
  else
    update_attributes :active => false
  end
end

Then '"$email" should have a "$level" subscription for "$quantity" months' do |email, level, quantity|
  user = User.find_by_email!(email)

  sp_user = Spreedly::Subscriber.find(user.id)
  sp_user.feature_level.should == level.downcase
  sp_user.active.should be_true
  sp_user.active_until.should be_close(quantity.to_i.months.from_now, 3.days)
end

The above step is fairly self explanatory, but let me provide some extra clarification. It finds the subscription and checks that it has the correct feature_level (based on the plans in env.rb), the user is active, and the user has a complimentary subscription that is active for roughly the same amount of time that’s listed in the test.

That should take care of the admin-centric cases. But what about the front-facing user sign-up side of the equation?

Lets take a look!

Now, you could do this two ways. 1.) Show a sign up form for the user, then show a subscribe link for each plan or 2.) show a link that takes you to the sign up form and redirect the user to the appropriate subscribe link on save. The latter is described below.

User sign up and redirect to Spreedly subscription url

Scenario: A customer signing up and subscribing to a paid plan
  Given I am not authenticated
  And the following plans exist:
    | level   |
    | free    |
    | basic   |
    | premium |
  When I go to the home page
  And I follow "Plans"
  And I follow "Join" within "#premium"
  And I fill in "First name" with "Brian"
  And I fill in "Last name" with "Ryckbost"
  And I fill in "Email" with "brian@collectiveidea.com"
  And I fill in "Password" with "testing"
  And I fill in "Password confirmation" with "testing"
  And I check "I agree to the Terms and Conditions"
  And I choose "Monthly"
  And I press "Register"

  And "brian@collectiveidea.com" pays for a premium plan with a credit card

  When I follow "Dashboard"
  And I follow "My Account"
  Then I should see "You are currently on the Premium plan"

We have to do a little magic to make it look like the user left our site, successfully paid on Spreedly and was then redirected back. We do that by stubbing what’s returned from our refresh_from_spreedly method you saw earlier.

When /^"([^"]*)" pays for a ([^"]*) plan with a credit card$/ do |email, plan|
  user = User.find_by_email(email)

  # stub what's being returned
  Spreedly::Subscriber.stub(:find).with(user.id).and_return(OpenStruct.new(:active => true, :token => '123xyz', :feature_level => plan))

  user.refresh_from_spreedly
  visit thank_you_url
end

And that, ladies and gentlemen, is how we have tested our Spreedly integration with Cucumber. It seems like a lot to take in, but when you take it step by step, you’ll see the pieces come together.

bryckbost@gmail.com

Comments

  1. December 07, 2010 at 9:50 AM

    Great write up! Learned a lot.

  2. twmills@gmail.com
    Theo Mills
    December 07, 2010 at 10:09 AM

    Thanks posting these specific types of cucumber tests. They are gold!