4
votes

I have a Shopify Rails app and I am trying to test some of the functionality of my "pro" plan, but having trouble updating the test shop plan. I can login no problem, but when I try to update my shops plan via capybara, I get redirected to the login page.

I've done some troubleshooting, but I really have no idea where this issue is stemming from because it works fine when I try it manually in my browser. Maybe database_cleaner or caching issue?

Here's my cucumber steps (basically just login to the app, choose a plan):

Background:
    Given I am a logged in user
    When I am on the pro plan

Capybara:

When "I am a logged in user" do
  step "I visit the login page"
  step "I supply my shopify url"
  step "I get taken to the app index page"
end

When /^I am on the (.+) plan$/ do |plan|
  click_link_or_button "Settings & Notifications"
  click_link_or_button "edit plan"
  choose("shop_plan_#{plan}")
  click_link_or_button "Update Plan"
  click_link_or_button "Approve charge"
end

The driver successfully authenticates into the app, visits the edit plan page, visits the Shopify "approve charge" authorization page. But after clicking "approve charge", the browser is redirected to the login page instead of the action I am expecting.

When I try this manually in my own browser, I am redirected to the correct page.

Here's the actual controller action when a user updates their plan:

Step 1. User selects plan from settings page - posts to this action, which will redirect user to a page with embedded JS which redirects user to a Shopify authentication page (has to be done this way to escape the embedded app iframe).

def update_plan_step_1
    @plan = shop_params[:plan]
    redirect_url = current_shop.confirm_plan(@plan)
    gon.authorization_url = redirect_url
    render :redirect_to_shopify_auth
end

And here is the confirm_plan method. Basically this creates a new Shopify Charge object - Shopify is going to respond with a unique expiring URL for the user to confirm the charge. We need to provide the price, name, and return_url for Shopify to redirect the user after they approve the charge:

def confirm_plan(shopify_plan)
    price = Plan.cost(shopify_plan)
    name = shopify_plan + "Plan"
    return_url = update_plan_step_2_url(:host => Figaro.env.root_uri)
    response = ShopifyAPI::RecurringApplicationCharge.create({
                              :name => name, 
                              :price => price, 
                              :return_url => return_url, 
                              :test=> !Rails.env.production? 
                              })
     response.confirmation_url
 end 

When I pry into this, I can see the return_url is set to the proper location: http://localhost:23456/shop/plans/update_plan_step_2 (shops#update_plan_step_2).

After user approves the charge on Shopify authentication page, they are supposed to be redirected to this action:

def update_plan_step_2
    #some code to update our shop record
end

But when I pry into this action, I can see that it's not even being called in the Test, so I know the issue is happening before this.

To summarize, it looks like everything is working until the user is supposed to be redirected to http://localhost:23456/shop/plans/update_plan_step_2. Instead, they are redirected to the authentication page.

Why would this happen in the test, but not when I try doing it manually? Any ideas on where the issue lies?

Logs:

Started GET "/shop/plans/update_plan_step_2?charge_id=12345" for 127.0.0.1 at 2015-10-30 11:09:58 -0700
Processing by ShopsController#update_plan_step_2 as HTML
Parameters: {"charge_id"=>"12345"}
Redirected to http://localhost:23456/login

So we can see user is being redirected to authenticate. Why would this be happening only in test? Could it be a caching issue where the shop session is not being stored in the test? And the session is destroyed when the user is taken off the app to the Shopify authentication page?

EDIT: I know exactly where it's being redirected (in an before action in the controller)

def shopify_session
      if shop_session
        begin
          ShopifyAPI::Base.activate_session(shop_session)
          yield
        ensure
          ShopifyAPI::Base.clear_session
        end
      else
        redirect_to_login  ## REDIRECTED HERE
      end
    end

Which means after user authenticates via Shopify, the shopify_session no longer exists.

1
What driver are you using in Capybara?Thomas Walpole
Hi @TomWalpole, sorry for the late response. Here is my config: Capybara.register_driver :chrome do |app| Capybara::Selenium::Driver.new(app, :browser => :chrome) end Capybara.javascript_driver = :chromeJackson Cunningham
are your scenarios tagged with @javascript?Thomas Walpole
I have the tag at the top of my feature: @javascript Feature: User adds a customerJackson Cunningham
I thought that was a DRY way to do it, but does it need to be above each scenario?Jackson Cunningham

1 Answers

2
votes

Capybara.default_host defaults to 127.0.0.1 which means that all access to your app occurs over http://127.0.0.1/some/path by default when visiting paths in your app with Capybara. When your app redirects to http://localhost/some/path the session cookies stored for the hostname 127.0.0.1 are not valid for hostname localhost so the app redirects to login. Either change your return_url to use a hostname of 127.0.0.1 or change Capybara.default_host to 'localhost' (using 'localhost' for default_host has a few small gotchas when using selenium though, so better to change the return_url)