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 🙌