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 . 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 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 like me to understand. Strava API Strava Strava programmer 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. Strava Authentication Flow The the flow very well: API docs outline Redirect user to the Strava authentication URL to sign-in and view the authorization page. A few parameters are passed in the URL to identify the app and give Strava a url to redirect back to. If the user authorizes the app, then Strava uses the provided url to redirect back to the app and passes a code as a parameter. If the user cancels the authorization they are still redirected back to the app, but are not given a code. The app must then take that code, along with the app ID and app secret token, then send it back to Strava. If the code, app ID and app secret token are all valid, then Strava returns a user authentication token along with the user’s basic profile. My app then saves the user authentication token as well as the Strava profile ID in the user profile. Test Environment Setup 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: — Creates the API calls for me and manages the additional params I need to pass to the API Faraday — Parses the JSON responses from the API into OpenStruct objects to allow the response to be access with basic Ruby instance methods JSON — Command line debugging tool (default to rails) Byebug — RSpec Testing Framework for Rails RSpec-Rails —Feature testing tool that allows me to interact with my site like a user would Capybara — For debugging allows me to use ‘save_and_open_page’ which lets me see what Capybara sees Launchy — Let’s me reset my database for each test condition Database_Cleaner — Cool gem that allows capybara to visit foreign pages outside my app Capybara-Mechanize 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 and gems need a little bit of configuration in order to work correctly, so inside of my file I’ve added these lines: database_cleaner capybara-mechanize rails_helper.rb Test Script Setup 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. Lines 1–3: 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. Lines 4–9: Creates a basic user profile and mock as this profile, nothing too special here. Note that I’m using instead of . This way I get an error message if the fails. current_user create! create create Lines 11–15: Go to this user’s show page and expect to see a link to . This is step 1 in the Strava Authentication Flow. Additionally, I’m demonstrating that the user does not have a or . These verifications could also belong in the user model test, but I put them here just to make sure everything is working as expected. “Add Strava to Account” strava_athlete_id strava_access_token Line 17–18: Click link to . This will send me to . 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. “Add Strava to Account” https://www.strava.com/oauth/token I can use Launchy here to see what Capybara sees after clicking by inserting ‘ ’ 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. ‘Add Strava to Account’ save_and_open_page Lines 19–22: 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 STRAVA_TEST_ENVIRONMENT_EMAIL=test@email.comexport STRAVA_TEST_ENVIRONMENT_PASSWORD=12345 Line 24: 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. Lines 26–29: 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 & saved. One thing to note here, I was originally calling instead of and my test was failing even though the user was getting it’s credentials saved. Turns out, 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. strava_athlete_id strava_access_token user.strava_athlete_id User.find(user.id).strava_athlete_id user Conclusion 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.