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:
- Spreedly set up
- Creating a Subscriber
- Comping a Subscriber
- 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.
Comments
Great write up! Learned a lot.
Thanks posting these specific types of cucumber tests. They are gold!