4

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

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

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

app/views/welcome/index.html.haml

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

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

到目前为止,从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对象模拟中我缺少一些东西(?)。

我没有专门绑定到任何实现/测试类型,所以我对如何测试我想要的功能持开放态度。我最初认为rack_session_accessgem可以提供帮助,但除非我用错了,否则我不能用它来做我想做的事。

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

更新解决方案

我认为真正让我遇到这个问题的是,在mobvious-rails gem 中,当您想要获取 时device_type,它会直接调用该request对象,我想我需要对其进行模拟以使助手在我的规范中正常工作. 正如答案中所指出的那样,高级功能规范中的这种低级模拟是一种代码(规范?)气味,事后看来,我应该听过代码实际上告诉我我做错了。此外,出于某种原因,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 的回答是正确的,因为我认为这是一个更“规范的解决方案,我将指导其他人在未来参考。

4

2 回答 2

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

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

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_urlvisit

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

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

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

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

    在测试中

    require 'spec_helper'
    require 'capybara-webkit'
    
    feature 'Switch to mobile site banner', js: true do
      capybara.javascript_driver = :webkit
    
于 2013-10-23T05:09:23.820 回答
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" }

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

根标记:

<% 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。如果功能规范允许您轻松访问环境或请求对象,我会感到惊讶。您应该从浏览器的 POV 工作,因此设置用户代理似乎是可行的方法。

于 2013-10-24T02:11:25.100 回答