简体   繁体   中英

How to get javascript to run in Rspec Capybara test

I'm building a simple Reddit Clone for practice, and would like to test to see if the ajax works and that a value on the screen is properly updated with the javascript response. Here is the test:

RSpec.describe "User voting", type: :system, js: true do # Rails 5 uses describe, Rails < 5 feature
    it "updates the downvote count" do
        user = create(:user)
        login_as(user)
        link = create(:link)
        visit root_path
        expect(page).to have_css('#upvotes-1', text: '0')
        click_on(id: 'upvoter-1')
        wait_for_ajax
        expect(page).to have_css('#upvotes-1', text: '1')
   end
end

wait_for_ajax: (in /spec/support/wait_for_ajax.rb)

module WaitForAjax
    def wait_for_ajax
        Timeout.timeout(Capybara.default_max_wait_time) do
            loop until finished_all_ajax_requests?
        end     
    end

    def finished_all_ajax_requests?
        page.evaluate_script('jQuery.active').zero?
    end
end

Relative code from index.html.erb:

<%= button_tag(class: "btn btn-secondary btn-sm", id: "upvoter-#{link.id}") do %>
 <span class="fa fa-chevron-up"></span>
 Upvote
 <%= content_tag(:span, link.upvotes(), id: "upvotes-#{link.id}") %>
<% end %>   

Controller code:

  def create
    @vote = current_user.votes.new(link_params)
    if @vote.vote_value == 1
      @new_value = @vote.link.upvotes
      @id_name = "#upvotes-" + @vote.link.id.to_s
    else
      @new_value = @vote.link.downvotes
      @id_name = "#downvotes-" + @vote.link.id.to_s
    end

    respond_to do |format|
      if @vote.save
        format.js   { }
      else
        format.html { render :new }
      end
    end
  end

And finally create.js.erb:

console.log("create.js.erb file");

$("<%= j @id_name %>").html("<%= j @new_value.to_s %>");

Gemfile:

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'
  gem 'rspec-rails'
  gem 'guard-rspec', require: false
  gem 'factory_bot_rails', '~> 4.0' 
  gem 'database_cleaner'
  gem 'rails-controller-testing'
  gem 'capybara', '~> 2.13'
  gem 'selenium-webdriver'
  gem 'chromedriver-helper'
  gem 'puma'
  gem 'poltergeist'
end

If I load the site myself and click on the button the tally updates correctly. However, the test fails on the second expect. If I reload the page, the tally will update so the database is updated and #create works as expected. The javascript doesn't get executed for some reason. And I've tried putting a sleep after the click_on as well. It still fails. There seems to be something simple I'm missing here.

Switching to Selenium helped me see the problem more clearly. Here is a pretty good tutorial that tells you how to get setup with Rails 5 / latest (late 2018) versions of things:

A Quick Guide to Rails System Tests in RSpec

In the end, I used .new to create the model, but hadn't saved it, so the new vote count wasn't showing. Moving the logic that pulled the count after the save solved the problem.

In votes_controller.rb:

  def create
    @vote = current_user.votes.new(link_params)
    respond_to do |format|
      if @vote.save
        format.js   {
          if @vote.vote_value == 1
            @new_value = @vote.link.upvotes
            @id_name = "#upvotes-" + @vote.link.id.to_s
          else
            @new_value = @vote.link.downvotes
            @id_name = "#downvotes-" + @vote.link.id.to_s
          end             
            }
     else
       format.html { render :new }
     end
   end
  end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM