In my rspec_helper.rb I defined;
Rails.application.routes.default_url_options[:host] = 'lvh.me'
It works fine for non-feature specs but doesn't work for feature specs. Host for urls are equal to "www.example.com" in feature specs.
I've debugged and in _feature_example_group.rb_ file, _default_url_options_ is always an empty hash.
found the following solution for this issue;
https://github.com/beydogan/rspec-rails/commit/b590c82573b27bd8a1be967811b4835119260f09
Is this valid?
What problem is this solving for you? I'd like to understand where this is causing an issue.
@cupakromer The problem is; when I set default_url_options in my spec/rails_helper.rb or environments/test.rb. It's being ignored in feature specs.
I set like following;
Rails.application.routes.default_url_options[:host] = 'lvh.me'
But in a feature spec;
posts_url is equal to http://www.example.com/posts instead of http://lvh.me/posts
Ok, I dug into this a bit. It's a little more complicated that it seems. Here's what is going on.
The Rails test cases, the RSpec example groups are a thin shim on top of these, setup an attribute default_url_options. If this is not set or defined, then the call chain falls back on whatever the current routes scope has configured. By default it has nothing configured for :host and the value is nil.
If we removed or comment out the line:
default_url_options[:host] ||= ::RSpec::Rails::FeatureExampleGroup::DEFAULT_HOST
You would get the following error:
Missing host to link to! Please provide the :host parameter, set
default_url_options[:host], or set :only_path to true
The reason your proposed solution in #1276 appears to work is simply because the example's default_url_options is nil and so it falls back to the routes which you have customized in the spec/rails_helper.rb. For other spec types, which don't have a :host option set by default, the route generation falls back to the session set by Rails' test case. This depending on the spec type and is normally set to a default of www.example.com or pulled from a request, but is all handled by Rails' test cases. This is not set for feature specs, because the session is handled by Capybara which does not set something for it.
So unfortunately, your solution is basically a no-op and is the same as deleting that if block. For the majority of cases, people don't customize the host option and they would get the above exception.
We could change it to:
if respond_to?(:default_url_options)
default_url_options[:host] ||= (
app.routes.default_url_options[:host] ||
::RSpec::Rails::FeatureExampleGroup::DEFAULT_HOST
)
end
However, this will cause other problems:
require 'rails_helper'
Rails.application.routes.default_url_options[:host] = 'lvh.me'
RSpec.feature "Relative path hosts set by Capybara", type: :feature do
it "causes a mismatch between the URLs" do
visit widgets_path
expect(current_url).to eq widgets_url
end
end
Results in a failure:
Failures:
1) Relative path hosts set by Capybara causes a mismatch between the URLs
Failure/Error: expect(current_url).to eq widgets_url
expected: "http://lvh.me/widgets"
got: "http://www.example.com/widgets"
(compared using ==)
# ./spec/features/capybara_mismatch_spec.rb:7:in `block (2 levels) in <top (required)>'
This is because Capybara uses Capybara.default_host to generate the "full" URL under the hood. The default host just happens to be "www.example.com". However, it won't actually use that web server. It just uses the value to generate the full URL while still using it's local server. You have to configure Capybara to use an external app host.
There's another wrinkle. Capybara expects the "http://" part in the URL, if it's not present the URL is created as: "http:///widgets". I'm not sure this is a bug, you'd have to ask them. So while Rails is happy to have "lvh.me", Capybara would need "http://lvh.me".
We are tightly coupled to Capybara right now. As you can see from the feature example group file it's essentially just all code necessary to handle Capybara's design decisions. It also causes a lot of confusion for newer users who do not understand this tight dependency.
I really do not want to add yet another special case for Capybara. Let me think on this a bit. I have a potential solution in mind but will need to think on it for a day.
I hope this helps understand what's happening.
Any fix?
Not yet, see @cupakromer's comments above, you can try setting the Capybara default host as a work around?
@JonRowe I'm not using Capybara. Same thing in controller tests.
This issue only affects feature tests, which use Capybara.
Again. This issue in controllers tests too.
Only way to fix it is:
[ApplicationController, ActionController::Base].each do |klass|
klass.class_eval do
def default_url_options(options = {})
{ :host => "example.com" }.merge(options)
end
end
end
Can you elaborate what symptoms you are seeing; It's possible you are suffering from the symptoms of the rails behaviour (which we cannot fix) or a different bug altogether.
I'm testing subdomains and instead of _path helpers using _url in my controller. It's only what I set.
Sorry you're going to have to elaborate further, when reporting issues it's best to actually provide an example showing what you're trying to do, and the unexpected outcome of that attempt. Even better if it's actually executable (but please... don't point me to a rails app repo, I don't have time to comb through an entire app).
I'm still having lots of problems when testing myroute_url using different subdomains.
Any thoughts?
Facing the same issue in features spec with Rspec and Capybara.
Tried adding the config in application.rb
Rails.application.default_url_options[:host] = Figaro.env.domain_name
Further tried overriding Capybara config
Capybara.configure do |config|
config.default_host = Figaro.env.domain_name
end
But 'about_us_url' returns "http://www.example.com/about_us" instead of "http://localhost:3000/about_us". This causes email specs to fail where we check if the url has been added to an email.
For emails you also have to configure ActionMailer::Base.default_url_options
That is configured. This issue is not related to email. While running any spec if I debug and check what urls are generated with 'xyz_url' method, it always prepends it with with 'http://www.example.com/'. It should ideally prepend whatever value is set to Rails.application.default_url_options[:host] in test environment.
RSpec doesn't have any value for this url, it comes from Capybara or from your config.
While debugging the spec if I check value of
self
it gives
RSpec::ExampleGroups::SignUp:0x007fe910f18168
And when we check value of
self.url_options
it gives
result = Hash (1 element)
host => www.example.com
So as you said, I think, the value is being set by either capybara or may be Rspec. Any thoughts?
That'll be the value from the Rails helpers we mix in, you need to check
your Rails configuration.
Hey @JonRowe
I checked and found that issue is exactly where @beydogan is suggesting in the first comment.
In the line 19 of feature_example_group.rb
default_url_options[:host]
is always nil, no matter where I set the default_url_options.
And thus in the same line default host is set to www.example.com
As of now in my application I have set the default host at all possible places.
config/environments/test.rb
Rails.application.default_url_options = {:host => Figaro.env.domain_name }
Rails.application.routes.default_url_options = {:host => Figaro.env.domain_name }
spec/support/capybara.rb
Capybara.app_host = 'http://localhost'
Capybara.always_include_port = true
Capybara.configure do |config|
config.default_host = Figaro.env.domain_name
end
Any further comments?
Sample app here: https://github.com/samphippen/demo_app_for_1275.git
Worth noting: this explicitly is not supposed to work in controller specs according to someone from rails core.
So request specs work, and feature specs don't work here.
For future reference: I tried all sorts of variations (e.g config.action_mailer.default_url_options = { host: 'www.example.com' }, Capybara's host etc), nothing worked. I then added Rails.application.routes.default_url_options[:host] = 'www.example.com' after the end (end of file, outside the config block) in config/environments/tests.rb and it worked.
I tried everything described in this issue too and my tests still broken.
I'm using apartment with custom domains and it's necessary setup default_url_options with custom domain.
anything found and tried, always end up with an error. prefixing for now with kind of the following visit("http://custom_domain/itll_work_someday"); but that quite feels weird. Hope there'd be a clear explanation
FWIW, I just ran into this issue, and found that if I call the url helper _before_ making any requests in my request spec, I get the expected hostname:
+expected_url = foo_bars_url(foo)
get url_for(foo)
expect(json).to include(
"links" => a_hash_including(
- "bars" => foo_bars_url(foo)
+ "bars" => expected_url
)
)
UPDATE: I'm no longer seeing this behaviour. It could have been an error on my part.
I'm seeing the exact same situation as @rvsingh. Any attempt to configure default_url_options is effectively ignored.
I have been able to work around the issue by acquiescing, and re-configuring default_url_options to use the host "www.example.com". Thanks to @kurko for the suggestion.
This is incredibly frustrating because rspec-rails is effectively forcing you to use "www.example.com". If you have any other desire, you're left with options that feel wrong.
I'm sorry you're frustrated, but we just set a default value if one isn't present, it's up to Rails how it uses that value, I suspect its being cached in a way making it difficult to override.
For controller tests inside the Rails.application.configure block seemed to work for me:
config.action_controller.default_url_options = {
host: ENV['HOST']
}
Same issue. Alternate resolution.
I noticed that a random feature test was failing inconsistently in both dev machine and CI environments. After reproducing with rspec --seed and getting consistent failures tried many of the approaches here. Unfortunately, none of them quite worked for me. The route helpers would still resolve incorrectly. i.e. my_page_url = www.example.com/my_page.
The interesting thing was that only the first feature test would fail. For all the subsequent feature tests in any feature testing file, the URL helpers would still resolve incorrectly, but the visit would be successful. In other words, visiting www.example.com/my_page would render my page correctly and run the necessary assertions as intended.
Simplest hack possible for me was just visiting one page before running the real tests:
# HACK: https://github.com/rspec/rspec-rails/issues/1275
config.before(:all, type: :feature) do
visit(my_page_path)
end
Added this to the RSpec configure block in my rails helper and haven't had any problems since.
ruby 2.3.4p301
rails 5.1.1
rspec 3.6.0
capybara 2.14.0
These options are ignored on system tests.
Had to do this to solve the problem:
def visit_to(path)
visit("http://test.lvh.me"+":#{Capybara.server_port}"+path)
end
I think this is just a Rails issue. There are many places to set default_url_options, but they either work on console but not web, or the other way around:
In Rails 5.1.4, I have tested the following scenarios on web and console (but not in Rspec):
# in development.rb
config.action_controller.default_url_options({:protocol => 'https'})
config.action_controller.default_url_options(:protocol => 'https')
# Does not work
# in development.rb, outside config block
Rails.application.routes.default_url_options[:protocol] = 'https'
# Does not work, but works under console
# in routes.rb
Rails.application.routes.draw do
default_url_options protocol: :https
# Does not work, but works under console
# in ApplicationController
def default_url_options
{ protocol: :https }
end
# Works in browser, but does not work under console
# in development.rb
config.action_controller.default_url_options= {:protocol => 'https'}
# Works in browser, but does not work under console
any one fix this problem?
my case is : Rails 5.2.1, ruby 2.5.1
in my environment it works well
Regardless of the last comments. I think we can close this issue. Feel free to comment if we think we should still look at it.
Any fixes for this problem ?
Most helpful comment
For future reference: I tried all sorts of variations (e.g
config.action_mailer.default_url_options = { host: 'www.example.com' }, Capybara's host etc), nothing worked. I then addedRails.application.routes.default_url_options[:host] = 'www.example.com'after theend(end of file, outside the config block) inconfig/environments/tests.rband it worked.