0
votes
  • rails (5.1.4)
  • rspec-rails (3.7.2)
  • capybara (2.16.1)

I'm trying to create a RSpec Rails 3.7 System spec as in https://relishapp.com/rspec/rspec-rails/v/3-7/docs/system-specs/system-spec .

Here my simple spec:

require 'rails_helper'

RSpec.describe "testing system", type: :system do

  it "tests the spec" do

    visit root_path

    click_link 'Home'

    save_and_open_page

  end  

The problem is that Capybara does render neither CSS content nor JS content after save_and_open_page call (in the browser) - just a plain HTML. The header inside this HTML-file contains some links

 <link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
  <script src="/assets/application-ff63e43aef379fef744a00f21a8aadf96dc2ae8e612f8e7974b231f946569691.js" data-turbolinks-track="reload"></script>

but they reference some empty files.

Is there some way to fix it?

I tried some recipes, but still no luck. I tried to precompile the assets, to move "capybara.html" into the "public" folder, but no effect.

4
Have you tried rake assets:clobber before rake assets:precompile to ensure you have a completely clean set of assets?Phil
Yes. It is a brand new demo project.prograils
My concern is that your link tags reference empty files. rake assets:clobber will clear the assets that are in place, before attempting the precompile. Then, the precompile should return the list of files generated. Plus the link tag should have href attributes pointing to the new js and css files. It might be useful to include the few lines from your layout.html.erb file that shows the page <head> and link tags.Phil

4 Answers

2
votes

Modifying stylesheet_link_tag is not a good solution, a much better solution is to specify Capybara.asset_host which will add a <base> tag to any saved pages. Generally this would be set to something like

Capybara.asset_host = "http://localhost:3000/"

which would then load the JS/CSS assets from your dev server which would have access to the test mode compiled assets in the public subdirectory. Note: that none of this means the page will actually be functional since JS requests will still fail, DB records won't exist anymore, etc. Also, since it saves element attributes (not properties) a checkbox you just checked will probably not be checked in the saved page. However it will give you a generally styled page you can inspect the structure of. If all you're looking for is a current image of the page you should be using the save_screenshot/save_and_open_screenshot functionality provided by most of Capybaras drivers instead.

0
votes

It has to do something with your assets. Clear cache and run rake assets:clobber and rake assets:precompile Still no luck, then check if Capybara is configured correctly.

0
votes

Check app/views/layouts/application.html.erb has the correct Rails tags for stylesheets and javascripts. Something like this:

<!DOCTYPE html>
<html>
<head>
  <title>My App</title>
  <%= stylesheet_link_tag    'application', media: 'all' %>
  <%= javascript_include_tag 'application' %>

On the command line, run:

rake assets:clobber
rake assets:precompile

Ensure that public/assets/ include:

.sprockets-manifest-<xyz>.json
application-<abc>.js
application-<def>.css

Open the .sprockets-manifest... file and you should see that there are application js and css files with filenames that match the actual public/assets/ files. This .sprockets-manifest file controls what actually gets included in the HTML head links and scripts when the Rails tags are replaced.

If this is still not working, ensure that the files are accessible by your user running the test (including the manifest). Occasionally lose the .sprockets-manifest file when copying files and in source control as it can appear to be hidden.

Finally, check your file log/test.log to see if there are any obvious errors being thrown during the tests.

-3
votes

I found a solution. Perhaps it's not the best one, but it works with me. If anybody find a better approach - let me know, please.

  1. Run rake assets:precompile. I didn't even set RAILS_ENV=test.

  2. Modify the stylesheet_link_tag method:

def stylesheet_link_tag2(*sources)
  options = sources.extract_options!.stringify_keys
  path_options = options.extract!('protocol').symbolize_keys

  sources.uniq.map { |source|
    tag_options = {
      "rel" => "stylesheet",
      "media" => "screen",
      "href" => path_to_stylesheet(source, path_options)[1..-1]
    }.merge!(options)
    tag(:link, tag_options)
  }.join("\n").html_safe
end

The idea is to turn the rendered link from this:

<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />

to this:

<link rel="stylesheet" media="all" href="assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />

eliminating the leading slash in the href attribute value (since we don't have a server running but just a saved HTML-page).

  1. Replace the code inside the header in \app\views\layouts\application.html.erb to:
<% if Rails.env.test? %>
  <%= stylesheet_link_tag2    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% else %>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% end %>
  1. Write a spec like this:
require 'rails_helper'

RSpec.describe "testing system", type: :system do

  it "tests..." do

    visit root_path

    click_link 'Home'

    save_and_open_page Rails.root.join( 'public', 'capybara.html' )

  end

end
  1. Add to .gitignore:

/public/capybara.html

Do the same thing with the JS-content.

UPDATE:

If you don't like modifying \app\views\layouts\application.html.erb you can do some monkey patching:

include ActionView::Helpers::AssetTagHelper

alias_method :old_stylesheet_link_tag, :stylesheet_link_tag

def stylesheet_link_tag2(*sources)
  options = sources.extract_options!.stringify_keys
  path_options = options.extract!('protocol').symbolize_keys

  sources.uniq.map { |source|
    tag_options = {
      "rel" => "stylesheet",
      "media" => "screen",
      "href" => path_to_stylesheet(source, path_options)[1..-1]
    }.merge!(options)
    tag(:link, tag_options)
  }.join("\n").html_safe
end  

def stylesheet_link_tag(*sources)

  if Rails.env.test?

    stylesheet_link_tag2(*sources)

  else

    old_stylesheet_link_tag(*sources)

  end

end

I usually put such code into app\helpers\application_helper.rb and add include ApplicationHelper into app\controllers\application_controller.rb

UPDATE 2 Setting Capybara.asset_host = "http://localhost:3000/" as @Thomas Walpole advised doesn't work. That's right - how can it work if http://localhost:3000/ is unavailable (AFTER the spec ran)? Of course - when I call save_and_open_page the HTML-file opens with a file://.... address - with no HTTP-server serving it. The attempts to set

Capybara.asset_host = "file://#{Rails.root}/public"

failed - looks like the base HTML-tag supports only http-adresses - not file://... ones. I checked it in Chrome and Firefox.

So my next code proposal is such:

include ActionView::Helpers::AssetTagHelper

alias_method :old_stylesheet_link_tag, :stylesheet_link_tag

def stylesheet_link_tag2(*sources)
  options = sources.extract_options!.stringify_keys
  path_options = options.extract!('protocol').symbolize_keys

  sources.uniq.map { |source|
    tag_options = {
      "rel" => "stylesheet",
      "media" => "screen",
      "href" => "file://#{Rails.root}/public" + path_to_stylesheet(source, path_options)
    }.merge!(options)
    tag(:link, tag_options)
  }.join("\n").html_safe
end  

def stylesheet_link_tag(*sources)

  if Rails.env.test?

    stylesheet_link_tag2(*sources)

  else

    old_stylesheet_link_tag(*sources)

  end

end

This eliminates the need to call

save_and_open_page Rails.root.join( 'public', 'capybara.html' )

instead you can simply call

save_and_open_page