Code Shopify About

Shopify App and Theme Development tutorials for those who are familiar with code and want to dive into Shopify.

Sign up for Shopify

Testing Shopify Authenticated Controllers with RSPEC (Rails)

Monday, Mar 18, 2019

Now we all know that testing is a very important part of the development process 💯. Sometimes, however, roadblocks 🛑 come up that lower your resolve.

This is why in this post, we'll teach you how to test your Authenticated Controllers with RSPEC when created a Shopify App.

This tutorial assumes that you've created your app with Rails and the Shopify Gem and the RSPEC Gem for testing. If you want to learn how to make an embedded app with Rails checkout our post here.

RSPEC is now recommending using the Request specs rather than the controller specs, but this tutorial should be relevant either way.

The Gems We Use

You'll want to install the following gems - if you setup RSPEC at the beginning, when you scaffold the test files will be created for you as well.


  group :development, :test do
    gem 'rspec-rails'
    gem 'factory_bot_rails'
  end
RSPEC is for testing and FactoryBot helps to create records.

The Files We'll Touch

1. The factories for our products and shops

  # spec/factories/products.rb

    FactoryBot.define do
      factory :product do
        shopify_id { "MyString" }
        shopify_product_type { "MyString" }
        shopify_title { "MyString" }
        shopify_available_for_sale { true }
        shopify_image_url { "MyString" }
        shop_id {nil}
      end
    end

  # spec/factories/shop.rb

  FactoryBot.define do
    factory :shop do
      shopify_domain {'example.myshopify.com'}
      shopify_token {"451a2b3er28e07d89iy3df0"}
      shopify_currency_code {nil}
      shopify_money_format {nil}
      currency_code {"USD"}
      language {"en"}
      notifications {false}
    end
  end
2. The Product spec file

  # spec/requests/products_spec.rb

    require 'rails_helper'

    RSpec.describe "Products", type: :request do

      describe "GET /products" do
        it "Products return with a HTTP status 200" do
          get products_path
          expect(response).to have_http_status(200)
        end
     end
  end

Now, as is, this test won't pass. When I run it, I get a http status of 302, meaning that a redirection happened. This makes sense, as at this point, in the browser you'd be redirected to a login page to authenticate your store. However, in test, we obviously don't have a store.

Authenticating The Shop

What we're gonna need to do is essentially fake a login to the shop prior to running the test. We do this by adding a function that mocks a login. For this we create a login function that takes a shop


# spec/requests/products_spec.rb

  require 'rails_helper'

  RSpec.describe "Products", type: :request do

    def login(shop)
      OmniAuth.config.test_mode = true
      OmniAuth.config.add_mock(:shopify,
      provider: 'shopify',
      uid: shop.shopify_domain,
      credentials: { token: shop.shopify_token })
      Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:shopify]
			    
      get "/auth/shopify"
      follow_redirect!
    end

    describe "GET /products" do
      it "Products return with a HTTP status 200" do
        get products_path
        expect(response).to have_http_status(200)
      end
    end
  end

Next we'll need to create a shop and then pass that shop into the login function we just create.


  # spec/requests/products_spec.rb

    require 'rails_helper'

    RSpec.describe "Products", type: :request do

      def login(shop)
      OmniAuth.config.test_mode = true
      OmniAuth.config.add_mock(:shopify,
      provider: 'shopify',
      uid: shop.shopify_domain,
      credentials: { token: shop.shopify_token })
      Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:shopify]
          
      get "/auth/shopify"
      follow_redirect!
   end

     describe "GET /products" do
       it "Products return with a HTTP status 200" do
         shop = FactoryBot.create(:shop)
         login(shop)
         @request.session[:shopify] = shop.id
         @request.session[:shopify_domain] = shop.shopify_domain
         get products_path
         expect(response).to have_http_status(200)
      end
    end
  end

You can see here that we've used FactoryBot to create a shop and then passed that shop into the login option. Next we set the @request session shopify field to the shop.id and the @request session shopify domain field to the shop.shopify_domain.

Now when we run the test, it passes 🙌

more posts