功能测试移动设备的条件页面内容呈现

时间:2013-10-20 23:16:43

标签: ruby-on-rails mobile rspec capybara poltergeist

我正在使用Rails项目中的Mobvious gem来确定用于访问页面的设备类型。我遇到问题的用户故事是:

  • 移动设备上的用户位于网站的移动版本
  • 移动用户点击“访问完整网站”按钮,将其带到桌面网站
  • 会话中加入desktop值,以确保记录他们在移动设备上查看桌面版网站的偏好(当移动用户首次访问移动设备上的主页时,他们会自动重新访问指向移动网站)
  • 在桌面网站主页上,移动设备用户可以看到“切换到移动网站”横幅以便他们这样做(桌面用户显然从未看过此横幅)

使用Mobvious实现条件渲染的代码很简单:

应用/视图/欢迎/ index.html.haml

- for_device_type :mobile do
  .switch-to-mobile-site-banner
    # code for banner

代码本身按预期工作:问题是我想为此编写RSpec feature test,但我想我似乎无法在RSpec功能测试场景中正确模拟移动用户代理无法直接访问 request 对象。我的理由是,在我测试页面上是否存在特定内容时,功能规范比request spec更合适。

到目前为止,从helper specs of the Mobvious gem获取提示,我在我的功能规范中删除了一个request对象,根据需要将device_type设置为:mobile,但是我似乎无法将.switch-to-mobile-site-banner中的内容显示为:

规格/特征/ mobile_navigation_features_spec.rb

feature 'Switch to mobile site banner' do
  include Mobvious::Rails::Helper

  given(:env) { double('env') }
  given(:request) { double('request') }

  background do
    allow(env).to receive(:[]).with('mobvious.device_type').and_return(:mobile)
    allow(request).to receive(:env).and_return(env)
  end

  scenario 'mobile user prefers using the desktop site' do
    visit root_url(desktop: 1)
    puts "Device type is #{device_type}" # => correctly returns :mobile
    expect(page).to have_selector('.switch-to-mobile-site-banner') # fails
  end
end

期望失败,并使用save_and_open_page查看页面上的呈现显示没有横幅,我不知道为什么。当代码通过Mobvious'for_device_type方法运行时,我似乎没有得到任何错误,所以我想也许我在request对象模拟(?)中缺少某些东西。 / p>

我没有专门针对任何实现/测试类型,因此我对如何测试我想要的功能有任何其他想法。我最初认为rack_session_access gem可以提供帮助,但除非我使用它错了,否则我无法用它做我想做的事。

澄清:我正在使用Poltergeist作为Capybara的javascript驱动程序。

使用解决方案更新

我认为真正让我误解的是,在mobvious-rails宝石中,当你想要获得device_type时,它calls the request object directly并且我想我需要嘲笑这个为了让助手在我的规格中正常工作。正如答案中所指出的那样,高级功能规范中的这种低级别模拟是一种代码(spec?)气味,事后我应该听到代码实际告诉我我做错了。此外,出于某种原因,在这种情况下添加js: true甚至没有在我脑海中浮现,无论是否在我的其他测试中使用它。

我最终使用Billy ChanKaleidoscope的答案部分来制定我喜欢的解决方案更简单,更清洁:

规格/特征/ mobile_navigation_features_spec.rb

feature 'Switch to mobile site banner' do
  background do
    page.driver.headers = { "User-Agent" => "mobile" }
  end

  scenario 'mobile user prefers using the desktop site', js: true do
    visit root_path(desktop: 1)
    expect(page).to have_selector('.switch-to-mobile-site-banner')
  end
end

由于Kaleidoscope是第一个提出一系列工作规格的人,我大部分时间都在考虑他,但是我会接受Billy Chan的答案是正确的,因为我觉得它是一个更“规范”的解决方案,我将指导其他人在将来参考。

2 个答案:

答案 0 :(得分:4)

首先,您需要在此功能中启用Javascript,因为移动检测是通过此gem中的Javascript以及许多其他类似解决方案完成的。

feature 'Switch to mobile site banner', js: true do

更新:根据Andrey的评论,Mobivious不会使用JS来检测移动设备,所以你不需要启用JS。

其次,我建议你尽可能在集成测试中使用低级模拟。您需要做的是完全像移动用户一样,看看他将体验什么。你甚至不需要低水平的Mobvious助手。

我四处搜寻,发现这颗宝石可能有所帮助:https://github.com/mururu/capybara-user_agent

虽然我之前没有使用过那个宝石,但语法看起来很简单

feature 'Switch to mobile site banner', js: true do

  background do
    set_user_agent(:iphone)
  end

  scenario 'mobile user prefers using the desktop site' do
    visit root_url(desktop: 1)
    expect(page).to have_selector('.switch-to-mobile-site-banner')
  end
end

OP评论的补充答案

  1. 关于到达'example.com'。修复方法是在root_path行使用root_url代替visit。建议您删除对域设置的依赖。

  2. 关于用户代理设置。我检查了宝石,语法与Poltergeist可以做的不同。所以,尽量不要使用gem而是根据Poltergeist的问题设置标题

    page.driver.headers = {"User-Agent:" => "iphone"} 
    

    参考:https://github.com/jonleighton/poltergeist/issues/127

    如果这仍然不起作用,您可以在此测试中暂时使用Webkit。毕竟他们都是无头司机。我总是安装这两个宝石,并使用Poltergeist作为主要宝石。安装宝石后,只需将其设置如下。

    在测试中

    require 'spec_helper'
    require 'capybara-webkit'
    
    feature 'Switch to mobile site banner', js: true do
      capybara.javascript_driver = :webkit
    

答案 1 :(得分:2)

在你的规范中启用js并且在你请求你正在指定的页面之前立即坚持这个(它只需要在你关心的请求之前去,但是先试试这个):

page.driver.headers = { "User-Agent" => "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9A334 Safari/7534.48.3" }

更新:这是我工作规范的代码:

root标记:

<% for_device_type :mobile do %>
  HAHA LOL MOBILE
<% end %>

规格:

require 'spec_helper'

feature 'Switch to mobile site banner' do
  scenario 'desktop content', js: true do
    visit "/"
    expect(page).to_not have_content('LOL')
  end

  scenario 'mobile content', js: true do
    page.driver.headers = { "User-Agent" => "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9A334 Safari/7534.48.3" }
    visit "/"
    expect(page).to have_content('LOL')
  end
end

更新2 至于为什么你的原始规格不起作用,你实际上并没有嘲笑env afaik。如果功能规格允许您轻松访问env或请求对象,我会感到惊讶。您应该使用浏览器的POV工作,因此设置用户代理似乎是要走的路。