This week I’m on a short break from school for the holidays and one of my goals for the week has been to get comfortable with the Strava API. Strava is my social media of choice and it also holds buckets of data for athletes, which makes it an interesting datasource to build an application off of. The best part about the Strava API is how good their documentation is. It is well organized, provides generic curl examples and describes the API interactions in a clear way that is easy for a beginner programmer like me to understand.
The first feature I wanted to build was to allow a user to create an account on my app, then allow them to authenticate that account with their own profile on Strava. Additionally, I needed to work out how to test this process. I had already messed around a little with using Faraday to access the API through my command-line, but the production app will need a full test suite. Before we get into testing let’s look at the Strava API authentication flow.
The API docs outline the flow very well:
Make sure the test environment database is setup (I’m using PostreSQL) and it is migrated. These are the gems I’m using to contact the API and run my test suite:
These all live inside my Gemfile. I have Faraday and JSON in the main gem list. Everything else is inside my development & test group:
The database_cleaner
and capybara-mechanize
gems need a little bit of configuration in order to work correctly, so inside of my rails_helper.rb
file I’ve added these lines:
At this point, my app allows a user to create a new account with their name, email and password. Additionally, users are required to be signed in to add Strava to their account and they can only add it from their personal user/show page. Let’s go through the test setup line by line to show how I’m doing things.
These are basic describe/context blocks except for line #3. Here I specify what driver I want Capybara to use. By default, Capybara uses the Rack driver, which doesn’t allow the test suite to access any outside domains. By including the capybara-mechanize gem I can now specify the driver to be mechanize, which does allow capybara to visit outside domains. This is useful, because the default driver works fine for most cases and I don’t know what kind of side affects using the mechanize driver would have on the rest of my test suite.
Creates a basic user profile and mock current_user
as this profile, nothing too special here. Note that I’m using create!
instead of create
. This way I get an error message if the create
fails.
Go to this user’s show page and expect to see a link to “Add Strava to Account”
. This is step 1 in the Strava Authentication Flow. Additionally, I’m demonstrating that the user does not have a strava_athlete_id
or strava_access_token
. These verifications could also belong in the user model test, but I put them here just to make sure everything is working as expected.
Click link to “Add Strava to Account”
. This will send me to https://www.strava.com/oauth/token. If I’m not using mechanize I get the error message below. Capybara ignores the protocol and domain, then expects a route to be present for /oauth/token.
I can use Launchy here to see what Capybara sees after clicking ‘Add Strava to Account’
by inserting ‘save_and_open_page
’ on line 18. Turns out I’m redirected to a login page for Strava. I need to login to my account in order for Capybara to go through the authorization process.
The Capybara methods still work on external websites and can interact with those pages. I inspected the login page to see how strava named the email and passwords fields. Next, I set environment variables in my terminal to store my email/password combo for my test environment. This is important because I don’t want to be posting my test environment credentials all over the internet when I’m posting here or on github. These can be set with an export command in the terminal.
export [email protected] STRAVA_TEST_ENVIRONMENT_PASSWORD=12345
After submitting the login credentials on line 22, I put another ‘save_and_open_page’ on line 23 to see where I’m redirected to (see page below). I see that I’m now at the authorize page, so I want Capybara to click ‘Authorize’. This is step 2 of the Strava Authentication Flow.
This is where my app does a little magic under the hood and performs steps 3–5 in the Strava Authentication Flow. The end result is that I expect to be redirected back to the user show page and for the user to now have their strava_athlete_id
& strava_access_token
saved. One thing to note here, I was originally calling user.strava_athlete_id
instead of User.find(user.id).strava_athlete_id
and my test was failing even though the user was getting it’s credentials saved. Turns out, user
was still associated with the state of user that I assigned it on line 4, so I needed to pull the user directly from the database.
This is probably the longest test script I’ve ever written, but that is expected when I’m testing a process with so much user interaction. If there are better ways to test this process let me know in the comments. Figuring out this test took me way longer than I’d like to admit, so if there is an easier way to do it I’d be all over that.