使用 Capybara 和 Cucumber 测试 Rails Shopify 应用程序(在测试中升级 Shopify 计划会导致身份验证错误)
Testing Rails Shopify App with Capybara & Cucumber (upgrading Shopify plan in test causes authentication error)
我有一个 Shopify Rails 应用程序,我正在尝试测试我的 "pro" 计划的一些功能,但在更新测试商店计划时遇到问题。我可以登录没问题,但是当我尝试通过水豚更新我的商店计划时,我被重定向到登录页面。
我已经做了一些故障排除,但我真的不知道这个问题是从哪里产生的,因为当我在浏览器中手动尝试时它工作正常。也许 database_cleaner 或缓存问题?
这是我的黄瓜步骤(基本上只是登录应用程序,选择一个计划):
Background:
Given I am a logged in user
When I am on the pro plan
水豚:
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
driver 成功验证进入应用程序,访问编辑计划页面,访问 Shopify "approve charge" 授权页面。但是在点击 "approve charge" 之后,浏览器被重定向到登录页面,而不是我期望的操作。
当我在自己的浏览器中手动尝试此操作时,我被重定向到正确的页面。
这是用户更新计划时的实际控制器操作:
第 1 步。用户从设置页面选择计划 - 发布到此操作,这会将用户重定向到具有嵌入式 JS 的页面,该页面将用户重定向到 Shopify 身份验证页面(必须以这种方式完成以逃避嵌入式应用程序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
这里是 confirm_plan 方法。基本上,这会创建一个新的 Shopify Charge object - Shopify 将以唯一的过期 URL 响应,供用户确认收费。我们需要提供价格、名称和 return_url 以便 Shopify 在他们批准收费后重定向用户:
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
当我窥探它时,我可以看到 return_url 设置到正确的位置:http://localhost:23456/shop/plans/update_plan_step_2
(shops#update_plan_step_2).
用户在 Shopify 身份验证页面上批准收费后,他们应该被重定向到此操作:
def update_plan_step_2
#some code to update our shop record
end
但是当我窥探这个动作时,我可以看到它甚至没有在测试中被调用,所以我知道问题发生在这之前。
总而言之,看起来一切正常,直到用户应该被重定向到 http://localhost:23456/shop/plans/update_plan_step_2
。相反,他们被重定向到身份验证页面。
为什么在测试中会出现这种情况,而当我尝试手动进行时却不会出现这种情况?关于问题所在的任何想法?
日志:
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
所以我们可以看到用户被重定向到身份验证。为什么这只会在测试中发生?商店 session 未存储在测试中是否可能是缓存问题? session 当用户离开应用程序到 Shopify 身份验证页面时被销毁?
编辑:我确切地知道它被重定向到哪里(在控制器的一个之前的动作中)
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
这意味着用户通过 Shopify 进行身份验证后,shopify_session 不再存在。
Capybara.default_host
默认为 127.0.0.1,这意味着对您的应用程序的所有访问都发生在 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 为主机名 127.0.0.1 存储的会话 cookie 对主机名 localhost 无效,因此应用程序重定向登录。要么将您的 return_url 更改为使用 127.0.0.1 的主机名,要么将 Capybara.default_host
更改为 'localhost'(使用 'localhost' 作为 default_host 在使用 selenium 时有一些小陷阱不过,最好更改 return_url)
我有一个 Shopify Rails 应用程序,我正在尝试测试我的 "pro" 计划的一些功能,但在更新测试商店计划时遇到问题。我可以登录没问题,但是当我尝试通过水豚更新我的商店计划时,我被重定向到登录页面。
我已经做了一些故障排除,但我真的不知道这个问题是从哪里产生的,因为当我在浏览器中手动尝试时它工作正常。也许 database_cleaner 或缓存问题?
这是我的黄瓜步骤(基本上只是登录应用程序,选择一个计划):
Background:
Given I am a logged in user
When I am on the pro plan
水豚:
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
driver 成功验证进入应用程序,访问编辑计划页面,访问 Shopify "approve charge" 授权页面。但是在点击 "approve charge" 之后,浏览器被重定向到登录页面,而不是我期望的操作。
当我在自己的浏览器中手动尝试此操作时,我被重定向到正确的页面。
这是用户更新计划时的实际控制器操作:
第 1 步。用户从设置页面选择计划 - 发布到此操作,这会将用户重定向到具有嵌入式 JS 的页面,该页面将用户重定向到 Shopify 身份验证页面(必须以这种方式完成以逃避嵌入式应用程序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
这里是 confirm_plan 方法。基本上,这会创建一个新的 Shopify Charge object - Shopify 将以唯一的过期 URL 响应,供用户确认收费。我们需要提供价格、名称和 return_url 以便 Shopify 在他们批准收费后重定向用户:
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
当我窥探它时,我可以看到 return_url 设置到正确的位置:http://localhost:23456/shop/plans/update_plan_step_2
(shops#update_plan_step_2).
用户在 Shopify 身份验证页面上批准收费后,他们应该被重定向到此操作:
def update_plan_step_2
#some code to update our shop record
end
但是当我窥探这个动作时,我可以看到它甚至没有在测试中被调用,所以我知道问题发生在这之前。
总而言之,看起来一切正常,直到用户应该被重定向到 http://localhost:23456/shop/plans/update_plan_step_2
。相反,他们被重定向到身份验证页面。
为什么在测试中会出现这种情况,而当我尝试手动进行时却不会出现这种情况?关于问题所在的任何想法?
日志:
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
所以我们可以看到用户被重定向到身份验证。为什么这只会在测试中发生?商店 session 未存储在测试中是否可能是缓存问题? session 当用户离开应用程序到 Shopify 身份验证页面时被销毁?
编辑:我确切地知道它被重定向到哪里(在控制器的一个之前的动作中)
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
这意味着用户通过 Shopify 进行身份验证后,shopify_session 不再存在。
Capybara.default_host
默认为 127.0.0.1,这意味着对您的应用程序的所有访问都发生在 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 为主机名 127.0.0.1 存储的会话 cookie 对主机名 localhost 无效,因此应用程序重定向登录。要么将您的 return_url 更改为使用 127.0.0.1 的主机名,要么将 Capybara.default_host
更改为 'localhost'(使用 'localhost' 作为 default_host 在使用 selenium 时有一些小陷阱不过,最好更改 return_url)