I'm using the Mobvious gem in a Rails project to determine the kind of device being used to access a page. The user story I'm having issues with is:
- A user on a mobile device is on the mobile version of the site
- The mobile user clicks a 'Visit Full Site' button which takes them to the desktop site
- A
desktop
value is put into the session to make sure their preference for viewing the desktop site on their mobile device is recorded (when mobile users first access the home page on a mobile device, they get automatically re-directed to the mobile site)
- On the desktop site home page, the mobile device user can see a 'Switch to Mobile Site' banner to give them to do so (the desktop user obviously never sees this banner)
The code to implement the conditional rendering with Mobvious is trivial:
app/views/welcome/index.html.haml
- for_device_type :mobile do
.switch-to-mobile-site-banner
# code for banner
The code itself works as expected: the issue is that I want to write a RSpec feature test for this, but I think I can't seem to simulate a mobile user agent properly in a RSpec feature test scenario where I don't have direct access to the request
object. My rationale is that a feature spec is more appropriate here than a request spec as I am testing for the presence of specific content on a page.
So far, taking cues from the helper specs of the Mobvious gem, I've stubbed out a request
object in my feature spec that sets device_type
to :mobile
as I want, but I can't seem to get the content in the .switch-to-mobile-site-banner
to display:
spec/features/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
The expectation is failing, and using save_and_open_page
to look at what's rendering on the page shows no banner, and I don't know why. I don't seem to be getting any errors when the code runs through Mobvious' for_device_type
method, so I'm thinking perhaps there's something I'm missing in the request
object mocking(?).
I'm not tied specifically to any implementation/test-type, so I'm open to any other ideas on how I can test the functionality I want to. I thought initially the rack_session_access
gem could help out, but unless I'm using it wrong, I couldn't use it to do what I want.
Clarification: I am using Poltergeist for Capybara's javascript driver.
Update with solution
I think what really threw me with this problem is that in the mobvious-rails gem, when you want to get the device_type
, it calls the request
object directly and I figured I needed to mock this out in order to get the helper working properly in my specs. As pointed out in the answers, this kind of low-level mocking in a high-level feature spec is a code (spec?) smell, and in hindsight I should have listened to the code practically telling me I was doing it wrong. Also, for some reason, adding js: true
in this case didn't even cross my mind, regardless of having used it in other tests of mine.
I ended up using parts of both Billy Chan and Kaleidoscope's answers to formulate a solution I like that is much simpler and cleaner:
spec/features/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
Since Kaleidoscope was the first to come up with a working set of specs that took me most of the way, I'm awarding him the bounty, but I'm going to accept Billy Chan's answer as correct because I think it is a more 'canonical' solution that I would direct others to reference in the future.